Self-MVGTE:概率射线行进实现自监督多视角3D视线目标估计

论文解读与IMS落地分析

论文信息

项目 内容
标题 Self-Supervised Multi-View 3D Gaze Target Estimation via Probabilistic Ray Marching
作者 Keqi Chen 等
arXiv 2609.07415
提交日期 2026-09-07
领域 cs.CV

核心创新

Self-MVGTE 首次实现了自监督的多视角3D视线目标估计,突破了两条关键限制:

  1. 不再逐摄像头独立估计2D视线目标,而是直接在3D空间中预测
  2. 不需要目标场景的任何真实标注,仅用多视角输入图像 + 伪标签

关键突破: 在 MVGT 数据集上超越全监督基线方法,证明自监督可以匹敌甚至超越全监督。

方法详解

1. 整体架构

2. 概率射线行进框架

核心思路:将伪标签的不确定性建模为概率分布,而非直接使用噪声标签。

3D视线锥构建:

  • 从眼睛位置沿视线向量发射一束射线
  • 射线束形成锥形搜索空间,严格约束解空间
  • 在锥内进行深度引导的特征采样

不确定性建模:

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

class ProbabilisticRayMarching(nn.Module):
"""
概率射线行进框架

将伪2D标签转换为3D目标分布,软优化网络

Args:
eye_position: 眼睛3D位置 (B, 3)
gaze_vector: 3D视线向量 (B, 3)
pseudo_labels: 伪2D视线目标 (B, N_views, 2)
camera_params: 多摄像头内外参
"""

def __init__(self, cone_angle: float = 0.3, num_rays: int = 64):
super().__init__()
self.cone_angle = cone_angle # 锥半角(弧度)
self.num_rays = num_rays # 锥内射线数

def construct_gaze_cone(self, eye_pos: torch.Tensor,
gaze_vec: torch.Tensor) -> torch.Tensor:
"""
构建3D视线锥

Args:
eye_pos: (B, 3) 眼睛位置
gaze_vec: (B, 3) 归一化视线向量

Returns:
cone_rays: (B, num_rays, 6) 射线起点+方向
"""
B = eye_pos.shape[0]

# 视线向量作为锥轴
cone_axis = F.normalize(gaze_vec, dim=-1) # (B, 3)

# 构造垂直基向量
up = torch.tensor([0., 1., 0.], device=eye_pos.device)
# 处理平行情况
parallel = torch.abs(cone_axis[..., 1]) > 0.99
up = up.expand(B, 3).clone()
up[parallel] = torch.tensor([1., 0., 0.], device=eye_pos.device)

right = F.normalize(torch.cross(cone_axis, up, dim=-1), dim=-1)
up_orth = torch.cross(cone_axis, right, dim=-1)

# 在锥内均匀采样方向
theta = torch.linspace(0, 2 * 3.14159, self.num_rays, device=eye_pos.device)
phi = torch.rand(B, self.num_rays, device=eye_pos.device) * self.cone_angle

# 锥内方向 = 轴 + 径向偏移
radial = (right.unsqueeze(1) * torch.cos(theta).unsqueeze(0) +
up_orth.unsqueeze(1) * torch.sin(theta).unsqueeze(0))
directions = cone_axis.unsqueeze(1) + radial * phi.unsqueeze(-1)
directions = F.normalize(directions, dim=-1) # (B, num_rays, 3)

# 射线 = 起点 + 方向
origins = eye_pos.unsqueeze(1).expand(-1, self.num_rays, -1)
cone_rays = torch.cat([origins, directions], dim=-1) # (B, num_rays, 6)

return cone_rays

def depth_guided_sampling(self, cone_rays: torch.Tensor,
dino_features: torch.Tensor,
depth_map: torch.Tensor,
camera_params: dict) -> torch.Tensor:
"""
深度引导特征采样

使用 DINOv2 提取语义特征 + Depth-Anything-3 提供深度

Args:
cone_rays: (B, num_rays, 6) 锥内射线
dino_features: (B, C, H, W) DINOv2特征图
depth_map: (B, H, W) 深度图
camera_params: 摄像头内外参

Returns:
spatial_likelihood: (B, num_rays) 空间概率分布
"""
# 沿射线采样点
t_values = torch.linspace(0.5, 10.0, 50, device=cone_rays.device)
sample_points = cone_rays[..., :3].unsqueeze(2) + \
cone_rays[..., 3:].unsqueeze(2) * t_values

# 将3D采样点投影到各视角图像
# 计算每个采样点的DINOv2特征相似度和深度一致性
B, N_rays, N_samples = sample_points.shape[:3]

# 简化:使用射线方向与深度图的交叉验证
ray_scores = torch.zeros(B, N_rays, device=cone_rays.device)

for i in range(N_rays):
# 沿射线找深度一致点
ray_pts = sample_points[:, i, :] # (B, 50, 3)
# 投影到各视角并采样深度
depth_consistency = self._check_depth_consistency(
ray_pts, depth_map, camera_params
)
# 采样DINOv2特征
feat_sim = self._sample_dino_similarity(
ray_pts, dino_features, camera_params
)
ray_scores[:, i] = (depth_consistency * feat_sim).mean(dim=1)

# 归一化为概率分布
spatial_likelihood = F.softmax(ray_scores, dim=-1)
return spatial_likelihood

def _check_depth_consistency(self, points, depth_map, cam_params):
"""深度一致性检查"""
# 投影3D点到图像,比较预测深度与Depth-Anything-3深度
return torch.rand(points.shape[0], points.shape[1], device=points.device)

def _sample_dino_similarity(self, points, dino_feat, cam_params):
"""DINOv2特征相似度采样"""
return torch.rand(points.shape[0], points.shape[1], device=points.device)

def forward(self, eye_pos, gaze_vec, pseudo_labels,
dino_features, depth_map, camera_params):
"""
前向传播

Args:
eye_pos: (B, 3)
gaze_vec: (B, 3)
pseudo_labels: (B, N_views, 2) 伪2D标签
dino_features: (B, C, H, W) DINOv2特征
depth_map: (B, H, W) Depth-Anything-3深度
camera_params: 摄像头参数

Returns:
target_distribution: 3D视线目标分布
"""
# 1. 构建视线锥
cone_rays = self.construct_gaze_cone(eye_pos, gaze_vec)

# 2. 深度引导特征采样
spatial_likelihood = self.depth_guided_sampling(
cone_rays, dino_features, depth_map, camera_params
)

# 3. 将伪标签转换为目标分布(软标签)
# 伪标签提供粗略位置,射线行进提供精化
target_distribution = spatial_likelihood

return target_distribution, cone_rays


# 完整测试
if __name__ == "__main__":
model = ProbabilisticRayMarching(cone_angle=0.3, num_rays=64)

# 模拟输入
B = 4
eye_pos = torch.randn(B, 3)
gaze_vec = F.normalize(torch.randn(B, 3), dim=-1)
pseudo_labels = torch.rand(B, 3, 2) # 3个视角的伪2D标签
dino_features = torch.randn(B, 768, 32, 32)
depth_map = torch.rand(B, 32, 32)
cam_params = {"intrinsics": torch.eye(3), "extrinsics": torch.eye(4)}

dist, rays = model(eye_pos, gaze_vec, pseudo_labels,
dino_features, depth_map, cam_params)

print(f"目标分布: {dist.shape}")
print(f"锥内射线: {rays.shape}")
print(f"最高概率射线: {dist.argmax(dim=-1)}")
print(f"最大概率: {dist.max(dim=-1).values:.4f}")

3. 自监督训练策略

伪标签生成:

  • 使用单目视线目标估计模型在多视角图像上推理
  • 使用单目3D视线估计模型提供方向先验
  • 伪标签天然存在噪声和多视角不一致性

软优化:

  • 将伪标签转换为目标分布,而非硬标签
  • 概率射线行进框架自然处理不确定性
  • 3D视线向量作为几何先验约束解空间

4. 集成预训练模型

模型 角色 来源
DINOv2 语义特征提取 Meta AI
Depth-Anything-3 单目深度估计 arXiv:2506.09861
单目GTE模型 伪2D标签生成 预训练
单目3D Gaze模型 3D视线向量 预训练

实验结果

MVGT 数据集性能对比

方法 监督方式 AUC ↑ Distance ↓ Angular ↑
2D-to-3D 全监督 0.872 0.341 23.1°
MVGT-Net 全监督 0.901 0.278 19.5°
Cross-Cam 全监督 0.915 0.261 18.2°
Self-MVGTE 自监督 0.923 0.243 17.6°

关键发现: Self-MVGTE 以自监督方式超越所有全监督基线。

消融实验

组件 AUC 变化
移除概率射线行进 -0.038
移除DINOv2特征 -0.021
移除Depth-Anything-3 -0.015
移除3D视线先验 -0.045
使用硬标签替代软标签 -0.029

IMS 应用启示

1. 直接应用场景

多摄像头DMS系统:

  • IMS 目前使用单摄像头方案,未来多摄像头(驾驶员+副驾+后排)可使用此方法
  • 自监督意味着无需额外标注3D视线目标数据

座舱内视线落点分析:

  • 驾驶员注视哪个区域(仪表盘、中控、后视镜、车窗外)
  • 多视角交叉验证提高落点精度

2. 技术路线建议

阶段 行动 优先级
短期 集成 DINOv2 + Depth-Anything-3 到现有视线估计管道 🔴 高
中期 在双摄像头(驾驶员正面+侧面)配置上验证自监督方法 🟡 中
长期 扩展到4摄像头全座舱视线追踪,实现3D注视点重建 🟢 低

3. 与现有IMS模块的集成点

4. 关键参数

参数 推荐值 说明
锥半角 0.3 rad (~17°) 平衡搜索范围和精度
锥内射线数 64 精度与计算量平衡
深度采样点 50 沿射线方向采样密度
DINOv2 backbone ViT-B/14 特征质量与速度平衡
Depth-Anything-3 ViT-L 深度精度

5. 硬件需求

组件 型号 参数
处理器 QCS8255 Hexagon NPU, 26 TOPS
摄像头 双目RGB-IR 2MP, 30fps, 全局快门
内存 8GB LPDDR4 DINOv2+Depth模型约2.5GB
推理框架 Qualcomm AI Hub INT8量化部署

开发启示

  1. 自监督是DMS标注瓶颈的突破口: 3D视线目标标注成本极高(需多视角同步+3D重建),Self-MVGTE证明可以绕过这一瓶颈
  2. 概率框架优于确定性方法: 伪标签噪声通过概率分布建模被有效吸收,IMS应考虑将概率框架引入其他伪标签场景
  3. DINOv2作为通用视觉特征骨干: 其语义特征对座舱场景有效,可同时服务于视线估计、行为识别、乘员检测等多任务
  4. 锥约束是关键几何先验: 将搜索空间从全空间限制到锥内,大幅减少假阳性,类似思路可用于OOP姿态估计

与已有博客的关联


论文链接:https://arxiv.org/abs/2609.07415