EyeCue:眼动引导的自我中心视频认知分心检测(IJCAI 2026 论文解读)

论文信息

  • 标题: Driver Cognitive Distraction Detection via Gaze-Empowered Egocentric Video Understanding
  • 作者: Lang Zhang, JinYi Yoon, Matthew Corbett, Abhijit Sarkar, Bo Ji
  • 机构: Virginia Tech, Inha University, Army Cyber Institute at West Point
  • 会议: IJCAI 2026(International Joint Conference on Artificial Intelligence)
  • 链接: arXiv:2605.07859
  • 代码: GitHub - langzhang2000/EyeCue

核心创新

首次将眼动信号与自我中心视频融合检测认知分心,准确率 74.38%,超越 11 个基线模型 7% 以上。

认知分心(cognitive distraction)是 DMS 领域最难检测的干扰类型——驾驶员视线在路面上、手在方向盘上,但思绪已经飘离。传统疲劳/分心检测方法对此束手无策。

EyeCue 的核心洞察:认知分心体现在眼动与视觉场景的交互模式中,而非单一模态特征。

方法详解

1. 问题定义

输入:

  • 自我中心视频片段 $\mathcal{F} = {f_t}_{t=1}^n$(n 帧)
  • 眼动坐标序列 $\mathcal{C} = {(x_t, y_t)}_{t=1}^n$

输出: 二分类(认知分心 / 注意力集中)

难点:

  • 认知分心无明确物理动作(手/视线位置正常)
  • 需要理解”眼动-场景”交互模式
  • 现有数据集规模有限、场景单一

2. 架构设计

EyeCue 采用三模块架构:

1
2
3
4
5
6
7
8
9
10
11
┌─────────────────────────────────────────────────────────────┐
│ EyeCue Framework │
├─────────────────┬──────────────────┬────────────────────────┤
Video Encoder │ Gaze Encoder │ GDSQ Module │
│ (场景理解) │ (眼动模式) │ (交互建模) │
├─────────────────┼──────────────────┼────────────────────────┤
│ v_CLS │ g_CLS │ s_CLS │
│ (全局场景特征) │ (全局眼动特征) │ (交互特征) │
└─────────────────┴──────────────────┴────────────────────────┘
↓ Concatenation ↓
[v_CLS, g_CLS, s_CLS] → MLP → 分类

2.1 视频编码器(Video Encoder)

作用: 提取驾驶场景的全局上下文和细粒度视觉细节

输入处理:

  • 眼动引导的视频预处理(叠加注视点、热力图掩码、裁剪感兴趣区域)
  • 增强驾驶员注视区域的特征表达

输出:

  • v_CLS:视频分类标记,全局场景表示
  • $\mathcal{P} = {p_i}_{i=1}^l$:视频 patch 标记序列,细粒度区域特征

骨干网络: TimeSformer / VideoMAE 等时空 Transformer

2.2 眼动编码器(Gaze Encoder)

作用: 建模驾驶员眼动行为模式

处理流程:

1
2
3
4
5
6
7
8
9
10
11
# 1. 坐标嵌入
gaze_coords = [(x_1, y_1), (x_2, y_2), ..., (x_n, y_n)]
embedded_coords = LinearProjection(gaze_coords) # 投影到与视频相同空间

# 2. 添加分类标记
tokens = [CLS_token] + embedded_coords

# 3. Transformer 编码
output = TransformerEncoder(tokens)
g_CLS = output[0] # 全局眼动模式
G = output[1:] # 帧级眼动特征

输出:

  • g_CLS:全局眼动模式(整个视频片段的注视行为总结)
  • $\mathcal{G} = {g_t}_{t=1}^n$:帧级眼动特征序列

2.3 眼动驱动语义查询模块(GDSQ)

核心创新: 显式建模眼动与场景的交互

关键假设: 驾驶员用眼动”查询”周围环境,认知状态体现在查询模式中。

处理流程:

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
# Step 1: 眼动引导的 Patch 选择
def gaze_guided_patch_selection(frame, gaze_point, h=1):
"""
根据眼动坐标选择相关视频 patch

Args:
frame: 视频帧 (H, W, C)
gaze_point: 注视点坐标 (x, y)
h: 选择 patch 数量(单 patch 或多 patch)

Returns:
selected_patches: h 个 patch 标记
"""
patch_size = 16 # 假设 patch 大小
patch_x = int(gaze_point[0] // patch_size)
patch_y = int(gaze_point[1] // patch_size)

selected_patches = []
for dx in range(-h//2, h//2 + 1):
for dy in range(-h//2, h//2 + 1):
if 0 <= patch_x + dx < W_patches and 0 <= patch_y + dy < H_patches:
selected_patches.append(patches[patch_y + dy, patch_x + dx])

return selected_patches

# Step 2: 交叉注意力机制
# Query: 眼动特征 G(驾驶员如何"查询"场景)
# Key/Value: 眼动引导的视觉 patch S(场景中被查询的内容)
def cross_attention(G, S):
"""
建模眼动-场景交互

G: 眼动特征序列 (n, d)
S: 眼动引导的视觉 patch (h*n, d)
"""
for _ in range(M): # M 次迭代优化
attention = MultiHeadAttention(
query=G, # 眼动作为查询
key=S, # 视觉 patch 作为键
value=S # 视觉 patch 作为值
)
G = attention(G)

s_CLS = GlobalAveragePooling(G) # 交互特征
return s_CLS

直觉:

  • 注意力集中时,眼动”查询”的对象与驾驶任务高度相关(红绿灯、行人、前车)
  • 认知分心时,眼动查询模式混乱,或查询对象与驾驶任务无关

3. 数据集:CogDrive

背景: 现有数据集规模小、场景单一,DR(eye)VE 是唯一包含眼动+视频+认知分心标注的数据集

构建方法:

  • 整合 4 个驾驶数据集:DR(eye)VE, BDD-A, DADA-2000, TrafficGaze
  • 统一标注协议,增加认知分心标注
  • 最终规模: 3,662 个自我中心视频片段 + 眼动信号 + 认知分心标签

场景覆盖:

  • 不同道路类型(城市/高速/乡村)
  • 不同时段(白天/夜晚)
  • 不同天气(晴天/雨天/雾天)

实验结果

1. 主要结果

方法类型 代表模型 准确率
眼动单模态 Gaze-Only 55.2%
视频分类 TimeSformer 63.4%
自我中心视频 EgoVLP 65.8%
基础模型 VideoMAE 66.3%
眼动+图像 DCDD 67.2%
EyeCue(本文) EyeCue 74.38%

关键发现:

  • 眼动单模态效果差(55.2%)→ 需要场景上下文
  • 纯视频方法次优(63-66%)→ 需要眼动信号引导
  • EyeCue 融合后提升 7%+

2. 泛化性能

场景 准确率
城市道路 72.1%
高速公路 73.8%
乡村道路 70.5%
白天 74.2%
夜晚 71.3%
晴天 73.5%
雨天 70.8%

结论: 跨场景准确率均超过 70%,泛化能力强。

3. 消融实验

配置 准确率 变化
完整 EyeCue 74.38% -
移除 GDSQ 68.2% -6.18%
移除眼动编码器 69.5% -4.88%
移除视频预处理 71.3% -3.08%

关键模块重要性: GDSQ > 眼动编码器 > 视频预处理

代码复现

1. 环境配置

1
2
3
4
5
6
7
8
9
10
11
# 克隆代码
git clone https://github.com/langzhang2000/EyeCue.git
cd EyeCue

# 创建环境
conda create -n eyecue python=3.10
conda activate eyecue

# 安装依赖
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install timm transformers einops opencv-python matplotlib

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
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
"""
EyeCue 核心模块复现

论文:Driver Cognitive Distraction Detection via Gaze-Empowered Egocentric Video Understanding
会议:IJCAI 2026
"""

import torch
import torch.nn as nn
import torch.nn.functional as F
from einops import rearrange
from timm.models.vision_transformer import Block

class GazeEncoder(nn.Module):
"""
眼动编码器

将眼动坐标序列编码为全局眼动模式和帧级特征
"""

def __init__(self, embed_dim=768, num_heads=12, num_layers=4, max_frames=64):
super().__init__()
self.embed_dim = embed_dim
self.max_frames = max_frames

# 坐标嵌入层(x, y 坐标投影到 embed_dim 维度)
self.coord_embed = nn.Linear(2, embed_dim)

# 位置编码
self.pos_embed = nn.Parameter(torch.zeros(1, max_frames + 1, embed_dim))

# 分类标记
self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))

# Transformer 编码器
self.blocks = nn.ModuleList([
Block(dim=embed_dim, num_heads=num_heads)
for _ in range(num_layers)
])

self.norm = nn.LayerNorm(embed_dim)

def forward(self, gaze_coords):
"""
Args:
gaze_coords: 眼动坐标序列 (B, T, 2),归一化到 [0, 1]

Returns:
g_CLS: 全局眼动特征 (B, embed_dim)
G: 帧级眼动特征 (B, T, embed_dim)
"""
B, T, _ = gaze_coords.shape

# 坐标嵌入
x = self.coord_embed(gaze_coords) # (B, T, embed_dim)

# 添加分类标记
cls_tokens = self.cls_token.expand(B, -1, -1) # (B, 1, embed_dim)
x = torch.cat([cls_tokens, x], dim=1) # (B, T+1, embed_dim)

# 添加位置编码
x = x + self.pos_embed[:, :T+1, :]

# Transformer 编码
for block in self.blocks:
x = block(x)

x = self.norm(x)

# 分离输出
g_CLS = x[:, 0] # (B, embed_dim) - 全局眼动模式
G = x[:, 1:] # (B, T, embed_dim) - 帧级特征

return g_CLS, G


class GazeDrivenSemanticQuery(nn.Module):
"""
眼动驱动语义查询模块(GDSQ)

建模眼动与场景的交互
"""

def __init__(self, embed_dim=768, num_heads=12, num_layers=3, h=1):
super().__init__()
self.h = h # 每个 gaze 点选择的 patch 数量
self.num_layers = num_layers

# 交叉注意力层
self.cross_attn_layers = nn.ModuleList([
nn.MultiheadAttention(embed_dim, num_heads, batch_first=True)
for _ in range(num_layers)
])

self.norms = nn.ModuleList([nn.LayerNorm(embed_dim) for _ in range(num_layers)])

def forward(self, G, video_patches, gaze_coords, patch_size=16, img_size=224):
"""
Args:
G: 眼动特征 (B, T, embed_dim)
video_patches: 视频 patch 标记 (B, T, num_patches, embed_dim)
gaze_coords: 眼动坐标 (B, T, 2),像素坐标
patch_size: patch 大小
img_size: 图像大小

Returns:
s_CLS: 交互特征 (B, embed_dim)
"""
B, T, num_patches, embed_dim = video_patches.shape

# 计算每帧的 patch 网格尺寸
patches_per_side = int(img_size // patch_size)

# 眼动引导的 patch 选择
selected_patches = []
for t in range(T):
# 第 t 帧的 patch
frame_patches = video_patches[:, t, :, :] # (B, num_patches, embed_dim)

# 第 t 帧的眼动坐标
coords = gaze_coords[:, t, :] # (B, 2)

# 计算对应的 patch 索引
patch_x = (coords[:, 0] * img_size / patch_size).long().clamp(0, patches_per_side - 1)
patch_y = (coords[:, 1] * img_size / patch_size).long().clamp(0, patches_per_side - 1)

# 选择 patch(简化版:只选择 gaze 所在的单个 patch)
patch_idx = patch_y * patches_per_side + patch_x # (B,)

# 收集选中的 patch
batch_idx = torch.arange(B, device=frame_patches.device)
selected = frame_patches[batch_idx, patch_idx] # (B, embed_dim)
selected_patches.append(selected)

S = torch.stack(selected_patches, dim=1) # (B, T, embed_dim)

# 交叉注意力:眼动查询场景
# Query: G (眼动特征)
# Key/Value: S (选中的视觉 patch)
x = G
for cross_attn, norm in zip(self.cross_attn_layers, self.norms):
attn_out, _ = cross_attn(query=x, key=S, value=S)
x = norm(x + attn_out)

# 池化得到交互特征
s_CLS = x.mean(dim=1) # (B, embed_dim)

return s_CLS


class EyeCue(nn.Module):
"""
EyeCue 完整模型

融合视频、眼动、交互特征检测认知分心
"""

def __init__(
self,
video_encoder, # 预训练的视频编码器
embed_dim=768,
num_heads=12,
gaze_layers=4,
gdsq_layers=3,
num_classes=2,
max_frames=64
):
super().__init__()

# 视频编码器(预训练 TimeSformer 或 VideoMAE)
self.video_encoder = video_encoder

# 眼动编码器
self.gaze_encoder = GazeEncoder(
embed_dim=embed_dim,
num_heads=num_heads,
num_layers=gaze_layers,
max_frames=max_frames
)

# GDSQ 模块
self.gdsq = GazeDrivenSemanticQuery(
embed_dim=embed_dim,
num_heads=num_heads,
num_layers=gdsq_layers
)

# 分类头
self.classifier = nn.Sequential(
nn.LayerNorm(embed_dim * 3),
nn.Linear(embed_dim * 3, embed_dim),
nn.GELU(),
nn.Dropout(0.3),
nn.Linear(embed_dim, num_classes)
)

def forward(self, video, gaze_coords):
"""
Args:
video: 视频片段 (B, T, C, H, W)
gaze_coords: 眼动坐标 (B, T, 2),归一化到 [0, 1]

Returns:
logits: 分类结果 (B, num_classes)
"""
# 视频编码
v_CLS, video_patches = self.video_encoder(video, return_patches=True)

# 眼动编码
g_CLS, G = self.gaze_encoder(gaze_coords)

# 交互建模
s_CLS = self.gdsq(G, video_patches, gaze_coords)

# 特征融合
combined = torch.cat([v_CLS, g_CLS, s_CLS], dim=-1)

# 分类
logits = self.classifier(combined)

return logits


# ============ 测试代码 ============

if __name__ == "__main__":
# 模拟数据
batch_size = 2
num_frames = 16
img_size = 224

# 模拟视频输入
video = torch.randn(batch_size, num_frames, 3, img_size, img_size)

# 模拟眼动坐标(归一化)
gaze_coords = torch.rand(batch_size, num_frames, 2)

# 创建简化版模型(不加载预训练权重)
class DummyVideoEncoder(nn.Module):
def __init__(self, embed_dim=768):
super().__init__()
self.embed_dim = embed_dim
self.proj = nn.Linear(3 * 16 * 16, embed_dim) # 简化投影

def forward(self, video, return_patches=False):
B, T, C, H, W = video.shape
# 简化处理:将每帧展平后投影
patches = rearrange(video, 'b t c (p1 h) (p2 w) -> b t (p1 p2) (c h w)',
p1=14, p2=14, h=16, w=16)
patches = self.proj(patches)
v_CLS = patches.mean(dim=[1, 2]) # 简化全局特征
return v_CLS, patches

# 实例化模型
video_encoder = DummyVideoEncoder()
model = EyeCue(video_encoder, embed_dim=768)

# 前向传播
with torch.no_grad():
logits = model(video, gaze_coords)

print(f"输入视频形状: {video.shape}")
print(f"输入眼动形状: {gaze_coords.shape}")
print(f"输出分类形状: {logits.shape}")
print(f"预测类别: {logits.argmax(dim=-1)}")

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
46
47
48
49
50
51
52
53
54
55
def inference_pipeline(model, video_path, gaze_data_path):
"""
EyeCue 推理流程

Args:
model: 加载权重的 EyeCue 模型
video_path: 自我中心视频路径
gaze_data_path: 眼动数据路径(CSV/JSON)

Returns:
prediction: "attentive" 或 "distracted"
confidence: 置信度
"""
import cv2
import numpy as np

# 1. 加载视频
cap = cv2.VideoCapture(video_path)
frames = []
while len(frames) < 64: # 采样 64 帧
ret, frame = cap.read()
if not ret:
break
frame = cv2.resize(frame, (224, 224))
frames.append(frame)
cap.release()

# 填充或截断
while len(frames) < 64:
frames.append(frames[-1])
frames = frames[:64]

# 转换为 tensor
video = torch.from_numpy(np.array(frames)).float()
video = video.permute(0, 3, 1, 2).unsqueeze(0) / 255.0 # (1, T, C, H, W)

# 2. 加载眼动数据
import pandas as pd
gaze_df = pd.read_csv(gaze_data_path)
gaze_coords = gaze_df[['x', 'y']].values[:64]
gaze_coords = torch.from_numpy(gaze_coords).float().unsqueeze(0)

# 3. 推理
model.eval()
with torch.no_grad():
logits = model(video, gaze_coords)
probs = torch.softmax(logits, dim=-1)

# 4. 输出结果
pred_idx = probs.argmax().item()
confidence = probs[0, pred_idx].item()

label_map = {0: "attentive", 1: "distracted"}

return label_map[pred_idx], confidence

IMS 开发启示

1. 技术路线

模块 EyeCue 启示 IMS 实施建议
数据采集 自我中心视频 + 眼动信号 集成 AR 眼镜或车内眼动追踪摄像头
特征提取 视频编码器 + 眼动编码器 复用 TimeSformer 预训练模型
交互建模 GDSQ 交叉注意力 实现 GDSQ 模块,推理延迟约 15ms
部署优化 模型量化 + TensorRT 目标:边缘设备实时推理(≥25fps)

2. 硬件需求

组件 最低配置 推荐配置
眼动追踪 单眼 IR 摄像头 双眼 IR 摄像头 + 940nm 补光
计算 QCS8255(Hexagon NPU) Orin-X(GPU 25 TOPS)
存储 2GB 模型权重 4GB 模型权重 + 视频缓存

3. Euro NCAP 2026 对接

认知分心检测场景(预期):

场景编号 描述 EyeCue 检测能力
CD-01 驾驶员思考与驾驶无关的事情 ✅ 可检测(准确率 74%)
CD-02 驾驶员”发呆”但视线在路面 ✅ 核心场景
CD-03 复杂交通场景下的注意力分散 ⚠️ 需扩展训练数据

开发优先级:

  1. 短期(3个月): 复现 EyeCue,在 DR(eye)VE 数据集验证
  2. 中期(6个月): 采集真实驾驶场景数据,扩展 CogDrive 数据集
  3. 长期(12个月): 嵌入式部署优化,满足 Euro NCAP 实时性要求

4. 与现有 IMS 模块集成

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
# IMS 认知分心检测模块接口设计
class CognitiveDistractionModule:
"""
IMS 认知分心检测模块

基于 EyeCue 架构
"""

def __init__(self, model_path, device="cuda"):
self.model = self._load_model(model_path)
self.device = device

def detect(self, video_frames, gaze_sequence):
"""
检测认知分心

Args:
video_frames: 最近 N 帧 RGB 图像 (N, H, W, C)
gaze_sequence: 对应的眼动坐标 (N, 2)

Returns:
result: {
"is_distracted": bool,
"confidence": float,
"attention_areas": list, # 注视区域列表
"risk_level": int # 0-2 风险等级
}
"""
# 预处理
video = self._preprocess_video(video_frames)
gaze = self._preprocess_gaze(gaze_sequence)

# 推理
logits = self.model(video, gaze)
probs = torch.softmax(logits, dim=-1)

# 后处理
is_distracted = probs[0, 1] > 0.6 # 阈值可配置

return {
"is_distracted": is_distracted,
"confidence": probs[0, 1].item(),
"attention_areas": self._extract_attention_areas(gaze_sequence),
"risk_level": 1 if is_distracted else 0
}

5. 与疲劳/分心检测的协同

graph LR
    A[输入视频] --> B[人脸检测]
    B --> C[疲劳检测]
    B --> D[视觉分心检测]
    B --> E[认知分心检测]
    
    C --> F[EAR+PERCLOS]
    D --> G[视线落点+AOI]
    E --> H[EyeCue 模型]
    
    F --> I[决策融合]
    G --> I
    H --> I
    
    I --> J{风险等级}
    J -->|低| K[正常驾驶]
    J -->|中| L[一级警告]
    J -->|高| M[二级警告+干预]

融合策略:

  • 疲劳检测(生理指标)优先级最高
  • 视觉分心(物理行为)次之
  • 认知分心(隐性状态)作为补充

局限性分析

局限 影响 解决方案
数据集规模有限(3,662 样本) 泛化能力受限 扩展数据采集,引入数据增强
依赖眼动追踪设备 成本增加,可靠性依赖硬件 探索纯视频方案作为降级选项
未考虑个体差异 不同驾驶员基线不同 引入个性化校准机制
实时性未充分验证 边缘部署挑战 模型剪枝、量化、知识蒸馏

参考文献

  1. Palazzi, A., et al. “DR(eye)VE: A Dataset for Attention-Based Tasks with Applications to Autonomous and Assisted Driving.” CVPR Workshops, 2018.
  2. Bertasius, G., et al. “Is Space-Time Attention All You Need for Video Understanding?” ICML, 2021. (TimeSformer)
  3. Tong, Z., et al. “VideoMAE: Masked Autoencoders are Data-Efficient Learners for Self-Supervised Video Pre-Training.” NeurIPS, 2022.

总结: EyeCue 为认知分心检测提供了首个有效的深度学习方案,通过眼动-场景交互建模实现了 74.38% 的准确率。对于 IMS 开发,建议优先复现该架构,结合 Euro NCAP 2026 要求进行场景扩展和部署优化。


EyeCue:眼动引导的自我中心视频认知分心检测(IJCAI 2026 论文解读)
https://dapalm.com/2026/06/05/2026-06-05-EyeCue-Cognitive-Distraction-Detection/
作者
Mars
发布于
2026年6月5日
许可协议