CCGF 深度解读:因果注视预测——舱内追踪丢失时的实时注视恢复方案

CCGF 深度解读:因果注视预测——舱内追踪丢失时的实时注视恢复方案

论文信息

项目 内容
标题 Context-Aware Causal Gaze Forecasting for Human-Vehicle Interaction During In-Cabin Tracking Dropouts
arXiv 2609.12374 (2026-09-11)
核心方法 CCGF (Causal Context-Gated Forecaster)
评估数据 2,047次自然追踪丢失事件 / 10.5小时 / 10名驾驶员
误差 175.7px (10.5°) — Live场景
开源 数据集+评估协议+baseline(待发布)

1. 核心问题

仪表盘式注视追踪器在大角度头部旋转时丢失眼睛跟踪——而这恰恰是DMS最需要信息的时刻(查盲区、看后视镜、路口扫描)。

1.1 追踪丢失场景

场景 触发条件 发生频率 DMS影响
肩膀检查 (shoulder check) 头部偏航>60° 每次变道 完全失明
看后视镜 头部俯仰+偏航 每30-60秒 注视丢失
路口扫描 大幅度左右看 每个路口 无法判断注意力
遮挡 手/帽/墨镜 不定 局部丢失

1.2 关键统计

指标 数值 说明
head_lost占比 8.5% GazeSense记录时间
事件数 2,047次 自然发生
总驾驶时长 10.5小时 10名驾驶员
监督源 Neon头戴式 不作为模型输入

1.3 因果 vs 非因果

方法 时间约束 可用性 DMS适用
离线填补(双向) 可用t之后数据 事后分析 ❌ 不可实时
因果预测(本文) 仅用t之前+t时刻场景 实时

2. 方法论

2.1 CCGF 架构

graph TB
    subgraph "输入(dropout前60帧历史)"
        A[注视轨迹历史<br/>60帧 gaze + head pose]
        B[场景特征<br/>DINOv3 实时更新]
    end
    
    subgraph "编码器"
        A --> C[时序编码器<br/>LSTM/Transformer]
        B --> D[场景编码器<br/>DINOv3 frozen]
    end
    
    subgraph "可靠性门控"
        C --> E[History Gate<br/>历史可靠性]
        D --> F[Scene Gate<br/>场景可靠性]
        E & F --> G[加权融合]
    end
    
    subgraph "输出"
        G --> H[预测注视方向<br/>2D坐标]
    end
    
    subgraph "两种评估条件"
        I[Live: 场景持续更新]
        J[Frozen: 冻结最后帧]
    end
    
    I --> D
    J --> D

2.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
import torch
import torch.nn as nn
from typing import Tuple, Optional

class CCGF(nn.Module):
"""
Causal Context-Gated Forecaster (CCGF)

因果注视预测器:
- 输入:60帧历史注视+头部姿态 + DINOv3场景特征
- 输出:当前时刻注视方向预测
- 关键:可靠性门控动态融合历史和场景信息

论文:arXiv:2609.12374
"""

def __init__(
self,
gaze_dim: int = 2, # 注视坐标 (x, y)
head_dim: int = 6, # 头部姿态 (yaw, pitch, roll + velocity)
scene_dim: int = 768, # DINOv3 特征维度
hidden_dim: int = 256,
history_frames: int = 60,
):
super().__init__()
self.history_frames = history_frames

# 时序编码器(处理历史注视+头部姿态)
input_dim = gaze_dim + head_dim
self.temporal_encoder = nn.LSTM(
input_size=input_dim,
hidden_size=hidden_dim,
num_layers=2,
batch_first=True,
dropout=0.1,
)

# 场景编码器(DINOv3冻结特征投影)
self.scene_projector = nn.Sequential(
nn.Linear(scene_dim, hidden_dim),
nn.GELU(),
nn.Linear(hidden_dim, hidden_dim),
)

# 可靠性门控
self.history_gate = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim // 4),
nn.GELU(),
nn.Linear(hidden_dim // 4, 1),
nn.Sigmoid(),
)

self.scene_gate = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim // 4),
nn.GELU(),
nn.Linear(hidden_dim // 4, 1),
nn.Sigmoid(),
)

# 融合解码器
self.fusion = nn.Sequential(
nn.Linear(hidden_dim * 2, hidden_dim),
nn.GELU(),
nn.Dropout(0.2),
nn.Linear(hidden_dim, hidden_dim // 2),
nn.GELU(),
nn.Linear(hidden_dim // 2, gaze_dim),
)

def forward(
self,
gaze_history: torch.Tensor, # (B, 60, 2)
head_history: torch.Tensor, # (B, 60, 6)
scene_features: torch.Tensor, # (B, 768) — DINOv3
dropout_progress: float = 0.0, # 0.0=开始丢失, 1.0=长期丢失
) -> torch.Tensor:
"""
因果注视预测

Args:
gaze_history: dropout前60帧注视轨迹
head_history: 同期头部姿态
scene_features: DINOv3场景特征
- Live: 持续更新(含dropout期间)
- Frozen: 冻结最后pre-dropout帧
dropout_progress: 丢失进度(控制门控权重)

Returns:
predicted_gaze: (B, 2) 预测注视坐标

Example:
>>> model = CCGF()
>>> gaze = torch.randn(4, 60, 2) # 60帧历史
>>> head = torch.randn(4, 60, 6)
>>> scene = torch.randn(4, 768)
>>> pred = model(gaze, head, scene, dropout_progress=0.3)
>>> print(f"预测注视: {pred.shape}") # (4, 2)
"""
# 1. 时序编码
combined_input = torch.cat([gaze_history, head_history], dim=-1)
temporal_out, _ = self.temporal_encoder(combined_input)
temporal_feat = temporal_out[:, -1, :] # (B, hidden_dim) 取最后帧

# 2. 场景特征投影
scene_feat = self.scene_projector(scene_features) # (B, hidden_dim)

# 3. 可靠性门控
# 随着丢失时间增长,历史可靠性下降,场景可靠性上升
history_weight = self.history_gate(temporal_feat) * (1 - 0.5 * dropout_progress)
scene_weight = self.scene_gate(scene_feat) * (0.5 + 0.5 * dropout_progress)

# 4. 加权融合
weighted_history = temporal_feat * history_weight
weighted_scene = scene_feat * scene_weight
fused = torch.cat([weighted_history, weighted_scene], dim=-1)

# 5. 预测注视
predicted_gaze = self.fusion(fused)

return predicted_gaze


class GazeDropoutSimulator:
"""
模拟注视追踪丢失场景,用于测试CCGF
"""

def __init__(
self,
fps: int = 30,
history_frames: int = 60,
max_dropout_frames: int = 90, # 3秒最大丢失
):
self.fps = fps
self.history_frames = history_frames
self.max_dropout_frames = max_dropout_frames

def simulate_dropout(
self,
full_gaze: torch.Tensor, # (T, 2) 完整注视轨迹
full_head: torch.Tensor, # (T, 6) 完整头部姿态
dropout_start: int,
dropout_duration: int,
) -> dict:
"""
模拟一次追踪丢失事件

Returns:
event: {
'history_gaze': (60, 2),
'history_head': (60, 6),
'dropout_gaze': (duration, 2), # ground truth
'dropout_duration': int,
}
"""
start = max(0, dropout_start - self.history_frames)

history_gaze = full_gaze[start:dropout_start]
history_head = full_head[start:dropout_start]

end = min(len(full_gaze), dropout_start + dropout_duration)
dropout_gaze = full_gaze[dropout_start:end]

return {
'history_gaze': history_gaze[-self.history_frames:],
'history_head': history_head[-self.history_frames:],
'dropout_gaze': dropout_gaze,
'dropout_duration': dropout_duration,
}


# 实际测试
if __name__ == "__main__":
model = CCGF()

# 模拟输入
B = 4
gaze_hist = torch.randn(B, 60, 2) # 60帧注视历史
head_hist = torch.randn(B, 60, 6) # 60帧头部姿态
scene_feat = torch.randn(B, 768) # DINOv3场景特征

# 不同丢失进度
for progress in [0.0, 0.3, 0.6, 0.9]:
pred = model(gaze_hist, head_hist, scene_feat, progress)
print(f"丢失进度 {progress:.1f}: 预测注视 = {pred[0].tolist()}")

# 模拟完整丢失事件
sim = GazeDropoutSimulator()
full_gaze = torch.cumsum(torch.randn(300, 2) * 0.5, dim=0)
full_head = torch.cumsum(torch.randn(300, 6) * 0.3, dim=0)

event = sim.simulate_dropout(full_gaze, full_head, dropout_start=100, dropout_duration=45)

# 在丢失的每一帧进行预测
predictions = []
for t in range(event['dropout_duration']):
progress = t / sim.max_dropout_frames
pred = model(
event['history_gaze'].unsqueeze(0),
event['history_head'].unsqueeze(0),
scene_feat[:1],
progress,
)
predictions.append(pred.squeeze(0))

predictions = torch.stack(predictions)
gt = event['dropout_gaze']

# 计算误差
errors = torch.norm(predictions - gt, dim=-1)
print(f"\n模拟丢失事件 (45帧/1.5s):")
print(f" 平均误差: {errors.mean().item():.1f} px")
print(f" 最大误差: {errors.max().item():.1f} px")
print(f" 模型参数: {sum(p.numel() for p in model.parameters()) / 1e6:.1f}M")

3. 关键结果

3.1 性能对比

方法 场景条件 误差 (px) 误差 (°) 相对改善
仅历史(惯性预测) 262.7 16.1 baseline
CCGF Frozen 210.8 12.9 -19.8%
CCGF Live 175.7 10.5 -33.1%

3.2 关键发现

发现 说明
Live > Frozen 丢失期间持续更新的场景特征比冻结更有效
场景上下文重要 比纯历史预测减少33%误差
长时间丢失退化 丢失>2秒后场景信息增益递减
8.5%时间受影响 head_lost占记录时间的8.5% — 不可忽视

3.3 评估协议

设置 说明
Leave-one-driver-out 10折交叉验证
自然发生事件 非人工截断
监督源 Neon头戴追踪器(不作为输入)
数据集公开 待发布

4. DMS 架构集成

graph LR
    A[仪表盘摄像头] --> B[注视追踪器<br/>GazeSense]
    B -->|正常| C[注视坐标输出]
    B -->|head_lost| D[CCGF 预测器]
    
    D --> E[历史注视缓冲<br/>60帧]
    D --> F[DINOv3场景特征<br/>实时更新]
    E & F --> G[因果注视预测]
    
    C & G --> H[注意力状态判断<br/>分心/疲劳/正常]
    H --> I[DMS决策]

5. IMS 开发启示

5.1 解决 DMS 盲区

DMS盲区 CCGF解决 IMS建议
肩膀检查时失明 历史注视+场景预测 集成CCGF模块
看后视镜时失明 场景特征持续追踪 Live模式优先
路口扫描失明 因果预测无延迟 实时推理<50ms

5.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
CCGF_DEPLOYMENT_CONFIG = {
"history_buffer": {
"frames": 60, # 2秒@30fps
"content": ["gaze_xy", "head_pose_6dof"],
"storage": "ring buffer",
},
"scene_feature": {
"model": "DINOv3-Small", # 或蒸馏更小模型
"input": "dashboard camera frame",
"update_rate": "30Hz (Live) or frozen (Frozen)",
"dim": 384, # 蒸馏后维度
},
"inference": {
"target_latency": "<50ms",
"platform": "Qualcomm QCS8255 NPU",
"model_size": "<5MB",
"quantization": "INT8",
},
"fallback_logic": {
"dropout_threshold": "head_lost > 3 frames",
"max_prediction_duration": "90 frames (3s)",
"after_max": "fallback to head pose only",
"confidence_flag": "low_confidence_warning",
},
}

5.3 Euro NCAP 2026 映射

Euro NCAP 场景 CCGF支持 说明
D-05 视线偏离 ✅ 丢失时仍可预测 解决转头查盲区的误判
F-01 疲劳检测 ⚠️ 间接支持 长时间预测不可靠
CD-01 认知分心 ⚠️ 间接 注视模式分析
路口扫描 ✅ 核心场景 大幅度左右看

6. 局限性

局限 影响 缓解
10.5°误差仍较大 精度不够高 需更高分辨率场景特征
3秒后退化 长时间丢失不可靠 设最大预测窗口
DINOv3计算量大 边缘部署困难 蒸馏到更小模型
仅评估自然事件 无极端场景 需补充合成极端场景
仪表盘视角限制 不覆盖所有头姿 需多摄像头

7. 结论

CCGF 的核心贡献:

  1. 定义因果注视恢复问题:在线DMS不能使用未来数据
  2. 场景上下文关键:DINOv3 Live更新比冻结减少33%误差
  3. 可靠性门控:随丢失时间动态调整历史/场景权重
  4. 8.5%时间受影响:head_lost不是边缘情况,是核心场景

IMS 启示: DMS在关键时刻(查盲区/路口)追踪丢失是不可接受的。CCGF 提供了实时因果预测方案,建议作为 DMS 的标准容错模块集成。


参考文献

  • CCGF: arXiv:2609.12374, 2026-09
  • DINOv3: Oquab et al., 2024
  • GazeSense: driver-facing RGB gaze tracker
  • Neon Tracker: Pupil Labs, head-mounted ground truth
  • Euro NCAP 2026 OMS Protocol (v1.0)

CCGF 深度解读:因果注视预测——舱内追踪丢失时的实时注视恢复方案
https://dapalm.com/2026/09/15/2026-09-15-ccgf-causal-gaze-forecasting-tracking-dropout-dms-ims/
作者
Mars
发布于
2026年9月15日
许可协议