EyeCue:视线增强的视频认知分心检测

arXiv 2605.07859 | 2026年5月

一、研究背景

1.1 认知分心vs视觉分心

驾驶员分心分为两类:

类型 特征 检测难度
视觉分心 眼睛离开道路 相对容易(视线偏离)
手动分心 手离开方向盘 中等(手部检测)
认知分心 思维不在驾驶 困难(无显性动作)

1.2 EyeCue核心思想

认知分心的检测难点:驾驶员眼睛可能在看前方,但思维在别处。

EyeCue解决方案:
利用第一人称视角视频(Egocentric Video)+ 注视点分析来检测认知分心。

flowchart TB
    A[驾驶舱摄像头] --> B[第一人称视频]
    
    B --> C1[视线追踪]
    B --> C2[场景理解]
    B --> C3[动作识别]
    
    C1 --> D[注视点分布]
    C2 --> E[注视语义]
    C3 --> F[注视序列模式]
    
    D --> G[认知分心分类器]
    E --> G
    F --> G
    
    G --> H{认知状态}
    H -->|专注| I1[正常]
    H -->|分心| I2[警告]

二、方法架构

2.1 实现代码

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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
"""
EyeCue: 视线增强的认知分心检测
"""

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np


class EyeCue(nn.Module):
"""
EyeCue: Gaze-Empowered Egocentric Video Understanding
for Cognitive Distraction Detection
"""

def __init__(self, config: dict):
super().__init__()

self.config = config

# 视频编码器
self.video_encoder = VideoEncoder(
d_model=config['video_dim'],
num_frames=config['num_frames']
)

# 注视点编码器
self.gaze_encoder = GazeEncoder(
d_model=config['gaze_dim'],
num_points=config['num_gaze_points']
)

# 视线-视频交叉注意力
self.cross_attention = CrossModalAttention(
video_dim=config['video_dim'],
gaze_dim=config['gaze_dim'],
fusion_dim=config['fusion_dim']
)

# 认知状态分类器
self.classifier = nn.Sequential(
nn.Linear(config['fusion_dim'], config['fusion_dim'] // 2),
nn.ReLU(),
nn.Dropout(config['dropout']),
nn.Linear(config['fusion_dim'] // 2, config['num_classes'])
)

def forward(self, video, gaze_sequence, gaze_heatmap=None):
"""
Args:
video: [B, T, C, H, W] 第一人称视频
gaze_sequence: [B, T, 2] 注视点序列
gaze_heatmap: [B, T, H, W] 注视点热力图(可选)

Returns:
logits: [B, num_classes] 认知状态
"""
# 1. 视频特征
video_feat = self.video_encoder(video) # [B, T, D_v]

# 2. 注视点特征
gaze_feat = self.gaze_encoder(gaze_sequence, gaze_heatmap) # [B, T, D_g]

# 3. 交叉注意力融合
fused_feat = self.cross_attention(video_feat, gaze_feat) # [B, D_f]

# 4. 分类
logits = self.classifier(fused_feat)

return logits


class VideoEncoder(nn.Module):
"""视频编码器"""

def __init__(self, d_model=256, num_frames=16):
super().__init__()

# 3D CNN + Transformer
self.conv3d = nn.Sequential(
nn.Conv3d(3, 64, kernel_size=(3, 5, 5), stride=(1, 2, 2), padding=(1, 2, 2)),
nn.BatchNorm3d(64),
nn.ReLU(),
nn.MaxPool3d((1, 2, 2)),
nn.Conv3d(64, 128, kernel_size=(3, 3, 3), stride=(1, 2, 2), padding=(1, 1, 1)),
nn.BatchNorm3d(128),
nn.ReLU(),
nn.AdaptiveAvgPool3d((num_frames, 1, 1))
)

self.proj = nn.Linear(128, d_model)

# 时序Transformer
encoder_layer = nn.TransformerEncoderLayer(d_model=d_model, nhead=8, batch_first=True)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=2)

def forward(self, x):
"""
Args:
x: [B, T, C, H, W]
Returns:
feat: [B, T, d_model]
"""
B, T, C, H, W = x.shape

# 转换为3D卷积格式
x = x.permute(0, 2, 1, 3, 4) # [B, C, T, H, W]

# 3D卷积
x = self.conv3d(x) # [B, 128, T', 1, 1]
x = x.squeeze(-1).squeeze(-1).permute(0, 2, 1) # [B, T', 128]

# 投影
x = self.proj(x) # [B, T', d_model]

# Transformer
x = self.transformer(x)

return x


class GazeEncoder(nn.Module):
"""注视点编码器"""

def __init__(self, d_model=128, num_points=16):
super().__init__()

# 注视点嵌入
self.gaze_embed = nn.Linear(2, d_model)

# 位置编码
self.pos_encoding = nn.Parameter(torch.randn(1, num_points, d_model))

# Transformer
encoder_layer = nn.TransformerEncoderLayer(d_model=d_model, nhead=4, batch_first=True)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=2)

# 热力图编码(可选)
self.heatmap_encoder = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=7, stride=2, padding=3),
nn.ReLU(),
nn.AdaptiveAvgPool2d(1),
nn.Flatten(),
nn.Linear(32, d_model // 2)
)

def forward(self, gaze_sequence, gaze_heatmap=None):
"""
Args:
gaze_sequence: [B, T, 2]
gaze_heatmap: [B, T, H, W](可选)

Returns:
feat: [B, T, d_model]
"""
# 注视点嵌入
x = self.gaze_embed(gaze_sequence) # [B, T, d_model]

# 位置编码
x = x + self.pos_encoding[:, :x.size(1)]

# Transformer
x = self.transformer(x)

# 热力图增强(可选)
if gaze_heatmap is not None:
B, T, H, W = gaze_heatmap.shape
heatmap_feat = self.heatmap_encoder(gaze_heatmap.view(B*T, 1, H, W))
heatmap_feat = heatmap_feat.view(B, T, -1)

# 简化融合
x = x + F.pad(heatmap_feat, (0, x.size(-1) - heatmap_feat.size(-1)))

return x


class CrossModalAttention(nn.Module):
"""交叉模态注意力"""

def __init__(self, video_dim=256, gaze_dim=128, fusion_dim=256):
super().__init__()

# 视频投影
self.video_proj = nn.Linear(video_dim, fusion_dim)

# 注视点投影
self.gaze_proj = nn.Linear(gaze_dim, fusion_dim)

# 交叉注意力
self.cross_attn = nn.MultiheadAttention(fusion_dim, num_heads=8, batch_first=True)

# 输出
self.output = nn.Sequential(
nn.LayerNorm(fusion_dim),
nn.Linear(fusion_dim, fusion_dim),
nn.ReLU()
)

def forward(self, video_feat, gaze_feat):
"""
Args:
video_feat: [B, T_v, D_v]
gaze_feat: [B, T_g, D_g]

Returns:
fused: [B, D_f]
"""
# 投影到统一维度
video = self.video_proj(video_feat) # [B, T_v, D_f]
gaze = self.gaze_proj(gaze_feat) # [B, T_g, D_f]

# 交叉注意力:视频attend to注视点
attn_out, _ = self.cross_attn(
query=video,
key=gaze,
value=gaze
)

# 残差连接
fused = self.output(video + attn_out)

# 全局池化
fused = fused.mean(dim=1)

return fused


# 认知分心特征分析
def analyze_cognitive_distraction_features():
"""分析认知分心的注视特征"""

features = {
'专注驾驶': {
'gaze_variance': 0.3, # 高方差(持续扫视)
'fixation_duration': 0.5, # 短注视
'saccade_frequency': 0.8, # 高频扫视
'gaze_road_ratio': 0.9, # 90%看道路
},
'认知分心': {
'gaze_variance': 0.1, # 低方差(凝视)
'fixation_duration': 2.0, # 长时间注视
'saccade_frequency': 0.2, # 低频扫视
'gaze_road_ratio': 0.95, # 看道路但不动
},
'视觉分心': {
'gaze_variance': 0.4,
'fixation_duration': 1.5,
'saccade_frequency': 0.6,
'gaze_road_ratio': 0.3, # 看非道路区域
}
}

print("=" * 70)
print("Cognitive Distraction Gaze Features")
print("=" * 70)
print(f"{'状态':<15} | {'视线方差':>8} | {'注视时长':>8} | {'扫视频率':>8} | {'道路比例':>8}")
print("-" * 70)

for state, metrics in features.items():
print(f"{state:<15} | {metrics['gaze_variance']:>8.2f} | {metrics['fixation_duration']:>8.1f}s | "
f"{metrics['saccade_frequency']:>8.2f} | {metrics['gaze_road_ratio']:>7.0%}")

return features


if __name__ == "__main__":
config = {
'video_dim': 256,
'gaze_dim': 128,
'fusion_dim': 256,
'num_frames': 16,
'num_gaze_points': 16,
'num_classes': 3, # 专注/认知分心/视觉分心
'dropout': 0.1
}

model = EyeCue(config)

B = 4
video = torch.randn(B, 16, 3, 224, 224)
gaze = torch.randn(B, 16, 2)

output = model(video, gaze)

print(f"Video shape: {video.shape}")
print(f"Gaze shape: {gaze.shape}")
print(f"Output shape: {output.shape}")
print(f"Model parameters: {sum(p.numel() for p in model.parameters()):,}")

print("\n")
analyze_cognitive_distraction_features()

三、实验结果

3.1 数据集

数据集 场景 分心类型 样本
DMD-ECG 模拟器 认知任务 50人
LBW 真实驾驶 手机通话 30人
自建 模拟器 N-back任务 20人

3.2 性能对比

方法 认知分心F1 视觉分心F1 整体准确率
视频CNN 0.62 0.85 73%
注视点SVM 0.58 0.78 68%
EyeCue 0.81 0.89 85%

3.3 认知分心特征详细分析

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
"""
认知分心的深度特征分析
"""

def analyze_cognitive_distraction_deep():
"""深度分析认知分心特征"""

# 认知分心的关键特征
features = {
'视线熵值': {
'专注': 2.5, # 高熵(分散扫视)
'认知分心': 0.8, # 低熵(凝视不动)
'视觉分心': 1.8
},
'注视点轨迹曲率': {
'专注': 0.15,
'认知分心': 0.02,
'视觉分心': 0.25
},
'瞳孔直径变化': {
'专注': 0.5, # mm变化
'认知分心': 0.1,
'视觉分心': 0.8
},
'扫视峰值速度': {
'专注': 450, # °/s
'认知分心': 120,
'视觉分心': 380
}
}

print("=" * 70)
print("Deep Feature Analysis for Cognitive Distraction")
print("=" * 70)
print(f"{'特征':<20} | {'专注':>10} | {'认知分心':>12} | {'视觉分心':>12}")
print("-" * 70)

for feature, values in features.items():
print(f"{feature:<20} | {values['专注']:>10.2f} | {values['认知分心']:>12.2f} | {values['视觉分心']:>12.2f}")

return features


if __name__ == "__main__":
analyze_cognitive_distraction_deep()

3.4 混淆矩阵分析

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
"""
混淆矩阵与误分类分析
"""

def analyze_confusion():
"""分析混淆矩阵"""

# 简化混淆矩阵(3类)
confusion = {
'专注': {'专注': 85, '认知分心': 10, '视觉分心': 5},
'认知分心': {'专注': 8, '认知分心': 81, '视觉分心': 11},
'视觉分心': {'专注': 5, '认知分心': 6, '视觉分心': 89}
}

print("\n" + "=" * 60)
print("Confusion Matrix (EyeCue)")
print("=" * 60)
print(f"{'真实\\预测':<15} | {'专注':>8} | {'认知分心':>10} | {'视觉分心':>10}")
print("-" * 60)

for true_label, pred_counts in confusion.items():
print(f"{true_label:<15} | {pred_counts['专注']:>8}% | {pred_counts['认知分心']:>10}% | {pred_counts['视觉分心']:>10}%")

return confusion


if __name__ == "__main__":
analyze_cognitive_distraction_features()
analyze_cognitive_distraction_deep()
analyze_confusion()

四、部署与实时性

4.1 实时推理优化

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
"""
EyeCue实时推理优化
"""

class EyeCueRealTime:
"""EyeCue实时推理"""

def __init__(self, model_path):
# 加载量化模型
self.model = self._load_quantized_model(model_path)
self.model.eval()

# 缓存
self.gaze_buffer = []
self.buffer_size = 16

def _load_quantized_model(self, path):
"""加载量化模型"""
config = {
'video_dim': 256,
'gaze_dim': 128,
'fusion_dim': 256,
'num_frames': 16,
'num_classes': 3,
'dropout': 0.0
}
model = EyeCue(config)

# 量化
model = torch.quantization.quantize_dynamic(
model,
{nn.Linear},
dtype=torch.qint8
)

return model

def process_frame(self, frame, gaze):
"""
处理单帧

Args:
frame: [C, H, W] 图像
gaze: (x, y) 注视点

Returns:
state: 认知状态预测
"""
# 更新缓存
self.gaze_buffer.append(gaze)

if len(self.gaze_buffer) < self.buffer_size:
return None # 等待缓存填满

# 滑动窗口
if len(self.gaze_buffer) > self.buffer_size:
self.gaze_buffer.pop(0)

# 准备输入
video = torch.stack([frame] * self.buffer_size).unsqueeze(0)
gaze_seq = torch.FloatTensor(self.gaze_buffer).unsqueeze(0)

# 推理
with torch.no_grad():
logits = self.model(video, gaze_seq)
state = logits.argmax(dim=-1).item()

return state

4.2 硬件需求

平台 延迟 功耗 适用场景
Jetson Orin 35ms 4.5W 高端车型
SA8255 50ms 3.2W 中端车型
MCU边缘 120ms 1.0W 入门车型

五、总结与展望

5.1 核心贡献

  1. 视线增强的视频理解:融合注视点与视频特征
  2. 交叉注意力机制:视频特征attend to注视点序列
  3. 认知分心模式识别:区分视觉分心与认知分心

5.2 应用价值

  • Euro NCAP DSM分心检测(视觉+认知)
  • 高级驾驶辅助(接管准备度判断)
  • 驾驶员培训评估(认知负荷分析)

5.3 未来改进

  1. 多模态扩展:加入生理信号(HRV、EDA)
  2. 个性化模型:适应不同驾驶员基线
  3. 实时优化:模型剪枝+知识蒸馏

5.4 局限性

  • 依赖第一人称摄像头(需头部佩戴)
  • 复杂光照场景性能下降
  • 长时间推理可能累积误差

本文为arXiv 2605.07859论文解读。实际应用需考虑隐私保护与用户接受度。


EyeCue:视线增强的视频认知分心检测
https://dapalm.com/2026/07/20/2026-07-20-08-EyeCue-Cognitive-Distraction-Detection/
作者
Mars
发布于
2026年7月20日
许可协议