驾驶员情绪检测:从疲劳监控到路怒症预警

发布时间: 2026-04-15
关键词: 情绪检测、路怒症、DMS、面部表情、EEG、多模态


研究背景

核心问题:负面情绪(愤怒、压力、悲伤)会显著影响驾驶安全

情绪 影响 事故风险
愤怒 攻击性驾驶、路怒症 +3x
压力 注意力分散、反应迟钝 +2x
悲伤 警觉性下降 +1.5x
疲劳 反应时间延长 +4x

情绪检测方法

1. 面部表情分析(FACS)

Facial Action Coding System(面部动作编码系统) 是情绪检测的标准方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
┌─────────────────────────────────────────────────────┐
│ FACS 情绪映射 │
├─────────────────────────────────────────────────────┤
│ │
│ 愤怒 (Anger) │
│ ────────── │
│ • 眉毛下压 + 聚拢 (AU 4) │
│ • 眼睑紧绷 (AU 7) │
│ • 嘴唇紧闭或张开 (AU 23/24/27) │
│ │
│ 恐惧 (Fear) │
│ ────────── │
│ • 眉毛上扬 (AU 1+2) │
│ • 眼睛睁大 (AU 5) │
│ • 嘴唇张开 (AU 20) │
│ │
│ 悲伤 (Sadness) │
│ ────────── │
│ • 眉毛内端上扬 (AU 1) │
│ • 眉毛外端下压 (AU 15) │
│ • 嘴角下拉 (AU 15) │
│ │
│ 快乐 (Happiness) │
│ ──────────────── │
│ • 嘴角上扬 (AU 12) │
│ • 眼睛周围皱纹 (AU 6) │
│ │
└─────────────────────────────────────────────────────┘

2. 多模态融合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import numpy as np
from typing import Dict, Tuple
from dataclasses import dataclass

@dataclass
class EmotionResult:
"""情绪检测结果"""
emotion: str # 'anger', 'fear', 'sadness', 'joy', 'neutral'
confidence: float # 0-1
arousal: float # 唤醒度 0-1
valence: float # 效价 -1到1
action_units: dict # AU 强度

class MultimodalEmotionDetector:
"""多模态情绪检测器"""

def __init__(self):
# 面部表情分析器
self.facial_analyzer = FacialExpressionAnalyzer()

# 生理信号分析器(可选)
self.physio_analyzer = PhysiologicalAnalyzer()

# 驾驶行为分析器(可选)
self.driving_analyzer = DrivingBehaviorAnalyzer()

# 融合权重
self.weights = {
'facial': 0.6,
'physio': 0.2,
'driving': 0.2
}

def detect(self,
face_image: np.ndarray,
physio_data: dict = None,
driving_data: dict = None) -> EmotionResult:
"""检测情绪

Args:
face_image: 面部图像
physio_data: {
'heart_rate': float,
'skin_conductance': float,
'eeg': np.ndarray (可选)
}
driving_data: {
'steering_variance': float,
'brake_count': int,
'speed_variance': float
}

Returns:
EmotionResult
"""
# 1. 面部表情分析
facial_result = self.facial_analyzer.analyze(face_image)

# 2. 生理信号分析(如果有)
physio_result = None
if physio_data:
physio_result = self.physio_analyzer.analyze(physio_data)

# 3. 驾驶行为分析(如果有)
driving_result = None
if driving_data:
driving_result = self.driving_analyzer.analyze(driving_data)

# 4. 融合决策
fused_emotion = self._fuse(facial_result, physio_result, driving_result)

return fused_emotion

def _fuse(self, facial, physio, driving) -> EmotionResult:
"""融合多模态结果"""
# 简化:以面部表情为主
if facial:
return EmotionResult(
emotion=facial['emotion'],
confidence=facial['confidence'],
arousal=facial.get('arousal', 0.5),
valence=facial.get('valence', 0),
action_units=facial.get('action_units', {})
)

return EmotionResult(
emotion='neutral',
confidence=0.5,
arousal=0.5,
valence=0,
action_units={}
)


class FacialExpressionAnalyzer:
"""面部表情分析器"""

def __init__(self):
# 加载模型
self.au_detector = AUDetector() # Action Unit 检测器
self.emotion_classifier = EmotionClassifier()

def analyze(self, face_image: np.ndarray) -> dict:
"""分析面部表情

Returns:
{
'emotion': str,
'confidence': float,
'arousal': float,
'valence': float,
'action_units': dict
}
"""
# 1. 检测 Action Units
aus = self.au_detector.detect(face_image)

# 2. 分类情绪
emotion, confidence = self.emotion_classifier.classify(aus)

# 3. 计算唤醒度和效价
arousal = self._compute_arousal(aus)
valence = self._compute_valence(emotion)

return {
'emotion': emotion,
'confidence': confidence,
'arousal': arousal,
'valence': valence,
'action_units': aus
}

def _compute_arousal(self, aus: dict) -> float:
"""计算唤醒度(情绪强度)"""
# 基于活跃的 AU 数量和强度
active_aus = sum(1 for au, intensity in aus.items() if intensity > 0.3)
return min(active_aus / 10, 1.0)

def _compute_valence(self, emotion: str) -> float:
"""计算效价(正面/负面)"""
valence_map = {
'joy': 0.8,
'neutral': 0.0,
'sadness': -0.6,
'fear': -0.7,
'anger': -0.9,
'surprise': 0.3,
'disgust': -0.8
}
return valence_map.get(emotion, 0)


class AUDetector:
"""Action Unit 检测器"""

def detect(self, face_image: np.ndarray) -> dict:
"""检测 Action Units

返回 AU 强度(0-1)
"""
# 简化:使用预训练模型
# 实际需要检测 68 个面部关键点
# 然后根据几何关系计算 AU

return {
'AU1': 0.0, # Inner Brow Raiser
'AU2': 0.0, # Outer Brow Raiser
'AU4': 0.0, # Brow Lowerer
'AU5': 0.0, # Upper Lid Raiser
'AU6': 0.0, # Cheek Raiser
'AU7': 0.0, # Lid Tightener
'AU9': 0.0, # Nose Wrinkler
'AU12': 0.0, # Lip Corner Puller
'AU15': 0.0, # Lip Corner Depressor
'AU17': 0.0, # Chin Raiser
'AU20': 0.0, # Lip Stretcher
'AU23': 0.0, # Lip Tightener
'AU24': 0.0, # Lip Pressor
'AU25': 0.0, # Lips Part
'AU26': 0.0, # Jaw Drop
'AU27': 0.0, # Mouth Stretch
}


class EmotionClassifier:
"""情绪分类器"""

def __init__(self):
# AU 到情绪的映射规则
self.emotion_rules = {
'anger': ['AU4', 'AU5', 'AU7', 'AU23'],
'fear': ['AU1', 'AU2', 'AU5', 'AU20'],
'sadness': ['AU1', 'AU15', 'AU17'],
'joy': ['AU6', 'AU12'],
'surprise': ['AU1', 'AU2', 'AU5', 'AU26'],
'disgust': ['AU9', 'AU15', 'AU17'],
}

def classify(self, aus: dict) -> Tuple[str, float]:
"""分类情绪

Returns:
(emotion, confidence)
"""
# 计算每种情绪的得分
scores = {}

for emotion, required_aus in self.emotion_rules.items():
score = sum(aus.get(au, 0) for au in required_aus) / len(required_aus)
scores[emotion] = score

# 找到最高得分的情绪
best_emotion = max(scores, key=scores.get)
confidence = scores[best_emotion]

# 如果所有得分都低,认为是中性
if confidence < 0.3:
return 'neutral', 1 - confidence

return best_emotion, confidence

路怒症检测

Road Rage Reasoning with VLMs

2025 年的研究提出了使用视觉语言模型(VLMs)进行路怒症推理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
┌─────────────────────────────────────────────────────┐
│ 路怒症检测与干预系统 │
├─────────────────────────────────────────────────────┤
│ │
│ 输入 │
│ ──── │
│ • 驾驶员面部表情 │
│ • 驾驶行为(方向盘、刹车) │
│ • 外部环境(前车行为、路况) │
│ │
│ 处理 │
│ ──── │
│ ┌─────────────────┐ │
│ │ VLM 推理 │ │
│ │ • 理解触发事件 │ │
│ │ • 评估愤怒程度 │ │
│ │ • 生成应对建议 │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 干预决策 │ │
│ │ • 警告 │ │
│ │ • 对话安抚 │ │
│ │ • 音乐调节 │ │
│ │ • ADAS 激活 │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘

微表情检测

核心挑战

挑战 说明
持续时间短 微表情仅持续 40-200 ms
幅度小 面部动作幅度很小
无意识 驾驶员不会主动表现

解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class MicroExpressionDetector:
"""微表情检测器"""

def __init__(self, frame_rate: int = 30):
self.frame_rate = frame_rate

# 微表情持续时间(帧数)
self.min_frames = int(0.04 * frame_rate) # 40 ms
self.max_frames = int(0.2 * frame_rate) # 200 ms

# 历史缓冲
self.au_history = []
self.history_window = int(0.5 * frame_rate) # 500 ms

def detect_micro_expression(self, current_aus: dict) -> dict:
"""检测微表情

Args:
current_aus: 当前帧的 AU 强度

Returns:
{
'detected': bool,
'type': str,
'onset_frame': int,
'offset_frame': int,
'intensity': float
}
"""
# 记录历史
self.au_history.append(current_aus)
if len(self.au_history) > self.history_window:
self.au_history.pop(0)

# 检测 AU 变化
if len(self.au_history) < self.max_frames:
return {'detected': False}

# 分析变化模式
for au_name in current_aus.keys():
au_sequence = [frame.get(au_name, 0) for frame in self.au_history]

# 检测快速上升和下降
onset, offset, intensity = self._detect_onset_offset(au_sequence)

if onset is not None and offset is not None:
duration = offset - onset

if self.min_frames <= duration <= self.max_frames:
return {
'detected': True,
'type': self._au_to_emotion(au_name),
'onset_frame': onset,
'offset_frame': offset,
'intensity': intensity
}

return {'detected': False}

def _detect_onset_offset(self, sequence: list) -> Tuple[int, int, float]:
"""检测上升和下降点"""
# 简化:寻找峰值
max_val = max(sequence)
max_idx = sequence.index(max_val)

if max_val < 0.5:
return None, None, 0

# 找到上升和下降点
threshold = max_val * 0.3

onset = None
for i in range(max_idx - 1, -1, -1):
if sequence[i] < threshold:
onset = i
break

offset = None
for i in range(max_idx + 1, len(sequence)):
if sequence[i] < threshold:
offset = i
break

return onset, offset, max_val

def _au_to_emotion(self, au_name: str) -> str:
"""AU 到情绪映射"""
mapping = {
'AU4': 'anger',
'AU12': 'joy',
'AU15': 'sadness',
'AU1': 'fear',
}
return mapping.get(au_name, 'unknown')

干预策略

情绪调节方法

方法 适用情绪 说明
音乐调节 愤怒、压力 播放舒缓音乐
温度调节 愤怒 降低车内温度
照明调节 压力 调整车内灯光
语音对话 愤怒、悲伤 AI 助手安抚
ADAS 激活 愤怒、压力 启用辅助驾驶

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class EmotionInterventionSystem:
"""情绪干预系统"""

def __init__(self):
self.emotion_detector = MultimodalEmotionDetector()

# 干预阈值
self.intervention_thresholds = {
'anger': 0.7,
'fear': 0.8,
'sadness': 0.6,
}

def process(self,
face_image: np.ndarray,
vehicle_state: dict) -> dict:
"""处理情绪并干预

Returns:
{
'emotion': str,
'intensity': float,
'intervention': str,
'message': str
}
"""
# 检测情绪
result = self.emotion_detector.detect(face_image)

# 检查是否需要干预
threshold = self.intervention_thresholds.get(result.emotion, 0.9)

if result.confidence > threshold:
# 选择干预策略
intervention = self._select_intervention(result.emotion, vehicle_state)

return {
'emotion': result.emotion,
'intensity': result.confidence,
'intervention': intervention['action'],
'message': intervention['message']
}

return {
'emotion': result.emotion,
'intensity': result.confidence,
'intervention': None,
'message': None
}

def _select_intervention(self, emotion: str, vehicle_state: dict) -> dict:
"""选择干预策略"""
if emotion == 'anger':
return {
'action': 'music_and_temperature',
'message': '检测到您可能感到愤怒,正在调整车内环境。建议深呼吸,保持冷静。'
}
elif emotion == 'fear':
return {
'action': 'adas_activation',
'message': '检测到您可能感到紧张,已启用辅助驾驶。'
}
elif emotion == 'sadness':
return {
'action': 'voice_comfort',
'message': '检测到您可能情绪低落。有什么可以帮您的吗?'
}
else:
return {
'action': 'none',
'message': None
}

参考资源