因果视线预测:眼动追踪中断恢复新方案

论文信息

项目 内容
标题 Context-Aware Causal Gaze Forecasting for Human-Vehicle Interaction During In-Cabin Tracking Dropouts
arXiv 2609.12374
关键词 causal gaze forecasting, eye tracking, dropout recovery, causal context
来源 Pith Review

核心创新

眼动追踪丢失时,用因果上下文信息预测驾驶员视线,不需要未来数据。

解决的问题

DMS摄像头在以下场景会丢失眼动追踪:

  1. 剧烈头部运动 — 快速转头时瞳孔不可见
  2. 遮挡 — 手/物体挡住面部
  3. 强光反射 — 红外补光被眼镜反射
  4. 眨眼 — 自然眨眼导致短暂丢失
  5. 姿态极端 — 头部偏转角过大

传统方案:丢失期间输出上一帧的gaze值(导致延迟和误报)
本方案:用因果模型预测丢失期间的gaze

因果 vs 非因果

方案 需要未来数据? 实时性 预测精度
上一帧保持 ❌ ✅ 实时 ❌ 差
Kalman滤波 ❌ ✅ 实时 ⚠️ 中
LSTM预测 ❌ ✅ 实时 ⚠️ 中
非因果上下文 ✅ 需要 ❌ 延迟 ✅ 好
因果上下文 (本文) ❌ 不需要 ✅ 实时 ✅ 好

方法详解

因果上下文门控预测

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
import torch
import torch.nn as nn
import torch.nn.functional as F

class CausalGazeForecaster(nn.Module):
"""
因果视线预测器

核心思路:
1. 只用当前和过去的信息(因果性)
2. 上下文信息门控(不是所有历史都重要)
3. 预测中断期间的gaze值

输入:历史gaze序列 + 上下文(头部姿态、车辆状态等)
输出:预测的gaze值 + 置信度
"""

def __init__(self, gaze_dim=2, context_dim=16, d_model=128,
n_heads=4, n_layers=3, seq_len=30):
super().__init__()
self.seq_len = seq_len
self.d_model = d_model

# Gaze编码
self.gaze_encoder = nn.Linear(gaze_dim, d_model)

# 上下文编码
# 上下文包括:头部姿态(3), 车辆速度(1), 方向盘角(1),
# 时间(1), 车道偏离(1), 交通状态(1) 等
self.context_encoder = nn.Linear(context_dim, d_model)

# 因果自注意力(只看过去)
self.causal_attention = nn.MultiheadAttention(
d_model, n_heads, batch_first=True
)

# 上下文门控
self.context_gate = nn.Sequential(
nn.Linear(d_model * 2, d_model),
nn.Sigmoid()
)

# 预测头
self.gaze_predictor = nn.Sequential(
nn.Linear(d_model, d_model // 2),
nn.ReLU(),
nn.Linear(d_model // 2, gaze_dim)
)

# 置信度预测
self.confidence_head = nn.Sequential(
nn.Linear(d_model, d_model // 2),
nn.ReLU(),
nn.Linear(d_model // 2, 1),
nn.Sigmoid()
)

# 因果掩码(下三角矩阵)
self.register_buffer(
'causal_mask',
torch.triu(torch.ones(seq_len, seq_len) * float('-inf'), diagonal=1)
)

def forward(self, gaze_history, context_history):
"""
Args:
gaze_history: (B, T, 2) 历史gaze [pitch, yaw] 度
context_history: (B, T, C) 上下文历史

Returns:
predicted_gaze: (B, 2) 预测的gaze
confidence: (B, 1) 预测置信度
"""
B, T, _ = gaze_history.shape

# 编码
gaze_emb = self.gaze_encoder(gaze_history) # (B, T, d)
ctx_emb = self.context_encoder(context_history) # (B, T, d)

# 上下文门控融合
gate = self.context_gate(torch.cat([gaze_emb, ctx_emb], dim=-1))
fused = gaze_emb * gate + ctx_emb * (1 - gate)

# 因果自注意力
attended, _ = self.causal_attention(
fused, fused, fused,
attn_mask=self.causal_mask[:T, :T]
)

# 取最后一帧预测
last = attended[:, -1, :] # (B, d)

# 预测gaze
predicted_gaze = self.gaze_predictor(last)
confidence = self.confidence_head(last)

return predicted_gaze, confidence

def predict_dropout(self, gaze_history, context_history,
dropout_duration=10):
"""
预测眼动追踪中断期间的gaze

Args:
dropout_duration: 中断持续帧数

Returns:
predictions: (B, dropout_duration, 2)
confidences: (B, dropout_duration, 1)
"""
predictions = []
confidences = []

current_gaze = gaze_history
current_ctx = context_history

for t in range(dropout_duration):
# 预测下一帧
pred_gaze, conf = self.forward(current_gaze, current_ctx)
predictions.append(pred_gaze)
confidences.append(conf)

# 将预测值追加到历史(自回归)
pred_gaze = pred_gaze.unsqueeze(1) # (B, 1, 2)
current_gaze = torch.cat([current_gaze[:, 1:], pred_gaze], dim=1)

# 上下文也需要预测/外推
# 实际中,车辆状态可以从CAN总线获取
# 这里简单用最后一个上下文值
current_ctx = torch.cat([
current_ctx[:, 1:],
current_ctx[:, -1:].clone()
], dim=1)

return (
torch.stack(predictions, dim=1), # (B, T, 2)
torch.stack(confidences, dim=1) # (B, T, 1)
)


# === DMS集成方案 ===
class DMSTrackingRecovery:
"""DMS眼动追踪中断恢复模块"""

def __init__(self):
self.forecaster = CausalGazeForecaster(
gaze_dim=2, # [pitch, yaw]
context_dim=16, # 上下文维度
d_model=128,
n_heads=4,
n_layers=3,
seq_len=30 # 1秒历史@30fps
)

# 上下文来源
self.context_sources = {
'head_pose': 3, # 头部pitch/yaw/roll
'vehicle_speed': 1, # 车速
'steering_angle': 1, # 方向盘角
'lane_deviation': 1, # 车道偏离
'brake_status': 1, # 刹车状态
'turn_signal': 1, # 转向灯
'time_of_day': 1, # 时间
'weather': 1, # 天气
'traffic_density': 1, # 交通密度
'nav_instruction': 1, # 导航指示
'audio_active': 1, # 音频活动
'phone_detected': 1, # 手机检测
'gaze_velocity': 2, # gaze速度(pitch_vel, yaw_vel)
}

def __call__(self, tracker_status, gaze_history, context_history):
"""
Args:
tracker_status: 'tracking' | 'lost'
gaze_history: (1, 30, 2) 最近30帧gaze
context_history: (1, 30, 16) 上下文

Returns:
gaze_output: (2,) gaze值
confidence: float
source: 'tracker' | 'predicted'
"""
if tracker_status == 'tracking':
return gaze_history[0, -1], 1.0, 'tracker'
else:
with torch.no_grad():
pred, conf = self.forecaster.predict_dropout(
gaze_history, context_history, dropout_duration=1
)
return pred[0, 0], conf[0, 0].item(), 'predicted'


# 测试
if __name__ == "__main__":
model = CausalGazeForecaster(gaze_dim=2, context_dim=16, d_model=64)

B, T = 4, 30
gaze = torch.randn(B, T, 2) # 历史gaze
ctx = torch.randn(B, T, 16) # 上下文

# 单帧预测
pred, conf = model(gaze, ctx)
print(f"输入: gaze {gaze.shape}, context {ctx.shape}")
print(f"预测gaze: {pred.shape}, 置信度: {conf.shape}")

# 中断预测
preds, confs = model.predict_dropout(gaze, ctx, dropout_duration=10)
print(f"中断预测: {preds.shape}, 置信度: {confs.shape}")
print(f"参数量: {sum(p.numel() for p in model.parameters())/1e6:.2f}M")

# DMS集成测试
recovery = DMSTrackingRecovery()
status = 'lost'
g, c, s = recovery(status, gaze[:1], ctx[:1])
print(f"\nDMS恢复: gaze={g.numpy()}, conf={c:.3f}, source={s}")

DMS 集成架构

中断场景分析

中断原因 持续时间 预测可行性 上下文贡献
自然眨眼 100-300ms ✅ 高 头部姿态不变
快速转头 200-500ms ⚠️ 中 转向灯+导航
手部遮挡 300-1000ms ⚠️ 中 手部检测
眼镜反光 不确定 ❌ 低 需要切换IR模式
极端头部角度 500ms+ ⚠️ 中 车辆状态

IMS 开发启示

  1. 眼动中断是DMS关键痛点 — 实际场景中追踪丢失很常见
  2. 因果预测优于简单保持 — 能反映gaze趋势变化
  3. 上下文是关键 — 车辆状态+头部姿态+导航提供丰富线索
  4. 置信度输出重要 — DMS需知道何时可信赖预测
  5. 自回归预测有误差累积 — 10帧后精度下降

局限性

  1. 自回归误差累积 — 长时间中断后预测精度下降
  2. 上下文假设 — 假设CAN总线数据可用
  3. 训练数据 — 需要包含中断场景的数据
  4. 未知中断原因 — 不同原因的中断预测难度不同

总结

因果视线预测为 DMS 眼动追踪中断提供了一个实用的恢复方案。对 IMS 团队:

  1. 实际场景中追踪丢失频率高 — 眨眼、遮挡、反光很常见
  2. 简单”保持上一帧”不够 — 驾驶员视线可能在持续变化
  3. 上下文信息丰富 — CAN总线+头部姿态+导航可提供强信号
  4. 10帧预测窗口足够 — 大多数中断在300-500ms内恢复
  5. 需与追踪器置信度联动 — 追踪器自己应输出质量分数

参考链接: