从实验室到道路:可穿戴注视追踪在真实驾驶中的精度评估与校准——GCPR 2026论文解读

论文信息

项目 内容
标题 From Laboratory to Road: Evaluating Wearable Gaze Accuracy for Driving
作者 William Engel 等
会议 GCPR 2026 (German Conference on Pattern Recognition)
类型 Extended Abstract (Poster)
arXiv 2610.07783
关键词 Mobile eye tracking, Gaze accuracy, Driving perception, Spatial supervision, Error modeling

核心问题

BEV表示与驾驶员注视的差距

自动驾驶系统广泛使用鸟瞰图(BEV)作为感知和规划之间的接口,但BEV只编码”场景中有什么”,而非”对驾驶员什么是行为相关的”。

驾驶员注视提供了这一空白的行为信号,但可穿戴眼动追踪的空间输出通常被当作真值使用,实际上受到多种因素影响:

误差来源 影响机制 典型误差
校准漂移 设备佩戴中滑动 2-3°系统性偏移
头部运动 相对运动导致追踪退化 可达5.8°+
光照变化 瞳孔大小变化影响模型 分散度增加40-50%
注视偏心度 远离光轴精度下降 偏心区偏差增加3x
目标运动 追踪延迟和系统性滞后 0.3-0.5°偏差

核心发现

道路驾驶平均注视误差4.58°,通过室内校准偏移校正降至1.10°,改善76%,且41个场景全部改善。

方法论

整体框架

道路实验设计

场景设置

参数 数值
驾驶时长 30分钟自然驾驶
场景-camera视角 32%外部道路 + 68%车内
注视范围 ±20°方位角, 0-20°仰角
验证场景数 41个
参考目标 车辆车牌中心
目标检测 YOLO + 手动审核
同步方式 语音关键词检测 + 时间戳对齐

误差测量方法

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
import numpy as np
from typing import Tuple

class GazeErrorMeasurement:
"""
道路注视误差测量框架

论文 Section 3.2 的方法实现

测量流程:
1. 驾驶员声明注视目标(语音)
2. YOLO检测车辆+车牌
3. 车牌中心作为参考点
4. 计算注视光线与参考光线的角度差
"""

def __init__(self, camera_intrinsics: dict):
"""
Args:
camera_intrinsics: 相机内参
fx, fy: 焦距
cx, cy: 主点
dist: 畸变系数
"""
self.fx = camera_intrinsics['fx']
self.fy = camera_intrinsics['fy']
self.cx = camera_intrinsics['cx']
self.cy = camera_intrinsics['cy']
self.dist = camera_intrinsics.get('dist', None)

def pixel_to_ray(self, pixel: np.ndarray) -> np.ndarray:
"""
像素坐标转单位光线

Args:
pixel: (2,) 像素坐标 [u, v]

Returns:
ray: (3,) 单位光线方向
"""
# 去畸变
u, v = pixel
x = (u - self.cx) / self.fx
y = (v - self.cy) / self.fy

# 归一化
norm = np.sqrt(x**2 + y**2 + 1)
ray = np.array([x, y, 1]) / norm
return ray

def angular_gaze_error(self, gaze_pixel: np.ndarray,
target_pixel: np.ndarray) -> float:
"""
计算角度注视误差

Args:
gaze_pixel: (2,) 注视点像素坐标
target_pixel: (2,) 目标点像素坐标

Returns:
error_deg: 角度误差(度)
"""
gaze_ray = self.pixel_to_ray(gaze_pixel)
target_ray = self.pixel_to_ray(target_pixel)

# 两光线间夹角
cos_angle = np.dot(gaze_ray, target_ray)
cos_angle = np.clip(cos_angle, -1, 1)
angle_rad = np.arccos(cos_angle)
angle_deg = np.degrees(angle_rad)

return angle_deg

def signed_bias(self, gaze_pixel: np.ndarray,
target_pixel: np.ndarray) -> Tuple[float, float]:
"""
计算有符号偏差(方位角/仰角)

Returns:
azimuth_bias: 方位角偏差(度)
elevation_bias: 仰角偏差(度)
"""
gaze_ray = self.pixel_to_ray(gaze_pixel)
target_ray = self.pixel_to_ray(target_pixel)

# 分解为方位角和仰角
gaze_az = np.arctan2(gaze_ray[0], gaze_ray[2])
gaze_el = np.arcsin(gaze_ray[1])
target_az = np.arctan2(target_ray[0], target_ray[2])
target_el = np.arcsin(target_ray[1])

az_bias = np.degrees(gaze_az - target_az)
el_bias = np.degrees(gaze_el - target_el)

return az_bias, el_bias

def fixation_precision(self, gaze_samples: np.ndarray,
target_pixel: np.ndarray) -> float:
"""
注视内精度(一个注视事件内的分散度)

Args:
gaze_samples: (N, 2) 一次注视的N帧注视点
target_pixel: (2,) 目标点

Returns:
precision_deg: 注视内精度(度)
"""
errors = []
for g in gaze_samples:
errors.append(self.angular_gaze_error(g, target_pixel))

# 中位精度
return np.median(errors)


class OffsetCalibration:
"""
偏移校正框架

论文 Section 3.4 的方法:
1. 从室内校准场景估计偏移量
2. 将偏移转移到道路场景
3. 偏移 = 校准场景中注视到目标的角度差的中位数
"""

def __init__(self):
self.offset = None # (azimuth, elevation) in degrees
self.scene_offsets = {} # 每个校准场景的偏移

def estimate_offset(self, gaze_pixels: np.ndarray,
target_pixels: np.ndarray,
camera_intrinsics: dict) -> Tuple[float, float]:
"""
从校准数据估计偏移

Args:
gaze_pixels: (N, 2) 校准时的注视点
target_pixels: (N, 2) 校准目标点
camera_intrinsics: 相机内参

Returns:
offset: (az_offset, el_offset) 偏移量(度)
"""
measurer = GazeErrorMeasurement(camera_intrinsics)

az_biases = []
el_biases = []

for g, t in zip(gaze_pixels, target_pixels):
az_b, el_b = measurer.signed_bias(g, t)
az_biases.append(az_b)
el_biases.append(el_b)

# 中位数偏移
az_offset = np.median(az_biases)
el_offset = np.median(el_biases)

self.offset = (az_offset, el_offset)
return self.offset

def apply_offset(self, gaze_pixels: np.ndarray,
camera_intrinsics: dict) -> np.ndarray:
"""
将偏移应用到道路注视数据

Args:
gaze_pixels: (N, 2) 原始注视点

Returns:
corrected_pixels: (N, 2) 校正后注视点
"""
if self.offset is None:
return gaze_pixels

# 将偏移从角度转回像素偏移
az_off, el_off = self.offset
fx = camera_intrinsics['fx']
fy = camera_intrinsics['fy']

# 角度偏移→像素偏移(小角度近似)
du = fx * np.radians(az_off)
dv = fy * np.radians(el_off)

corrected = gaze_pixels.copy()
corrected[:, 0] += du
corrected[:, 1] += dv

return corrected


# 测试
if __name__ == "__main__":
print("=" * 60)
print("可穿戴注视追踪精度评估 - 测试")
print("=" * 60)

# 模拟相机内参
intrinsics = {'fx': 600, 'fy': 600, 'cx': 320, 'cy': 240}

measurer = GazeErrorMeasurement(intrinsics)

# 模拟注视点和目标
gaze = np.array([350, 200]) # 注视点
target = np.array([340, 210]) # 目标车牌中心

error = measurer.angular_gaze_error(gaze, target)
az_b, el_b = measurer.signed_bias(gaze, target)

print(f"\n注视点: {gaze}")
print(f"目标点: {target}")
print(f"角度误差: {error:.2f}°")
print(f"方位角偏差: {az_b:.2f}°")
print(f"仰角偏差: {el_b:.2f}°")

# 偏移校正
calibrator = OffsetCalibration()

# 模拟校准数据(有系统性偏移)
np.random.seed(42)
n_cal = 100
targets_cal = np.random.randint(200, 440, (n_cal, 2)).astype(float)
gazes_cal = targets_cal + np.array([8, -5]) + np.random.randn(n_cal, 2) * 3

offset = calibrator.estimate_offset(gazes_cal, targets_cal, intrinsics)
print(f"\n估计偏移: 方位角={offset[0]:.2f}°, 仰角={offset[1]:.2f}°")

# 模拟道路数据
road_targets = np.random.randint(200, 440, (41, 2)).astype(float)
road_gazes = road_targets + np.array([8, -5]) + np.random.randn(41, 2) * 4

# 校正前误差
errors_before = [measurer.angular_gaze_error(g, t)
for g, t in zip(road_gazes, road_targets)]
print(f"\n校正前: 平均误差={np.mean(errors_before):.2f}°")

# 校正后误差
corrected_gazes = calibrator.apply_offset(road_gazes, intrinsics)
errors_after = [measurer.angular_gaze_error(g, t)
for g, t in zip(corrected_gazes, road_targets)]
print(f"校正后: 平均误差={np.mean(errors_after):.2f}°")
print(f"改善: {(1-np.mean(errors_after)/np.mean(errors_before))*100:.1f}%")
print(f"改善场景数: {sum(1 for a,b in zip(errors_after, errors_before) if a < b)}/41")

室内控制实验

5个独立协议隔离驾驶相关因素:

协议 因素 方法 关键发现
P1 光照 亮度变化 棋盘格角点注视+亮度扫描 分散度增加40-50%
P2 头部运动 运动/振动 圆形网格+头部旋转/平台振动 分散度可达10°(最大影响)
P3 追踪 目标运动 十字标以不同速度移动 中位数4.03-4.31°
P4 偏心度 注视角度 棋盘格不同角落 偏心区偏差从0.22°→0.74°
P5 深度 距离变化 2-12m等角大小棋盘 4.78-5.26°,无单调趋势

偏移估计与转移

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
class OnlineRecalibration:
"""
在线重校准策略

论文发现:偏移在不同session间变化
→ 可靠BEV监督需要在线重校准和条件相关的偏移估计
"""

def __init__(self, initial_offset=(0, 0),
adaptation_rate=0.01,
min_confidence=0.5):
"""
Args:
initial_offset: 初始偏移
adaptation_rate: 自适应学习率
min_confidence: 最小置信度才更新偏移
"""
self.offset = np.array(initial_offset)
self.eta = adaptation_rate
self.min_conf = min_confidence
self.confidence = 0.0
self.frame_count = 0
self.condition_offset = {} # 条件相关偏移

def update(self, detected_target: np.ndarray,
gaze_pixel: np.ndarray,
condition: str = 'default'):
"""
在线更新偏移(当有可靠检测目标时)

Args:
detected_target: 检测到的目标位置(如交通标志)
gaze_pixel: 当前注视点
condition: 当前驾驶条件(如highway/urban/night)
"""
# 估计瞬时偏移
instant_offset = detected_target - gaze_pixel

# 置信度基于检测置信度
if self.confidence > self.min_conf:
# 指数移动平均
self.offset = (1 - self.eta) * self.offset + self.eta * instant_offset

# 条件相关偏移
if condition not in self.condition_offset:
self.condition_offset[condition] = self.offset.copy()
else:
co = self.condition_offset[condition]
self.condition_offset[condition] = (1 - self.eta) * co + self.eta * instant_offset

self.frame_count += 1
return self.offset

def get_condition_offset(self, condition: str) -> np.ndarray:
"""获取条件相关偏移"""
if condition in self.condition_offset:
return self.condition_offset[condition]
return self.offset

实验结果

核心数据

指标 原始值 校正后 改善
系统基线(2m静态) 4.08° — 基线
道路平均误差 4.58° 1.10° 76%
改善场景比例 — 41/41 (100%) 全部改善
校准间转移 — 100%正转移 平均改善~3°
注视精度(中位数) 0.31° — 稳定
注视精度(均值) 0.37° — 稳定

偏心度影响

区域 方位角偏差中位数
中心区 ~0.22°
中间区 ~0.48°
外围区 ~0.74°

结论:单一全局偏移只是一阶校正,偏心度效应需要局部校正。

因素影响排序

因素 对精度影响 对分散度影响
头部运动 最大(可达10°分散) 最大
光照变化 中等 +40-50%
偏心度 小-中等(0.22→0.74°) 小
距离 小(无单调趋势) 小
追踪速度 小(4.03-4.31°) 小

IMS开发启示

1. 嵌入式DMS校准策略

策略 实现方式 预期精度提升 部署复杂度
出厂校准 生产线固定光照校准 基线精度 无
首次使用校准 驾驶员首次使用时看3-5个固定点 +30% 低
在线自动校准 利用交通标志/后视镜作为参考点 +50% 中
条件自适应 根据光照/路况切换偏移模型 +60% 中高
不确定性输出 输出gaze+不确定性椭圆 N/A(安全增强) 中

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
class UncertaintyAwareGaze:
"""
不确定性感知的注视表示

论文建议:在BEV中表示为不确定区域
而非精确点,用于安全关键决策
"""

def __init__(self, gaze_point, angular_error_std):
"""
Args:
gaze_point: (2,) 注视点像素坐标
angular_error_std: 角度误差标准差(度)
"""
self.gaze = np.array(gaze_point)
self.sigma = np.radians(angular_error_std)

def to_ellipse(self, fx, fy, cx, cy, distance=10.0):
"""
转换为3D空间中的不确定性椭圆

Args:
distance: 到目标的距离(米)

Returns:
ellipse_params: (center, axes, angle)
"""
# 角度误差→空间误差
spatial_sigma = distance * self.sigma # 米

# 椭圆参数
center = self.gaze
axes = (fx * self.sigma, fy * self.sigma) # 像素

return {
'center': center,
'semi_axes': axes,
'angle': 0, # 简化为圆形
'spatial_radius_m': spatial_sigma
}

def covers_target(self, target_point, confidence=0.95):
"""
判断目标是否在注视不确定性区域内

Args:
target_point: (2,) 目标像素坐标
confidence: 置信度

Returns:
is_covered: bool
probability: 目标在区域内的概率
"""
from scipy.stats import chi2

dist = np.linalg.norm(self.gaze - target_point)
threshold = np.sqrt(chi2.ppf(confidence, df=2)) * self.sigma

return dist < threshold * 1000 # 像素尺度转换

3. DMS在线校准落地建议

阶段 时间 实现
Phase 1 上车 检测驾驶员面部,建立初始偏移估计
Phase 2 驾驶中 利用红绿灯/交通标志作为自然校准点
Phase 3 长途驾驶 每30分钟自动重校准(防止漂移)
Phase 4 条件切换 光照/路况变化时切换偏移模型

总结

本文是首个在真实驾驶条件下量化可穿戴注视追踪精度的系统性研究。核心发现:

  1. 误差显著但可校正:原始4.58°→校正后1.10°(76%改善)
  2. 偏移随session变化:需要在线重校准
  3. 偏心度效应:全局偏移只是一阶校正,需要局部校正
  4. 头部运动影响最大:分散度可达10°
  5. 不确定性表示:注视应表示为不确定区域而非精确点

IMS落地建议: 在嵌入式DMS中实现在线自动校准(利用交通标志作为自然校准点),并输出gaze+不确定性,用于安全关键决策。预期精度从2-3°提升到1.5°以下。

信息来源: arXiv:2610.07783 | GCPR 2026