可穿戴视线追踪器从实验室到道路:4.58°误差揭示的DMS标定难题

论文信息

项目 内容
标题 From Laboratory to Road: Evaluating Wearable Gaze Accuracy for Driving
arXiv 2610.07783
会议 GCPR 2026 (German Conference on Pattern Recognition)
时间 2026年10月6日
作者 William Engel 等
领域 cs.CV
链接 https://arxiv.org/abs/2610.07783

核心发现

首次系统量化可穿戴眼动仪在真实驾驶条件下的精度:平均误差4.58°,通过偏移校准可降至1.10°,但偏移在session间变化,需要在线重校准。

一句话总结: 实验室里精度1°的眼动仪,到了车上变成了4.58°——标准答案在真实世界里不标准。

为什么这很重要

BEV自动驾驶中的视线监督

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# BEV (Bird's Eye View) 自动驾驶中的视线应用
bev_gaze_application = {
"场景": "L3/L4自动驾驶需要监控驾驶员是否可接管",
"方法": "用可穿戴眼动仪记录驾驶员注视BEV中的哪个物体",
"问题": "眼动仪标称精度1-2°,但实际驾驶中可能>4°",
"影响": "4.58°误差→在10米距离上偏差0.8米→无法确定驾驶员在看哪辆车",
"解决": "需要在线重校准+条件依赖的不确定性估计"
}

# 误差到距离的映射
import numpy as np

def angular_to_spatial(angle_deg, distance_m):
"""角度误差→空间位置误差"""
return np.tan(np.radians(angle_deg)) * distance_m

print("角度误差 → 不同距离的空间误差:")
print(f"{'距离(m)':<10} {'1°误差':<12} {'4.58°误差':<12} {'1.10°校准后':<12}")
print("-" * 50)
for d in [5, 10, 20, 50, 100]:
e1 = angular_to_spatial(1, d)
e_raw = angular_to_spatial(4.58, d)
e_cal = angular_to_spatial(1.10, d)
print(f"{d:<10} {e1:<10.2f}m {e_raw:<10.2f}m {e_cal:<10.2f}m")

实验设计

1. 研究框架

2. 道路实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
road_experiment = {
"场景": "驾驶员注视前方车辆车牌",
"验证场景数": 41,
"测量方法": "眼动仪估计注视方向 vs 车牌实际角度",
"原始误差": "4.58° (mean)",
"校准后误差": "1.10° (offset-corrected)",
"改善": "全部41个场景均有改善",
"关键发现": "偏移在session间变化 → 需在线重校准"
}

print(f"道路实验结果:")
print(f" 验证场景: {road_experiment['验证场景数']}")
print(f" 原始误差: {road_experiment['原始误差']}")
print(f" 校准后: {road_experiment['校准后误差']}")
print(f" 改善: 4.58° → 1.10° (降低76%)")
print(f" 关键发现: {road_experiment['关键发现']}")

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

class GazeErrorFactors:
"""
影响可穿戴眼动仪精度的5个因素
"""

factors = {
"distance": {
"desc": "注视距离",
"effect": "近距离(<1m)误差大,远距离(>5m)误差小",
"driving_impact": "车内仪表(近) vs 路面车辆(远)"
},
"illumination": {
"desc": "光照条件",
"effect": "暗光→瞳孔扩张→模型偏差",
"driving_impact": "隧道/夜间/逆光"
},
"head_motion": {
"desc": "头部运动",
"effect": "运动→眼镜滑动→标定失效",
"driving_impact": "驾驶员转头看后视镜"
},
"target_motion": {
"desc": "目标运动",
"effect": "运动目标→追视→动态误差",
"driving_impact": "注视移动的行人/车辆"
},
"gaze_eccentricity": {
"desc": "视线偏心度",
"effect": "直视→精度高;斜视→精度低",
"driving_impact": "注视侧窗vs前方"
}
}

@classmethod
def print_analysis(cls):
for name, info in cls.factors.items():
print(f"\n{info['desc']}:")
print(f" 效果: {info['effect']}")
print(f" 驾驶影响: {info['driving_impact']}")

GazeErrorFactors.print_analysis()

方法详解

偏移校准模型

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

class GazeOffsetCalibration:
"""
可穿戴眼动仪偏移校准

发现:原始误差主要是系统性偏移(非随机)
校准:从室内数据估计偏移向量,应用到道路数据

问题:偏移在session间变化
解决:需要在线重校准
"""

def __init__(self):
self.offset = np.zeros(2) # (pitch_offset, yaw_offset)

def estimate_offset(self, indoor_data):
"""
从室内校准数据估计偏移

indoor_data: [(gaze_pred, gaze_true), ...]
"""
errors = np.array([
pred - true for pred, true in indoor_data
])
self.offset = np.mean(errors, axis=0)
return self.offset

def apply_correction(self, gaze_pred):
"""应用偏移校准"""
return gaze_pred - self.offset

def evaluate(self, gaze_pred, gaze_true):
"""评估校准前后的误差"""
raw_error = np.mean(np.sqrt(np.sum(
(gaze_pred - gaze_true)**2, axis=1
)))

corrected = self.apply_correction(gaze_pred)
cal_error = np.mean(np.sqrt(np.sum(
(corrected - gaze_true)**2, axis=1
)))

return {
"raw_error": raw_error,
"corrected_error": cal_error,
"improvement": raw_error - cal_error
}


# 模拟实验结果
np.random.seed(42)

# 室内校准数据(10个点)
indoor_data = [
(np.array([5.0, 3.0]), np.array([2.0, 1.0])) # 偏移~3°
for _ in range(10)
]

# 道路测试数据(41个场景)
road_data = [
(np.array([8 + np.random.randn()*0.5,
6 + np.random.randn()*0.5]),
np.array([5 + np.random.randn()*0.3,
3 + np.random.randn()*0.3]))
for _ in range(41)
]

cal = GazeOffsetCalibration()

# 估计偏移
offset = cal.estimate_offset(indoor_data)
print(f"估计偏移: pitch={offset[0]:.2f}°, yaw={offset[1]:.2f}°")

# 评估
gaze_pred = np.array([d[0] for d in road_data])
gaze_true = np.array([d[1] for d in road_data])

result = cal.evaluate(gaze_pred, gaze_true)
print(f"\n道路测试结果:")
print(f" 原始误差: {result['raw_error']:.2f}°")
print(f" 校准后误差: {result['corrected_error']:.2f}°")
print(f" 改善: {result['improvement']:.2f}° ({result['improvement']/result['raw_error']*100:.0f}%)")

print(f"\n⚠️ 关键发现: 偏移在session间变化")
print(f" → 固定偏移校准无法长期有效")
print(f" → 需要在线重校准机制")

在线重校准策略

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

利用驾驶场景中的自然锚点进行自动校准
"""

def __init__(self):
self.methods = {
"road_center": {
"desc": "假设驾驶员大部分时间看道路中心",
"method": "统计长时间视线分布的众数作为零点",
"advantage": "无需额外标定动作",
"disadvantage": "假设不一定成立"
},
"mirror_glance": {
"desc": "后视镜扫视作为已知锚点",
"method": "检测到后视镜扫视事件→用已知后视镜角度校准",
"advantage": "后视镜角度可从车辆配置获取",
"disadvantage": "需要后视镜扫视检测"
},
"instrument_cluster": {
"desc": "仪表盘扫视作为已知锚点",
"method": "检测到看仪表盘→用仪表盘角度校准",
"advantage": "仪表盘位置固定",
"disadvantage": "不是所有驾驶员都频繁看仪表盘"
},
"periodic_calibration": {
"desc": "定期主动校准",
"method": "提示驾驶员看指定点(如后视镜中心)",
"advantage": "最准确",
"disadvantage": "干扰驾驶体验"
}
}

def recommend(self):
"""推荐组合策略"""
return [
"road_center(持续隐性校准)",
"mirror_glance(每次扫视后视镜时校准)",
"periodic_calibration(每30分钟主动校准一次)"
]

recal = OnlineRecalibration()
print("在线重校准策略:")
for name, info in recal.methods.items():
print(f"\n {name}: {info['desc']}")
print(f" 方法: {info['method']}")

print(f"\n推荐组合: {recal.recommend()}")

对DMS(非可穿戴)的启示

车载DMS vs 可穿戴眼动仪

维度 车载DMS摄像头 可穿戴眼动仪
安装位置 固定(方向盘后方) 眼镜上(随头动移动)
标定 出厂固定 每次佩戴需标定
头动影响 小(固定安装) 大(眼镜滑动)
基线精度 3-5° 1-2°(实验室)/ 4-5°(道路)
长期稳定性 ✅ 好 ❌ 差(session间变化)

车载DMS可借鉴的经验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 车载DMS虽然固定安装,但仍存在类似的偏移问题
dms_offset_issues = {
"驾驶员身高差异": "不同身高→面部在画面中位置不同→视线角度映射有偏移",
"座椅位置变化": "座椅调节→相对摄像头角度变化",
"墨镜遮挡": "遮挡→模型退化→系统性偏移",
"光照变化": "昼夜→瞳孔大小变化→特征点位置偏移",
}

# 从论文学到的DMS改进
dms_improvements = {
1: "定期自动校准:利用后视镜扫视/仪表盘扫视作为已知锚点",
2: "条件依赖的不确定性估计:不同条件下输出不同置信度",
3: "多session校准:不依赖一次性出厂标定,持续优化",
4: "偏移检测:监控视线分布的系统性偏移"
}

print("车载DMS从论文学到的改进:")
for k, v in dms_improvements.items():
print(f" {k}. {v}")

具体改进方案

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
class AdaptiveDMSCalibration:
"""
自适应DMS校准方案

借鉴可穿戴眼动仪的在线重校准思想
应用到固定安装的车载DMS
"""

def __init__(self):
self.calibration_anchors = {
"forward_gaze": {
"method": "长时间直行时视线众数",
"update_rate": "每5分钟",
"confidence": "高"
},
"mirror_glance": {
"method": "后视镜扫视时已知角度",
"update_rate": "每次扫视时",
"confidence": "中"
},
"instrument_check": {
"method": "看速度仪表时已知角度",
"update_rate": "每次扫视时",
"confidence": "中"
}
}
self.calibration_matrix = np.eye(2) # 2x2仿射变换

def update_calibration(self, anchor, gaze_pred, gaze_known):
"""
用已知锚点更新校准

gaze_pred: 模型预测的视线
gaze_known: 锚点的真实角度
"""
offset = gaze_pred - gaze_known
# 指数移动平均更新
alpha = 0.05 # 学习率
self.calibration_offset = (
(1-alpha) * self.calibration_offset + alpha * offset
if hasattr(self, 'calibration_offset')
else offset
)

def correct(self, gaze_pred):
"""应用校准"""
if hasattr(self, 'calibration_offset'):
return gaze_pred - self.calibration_offset
return gaze_pred

测试场景

GAZE-CAL-01 DMS自动校准测试

前置条件:

  • 车载DMS摄像头已安装
  • 驾驶员身高170cm,座椅居中

测试步骤:

  1. 驾驶员直行10分钟 → 系统建立视线基线
  2. 驾驶员扫视后视镜 → 系统用已知角度校准
  3. 调整座椅前移5cm → 记录视线偏移
  4. 系统自动检测偏移并用后视镜扫视重校准

判定条件:

场景 校准前误差 校准后误差 通过条件
初始 3-5° <2° ✅
座椅调整 5-8° <2° ✅
墨镜 5-10° <3° ✅
夜间 4-6° <2° ✅

结论

这篇GCPR 2026论文虽然聚焦可穿戴眼动仪,但对车载DMS有重要启示:

  1. 标称精度≠实际精度 — 实验室1°可能变成道路4.58°
  2. 偏移校准有效但不稳定 — session间变化需在线重校准
  3. 自然锚点校准 — 后视镜/仪表盘扫视可作为自动校准锚点
  4. 条件依赖不确定性 — 不同条件需要不同的不确定性估计
  5. 车载DMS同样需要自适应校准 — 座椅调节/驾驶员变化都引入偏移

建议:

  • 在DMS中实现基于后视镜扫视的自动校准机制
  • 添加视线分布偏移检测(监控系统性偏移)
  • 按条件(光照/遮挡/驾驶员变化)输出不同的不确定性

论文来源:arXiv:2610.07783 (GCPR 2026), 可穿戴眼动仪驾驶精度评估