DMS红外眼动鲁棒性:墨镜/口罩遮挡应对方案

DMS红外眼动鲁棒性:墨镜/口罩遮挡应对方案

发布日期: 2026-07-03
标签: DMS, 红外摄像头, 墨镜遮挡, 口罩检测
分类: 技术方案


核心摘要

Euro NCAP 2026明确要求DMS在墨镜(透光率>70%)和口罩遮挡下保持性能,并对暗墨镜(透光率<15%)在10秒内通知驾驶员。本文解析红外眼动追踪的墨镜穿透原理、口罩遮挡下的关键点迁移检测方案、多波长红外融合抗干扰技术,以及符合Euro NCAP鲁棒性标准的系统集成。


1. Euro NCAP 2026鲁棒性要求

1.1 遮挡场景分类

Euro NCAP Safe Driving Protocol v1.1 Section 6.2:

遮挡类型 透光率/覆盖率 系统要求 警告时限
清墨镜(Clear Sunglasses) >70% 必须保持正常检测 无需警告
浅墨镜(Light Sunglasses) 30%-70% 性能降低≤10% 无需警告
暗墨镜(Dark Sunglasses) <15% 通知驾驶员 ≤10秒
口罩(Face Mask) 覆盖口鼻 性能降低≤15% 无需警告
帽子遮挡眼睛 部分遮挡眼睛 通知驾驶员 ≤10秒
长头发遮挡眼睛 部分遮挡眼睛 通知驾驶员 ≤10秒
厚睫毛妆容 妆妆遮挡 性能降低≤10% 无需警告
长面部毛发(>150mm) 严重遮挡 通知驾驶员 ≤10秒

1.2 性能降级阈值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
### Performance Degradation Thresholds

Euro NCAP 2026鲁棒性测试:

**正常检测性能基准:**
- 眼睑检测准确率:≥95%
- 注视方向准确率:≥90%
- 头部姿态准确率:≥85%

**遮挡场景降级阈值:**
- 清墨镜:性能降级≤5%
- 浅墨镜:性能降级≤10%
- 口罩:性能降级≤15%
- 其他遮挡:系统通知驾驶员(无需保持性能)

2. 墨镜红外穿透原理

2.1 墨镜光学特性

墨镜类型 可见光透光率 红外透光率(850nm) 红外透光率(940nm)
清墨镜 >70% >80% >70%
浅墨镜 30%-70% 60%-80% 50%-70%
暗墨镜 <15% 30%-50% 20%-40%
偏光墨镜 不定 不定(可能阻挡红外) 不定
IR涂层墨镜 不定 <5% <5%(专阻红外)

关键洞察:

  • 普通墨镜(染色)红外透光率高于可见光
  • 偏光墨镜可能阻挡红外(需测试)
  • IR涂层墨镜专门阻挡红外(DMS专用反检测眼镜)

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
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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
"""
多波长红外眼动追踪
墨镜遮挡应对方案

波长选择:
- 850nm:穿透普通墨镜较好,瞳孔检测清晰
- 940nm:隐蔽性好,但墨镜穿透差
- 780nm:穿透最佳,但可见红光(用户体验差)

策略:
1. 双波长交替照射(850nm+940nm)
2. 根据墨镜类型自动切换波长
3. 融合双波长检测结果
"""

import numpy as np
import cv2
from typing import Dict, Tuple
from dataclasses import dataclass

@dataclass
class SunglassesDetection:
"""墨镜检测结果"""

sunglasses_detected: bool # 是否检测到墨镜
transmittance_estimate: float # 透光率估计(0-1)
sunglasses_type: str # 墨镜类型("clear", "light", "dark", "polarized", "ir_blocking")

ir_850nm_detected: bool # 850nm红外检测是否成功
ir_940nm_detected: bool # 940nm红外检测是否成功

wavelength_selection: str # 推荐波长("850nm", "940nm", "fusion")


class MultiWavelengthIREyeTracker:
"""
多波长红外眼动追踪器

墨镜遮挡应对:
1. 检测墨镜类型(透光率估计)
2. 选择最佳波长(850nm/940nm/融合)
3. 眼动检测 + 眼睑检测

Euro NCAP应对策略:
- 清墨镜(>70%透光率):850nm正常检测
- 浅墨镜(30%-70%透光率):850nm+增强曝光
- 暗墨镜(<15%透光率):通知驾驶员(无法检测)
"""

def __init__(self,
ir_850nm_camera_config: Dict,
ir_940nm_camera_config: Dict):
"""
Args:
ir_850nm_camera_config: 850nm红外摄像头配置
ir_940nm_camera_config: 940nm红外摄像头配置
"""
self.850nm_config = ir_850nm_camera_config
self.940nm_config = ir_940nm_camera_config

# 墨镜检测阈值
self.clear_threshold = 0.70
self.light_threshold = 0.30
self.dark_threshold = 0.15

# 眼动检测模型(简化)
self.eye_detector_850nm = None # 加载850nm眼动模型
self.eye_detector_940nm = None # 加载940nm眼动模型

def detect_sunglasses(self,
rgb_image: np.ndarray,
ir_850nm_image: np.ndarray) -> SunglassesDetection:
"""
检测墨镜类型

方法:
1. RGB图像检测眼镜轮廓
2. RGB vs IR亮度对比估计透光率

Args:
rgb_image: RGB可见光图像
ir_850nm_image: 850nm红外图像

Returns:
SunglassesDetection: 墨镜检测结果
"""
# 检测眼镜轮廓(RGB)
glasses_detected = self._detect_glasses_contour(rgb_image)

if not glasses_detected:
return SunglassesDetection(
sunglasses_detected=False,
transmittance_estimate=1.0,
sunglasses_type="none",
ir_850nm_detected=True,
ir_940nm_detected=True,
wavelength_selection="850nm"
)

# 估计透光率(RGB vs IR亮度对比)
transmittance = self._estimate_transmittance(rgb_image, ir_850nm_image)

# 分类墨镜类型
if transmittance > self.clear_threshold:
glasses_type = "clear"
elif transmittance > self.light_threshold:
glasses_type = "light"
elif transmittance > self.dark_threshold:
glasses_type = "medium"
else:
glasses_type = "dark"

# 检测IR穿透能力
ir_850nm_detected = self._check_ir_detection(ir_850nm_image)

# 940nm检测需要单独采集
ir_940nm_detected = True # 假设

# 选择波长
if glasses_type in ["clear", "light"]:
wavelength_selection = "850nm"
elif glasses_type == "medium":
wavelength_selection = "fusion"
else:
wavelength_selection = "notify_driver" # 暗墨镜无法检测

return SunglassesDetection(
sunglasses_detected=True,
transmittance_estimate=transmittance,
sunglasses_type=glasses_type,
ir_850nm_detected=ir_850nm_detected,
ir_940nm_detected=ir_940nm_detected,
wavelength_selection=wavelength_selection
)

def _detect_glasses_contour(self, rgb_image: np.ndarray) -> bool:
"""
检测眼镜轮廓

方法:
- Haar特征分类器
- 或深度学习眼镜检测模型
"""
# 简化实现:基于边缘检测
gray = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2GRAY)
edges = cv2.Canny(gray, 50, 150)

# 检测眼镜形状(两个对称圆形区域)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

glasses_detected = len(contours) > 2 # 至少检测到眼镜轮廓

return glasses_detected

def _estimate_transmittance(self,
rgb_image: np.ndarray,
ir_image: np.ndarray) -> float:
"""
估计墨镜透光率

方法:
- RGB亮度(眼镜区域)vs IR亮度(眼镜区域)
- 红外透光率通常高于可见光透光率

Args:
rgb_image: RGB图像
ir_image: 红外图像

Returns:
transmittance: 估计透光率
"""
# 提取眼镜区域亮度
# 简化:假设眼镜区域在图像中央

# RGB亮度(眼镜区域)
rgb_brightness = np.mean(rgb_image[100:200, 200:400])

# IR亮度(眼镜区域)
ir_brightness = np.mean(ir_image[100:200, 200:400])

# 透光率估计(归一化)
# 正常情况下 RGB亮度 ≈ IR亮度
# 戴墨镜后 RGB亮度降低,IR亮度相对保持

transmittance = rgb_brightness / (ir_brightness + 1e-6)

# 限制范围
transmittance = np.clip(transmittance, 0.0, 1.0)

return transmittance

def _check_ir_detection(self, ir_image: np.ndarray) -> bool:
"""
检查红外眼动检测是否成功

方法:
- 眼睑检测
- 瞳孔检测

Args:
ir_image: 红外图像

Returns:
detected: 是否成功检测
"""
# 简化实现:基于亮度阈值检测眼睛区域

# 眼睛区域亮度特征
eye_region_brightness = np.mean(ir_image[100:150, 300:380])

# 检测阈值
detection_threshold = 50

detected = eye_region_brightness > detection_threshold

return detected

def track_eye_with_sunglasses(self,
ir_850nm_image: np.ndarray,
ir_940nm_image: np.ndarray,
sunglasses_info: SunglassesDetection) -> Dict:
"""
墨镜遮挡下的眼动追踪

Args:
ir_850nm_image: 850nm红外图像
ir_940nm_image: 940nm红外图像
sunglasses_info: 墨镜检测结果

Returns:
eye_tracking_result: 眼动追踪结果
"""
wavelength = sunglasses_info.wavelength_selection

if wavelength == "notify_driver":
# 暗墨镜:无法检测,通知驾驶员
return {
'action': 'notify_driver',
'reason': 'dark_sunglasses_occlusion',
'eye_detected': False,
'gaze_direction': None,
'eyes_closed': None
}

# 选择波长
if wavelength == "850nm":
primary_image = ir_850nm_image
elif wavelength == "940nm":
primary_image = ir_940nm_image
else: # fusion
primary_image = self._fuse_dual_wavelength(ir_850nm_image, ir_940nm_image)

# 眼动检测(简化)
eye_detected = self._check_ir_detection(primary_image)

# 眼睑检测
eyes_closed = self._detect_eyes_closed(primary_image)

# 注视方向(简化)
gaze_direction = self._estimate_gaze_direction(primary_image)

return {
'action': 'eye_tracking',
'wavelength': wavelength,
'eye_detected': eye_detected,
'gaze_direction': gaze_direction,
'eyes_closed': eyes_closed,
'sunglasses_type': sunglasses_info.sunglasses_type,
'transmittance': sunglasses_info.transmittance_estimate
}

def _fuse_dual_wavelength(self,
ir_850nm: np.ndarray,
ir_940nm: np.ndarray) -> np.ndarray:
"""
双波长融合

方法:
- 加权平均(850nm权重较高,穿透更好)
- 或最大值融合(保留最亮特征)

Args:
ir_850nm: 850nm红外图像
ir_940nm: 940nm红外图像

Returns:
fused_image: 融合图像
"""
# 加权融合(850nm权重0.7,940nm权重0.3)
fused = 0.7 * ir_850nm + 0.3 * ir_940nm

return fused.astype(np.uint8)

def _detect_eyes_closed(self, ir_image: np.ndarray) -> bool:
"""眼睑检测(简化)"""
# 基于眼睑区域亮度特征
# 简化实现
return False

def _estimate_gaze_direction(self, ir_image: np.ndarray) -> Tuple[float, float]:
"""注视方向估计(简化)"""
# 简化实现
return (0.5, 0.5) # 默认注视前方


# 测试示例
if __name__ == "__main__":
tracker = MultiWavelengthIREyeTracker(
ir_850nm_camera_config={'fps': 60, 'resolution': (640, 480)},
ir_940nm_camera_config={'fps': 60, 'resolution': (640, 480)}
)

# 模拟图像
rgb_test = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)
ir_850nm_test = np.random.randint(0, 255, (480, 640), dtype=np.uint8)
ir_940nm_test = np.random.randint(0, 255, (480, 640), dtype=np.uint8)

# 检测墨镜
sunglasses_info = tracker.detect_sunglasses(rgb_test, ir_850nm_test)

print(f"=== 墨镜检测结果 ===")
print(f"墨镜检测:{sunglasses_info.sunglasses_detected}")
print(f"透光率估计:{sunglasses_info.transmittance_estimate:.2%}")
print(f"墨镜类型:{sunglasses_info.sunglasses_type}")
print(f"推荐波长:{sunglasses_info.wavelength_selection}")

# 眼动追踪
eye_result = tracker.track_eye_with_sunglasses(ir_850nm_test, ir_940nm_test, sunglasses_info)

print(f"\n=== 眼动追踪结果 ===")
print(f"波长选择:{eye_result['wavelength']}")
print(f"眼睛检测:{eye_result['eye_detected']}")

3. 口罩遮挡应对方案

3.1 口罩遮挡影响分析

检测项 无口罩准确率 口罩遮挡准确率 降级幅度 应对方案
眼睑检测 95% 93% 2% 眼睑区域未遮挡,性能保持
注视方向 90% 85% 5% 依赖眼动特征,性能保持
头部姿态 85% 70% 15% 下巴轮廓丢失,需关键点迁移
疲劳检测 92% 90% 2% PERCLOS眼睑指标未影响
分心检测 88% 85% 3% 注视特征未影响

3.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
"""
口罩遮挡下的头部姿态检测
关键点迁移方案

迁移策略:
- 口鼻关键点丢失 → 使用眼眉+下巴替代
- 轮廓特征迁移 → 额头+眼眉轮廓推断头部姿态
"""

import cv2
import numpy as np
from typing import Dict, List, Tuple

class FaceMaskRobustPoseEstimator:
"""
口罩遮挡下的头部姿态估计器

关键点迁移策略:
- 正常检测:68关键点(Dlib)
- 口罩遮挡:迁移到眼眉+额头关键点

口罩影响:
- 口鼻关键点(51-68)不可见
- 眼眉关键点(17-48)可见
- 额头轮廓关键点(0-16)可见

替代方案:
- 下巴轮廓(0-16)推断头部Y轴旋转
- 眼眉轮廓(17-48)推断头部Z轴旋转
"""

def __init__(self):
# 正常关键点索引(Dlib 68点)
self.NORMAL_LANDMARKS = {
'jaw': range(0, 17),
'left_eyebrow': range(17, 22),
'right_eyebrow': range(22, 27),
'nose': range(27, 36),
'left_eye': range(36, 42),
'right_eye': range(42, 48),
'mouth': range(48, 68)
}

# 口罩遮挡可用关键点
self.MASK_VISIBLE_LANDMARKS = {
'jaw': range(0, 17), # 下巴轮廓可见
'left_eyebrow': range(17, 22),
'right_eyebrow': range(22, 27),
'nose_tip': range(27, 31), # 鼻尖可能可见
'left_eye': range(36, 42),
'right_eye': range(42, 48)
}

# 口罩检测阈值
self.mask_confidence_threshold = 0.5

def detect_face_mask(self, landmarks: List[Tuple[int, int]]) -> bool:
"""
检测是否戴口罩

方法:
- 口鼻关键点(51-68)不可见或异常
- 眼眉关键点(17-48)可见

Args:
landmarks: 人脸关键点

Returns:
mask_detected: 是否检测到口罩
"""
# 检查口鼻关键点可见性
mouth_landmarks = landmarks[48:68]

# 简化判定:口鼻区域关键点缺失或异常
mouth_visible = len(mouth_landmarks) > 0

# 口罩判定
mask_detected = not mouth_visible

return mask_detected

def estimate_pose_with_mask(self,
landmarks: List[Tuple[int, int]],
mask_detected: bool) -> Tuple[float, float, float]:
"""
口罩遮挡下的头部姿态估计

Args:
landmarks: 人脸关键点
mask_detected: 是否检测到口罩

Returns:
(yaw, pitch, roll): 头部姿态(度)
"""
if not mask_detected:
# 正常姿态估计
return self._estimate_pose_normal(landmarks)
else:
# 口罩遮挡:关键点迁移
return self._estimate_pose_mask_occlusion(landmarks)

def _estimate_pose_normal(self, landmarks: List[Tuple[int, int]]) -> Tuple[float, float, float]:
"""
正常姿态估计(68关键点)

方法:
- PnP(Perspective-n-Point)算法
- 3D人脸模型拟合
"""
# 简化实现
yaw = 0.0 # 左右转头
pitch = 0.0 # 上下俯仰
roll = 0.0 # 左右侧倾

return yaw, pitch, roll

def _estimate_pose_mask_occlusion(self, landmarks: List[Tuple[int, int]]) -> Tuple[float, float, float]:
"""
口罩遮挡下的姿态估计(关键点迁移)

方法:
- 使用下巴轮廓(0-16)推断yaw/pitch
- 使用眼眉轮廓(17-48)推断roll

Args:
landmarks: 可见的关键点

Returns:
(yaw, pitch, roll): 头部姿态
"""
# 提取下巴轮廓关键点
jaw_landmarks = landmarks[0:17]

# 提取眼眉关键点
left_eyebrow = landmarks[17:22]
right_eyebrow = landmarks[22:27]

# 计算下巴轮廓对称性推断yaw
jaw_center = np.mean(jaw_landmarks, axis=0)
jaw_left = jaw_landmarks[0]
jaw_right = jaw_landmarks[16]

jaw_width = jaw_right[0] - jaw_left[0]
jaw_offset = jaw_center[0] - (jaw_left[0] + jaw_right[0]) / 2

yaw = np.degrees(np.arctan2(jaw_offset, jaw_width))

# 计算下巴轮廓垂直变化推断pitch
jaw_top = np.min(jaw_landmarks, axis=0)[1]
jaw_bottom = np.max(jaw_landmarks, axis=0)[1]

face_height_estimate = jaw_bottom - jaw_top

# 简化pitch估计
pitch = 0.0

# 计算眼眉倾斜推断roll
left_eyebrow_center = np.mean(left_eyebrow, axis=0)
right_eyebrow_center = np.mean(right_eyebrow, axis=0)

eyebrow_line = right_eyebrow_center - left_eyebrow_center

roll = np.degrees(np.arctan2(eyebrow_line[1], eyebrow_line[0]))

return yaw, pitch, roll


# 测试示例
if __name__ == "__main__":
estimator = FaceMaskRobustPoseEstimator()

# 模拟关键点(68点)
# 简化:仅生成下巴+眼眉关键点
landmarks_test = []

# 下巴轮廓(17点)
for i in range(17):
landmarks_test.append((100 + i * 20, 200))

# 眼眉关键点(10点)
for i in range(10):
landmarks_test.append((150 + i * 10, 150))

# 检测口罩
mask_detected = estimator.detect_face_mask(landmarks_test)

print(f"=== 口罩检测结果 ===")
print(f"口罩检测:{mask_detected}")

# 姿态估计
yaw, pitch, roll = estimator.estimate_pose_with_mask(landmarks_test, mask_detected)

print(f"\n=== 姿态估计结果 ===")
print(f"Yaw(左右转头):{yaw:.2f}°")
print(f"Pitch(上下俯仰):{pitch:.2f}°")
print(f"Roll(左右侧倾):{roll:.2f}°")

4. Euro NCAP系统集成方案

4.1 遮挡通知机制

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
"""
Euro NCAP 2026 遮挡通知机制
墨镜/口罩/帽子遮挡警告

通知要求:
- 暗墨镜(<15%透光率):≤10秒通知
- 帽子遮挡眼睛:≤10秒通知
- 长头发遮挡眼睛:≤10秒通知
- 长面部毛发(>150mm):≤10秒通知

通知方式:
- 视觉警告:仪表盘图标+文字
- 听觉警告:可选(不强制)
"""

from enum import Enum
from typing import Optional
import time

class OcclusionLevel(Enum):
"""遮挡等级"""
NONE = 0 # 无遮挡
PERFORMANCE_OK = 1 # 遮挡但性能保持(清墨镜/口罩)
NOTIFY_DRIVER = 2 # 需通知驾驶员(暗墨镜/帽子)
DISABLE_SYSTEM = 3 # 系统禁用(严重遮挡)


class OcclusionNotificationSystem:
"""
遮挡通知系统

Euro NCAP要求:
- 检测到严重遮挡后≤10秒通知驾驶员
- 通知持续显示直到遮挡解除
- 无需听觉警告(仅视觉警告即可)
"""

def __init__(self):
self.current_level = OcclusionLevel.NONE
self.notification_start_time: Optional[float] = None

# Euro NCAP时间参数
self.notify_threshold_sec = 10

def evaluate_occlusion(self,
sunglasses_info: SunglassesDetection,
mask_detected: bool,
hat_detected: bool,
hair_occlusion: bool,
facial_hair_length_mm: float,
current_time: float) -> dict:
"""
评估遮挡等级并触发通知

Args:
sunglasses_info: 墨镜检测结果
mask_detected: 是否检测到口罩
hat_detected: 是否检测到帽子遮挡眼睛
hair_occlusion: 是否检测到长头发遮挡眼睛
facial_hair_length_mm: 面部毛发长度(mm)
current_time: 当前时间戳

Returns:
notification_command: 通知指令
"""
# 判定遮挡等级

# 1. 墨镜遮挡
if sunglasses_info.sunglasses_detected:
if sunglasses_info.sunglasses_type in ["clear", "light"]:
# 清墨镜/浅墨镜:性能保持
self.current_level = OcclusionLevel.PERFORMANCE_OK
elif sunglasses_info.sunglasses_type in ["medium", "dark"]:
# 暗墨镜:需通知驾驶员
self.current_level = OcclusionLevel.NOTIFY_DRIVER

# 2. 口罩遮挡(性能保持)
if mask_detected:
# 口罩不影响眼动检测,性能保持
if self.current_level == OcclusionLevel.NONE:
self.current_level = OcclusionLevel.PERFORMANCE_OK

# 3. 帽子遮挡(需通知)
if hat_detected:
self.current_level = OcclusionLevel.NOTIFY_DRIVER

# 4. 长头发遮挡(需通知)
if hair_occlusion:
self.current_level = OcclusionLevel.NOTIFY_DRIVER

# 5. 长面部毛发(需通知)
if facial_hair_length_mm > 150:
self.current_level = OcclusionLevel.NOTIFY_DRIVER

# 生成通知指令
notification = self._generate_notification(current_time)

return notification

def _generate_notification(self, current_time: float) -> dict:
"""生成通知指令"""

if self.current_level == OcclusionLevel.NONE:
return {'action': 'clear_notification'}

if self.current_level == OcclusionLevel.PERFORMANCE_OK:
# 性能保持,无需通知
return {'action': 'no_notification', 'performance': 'ok'}

# 需通知驾驶员
if self.notification_start_time is None:
self.notification_start_time = current_time

elapsed = current_time - self.notification_start_time

# Euro NCAP要求≤10秒触发
if elapsed > self.notify_threshold_sec:
return {
'action': 'notify_driver',
'level': self.current_level.value,
'visual': {
'icon': 'occlusion_warning_yellow',
'text': 'DMS PERFORMANCE LIMITED - Please remove obstruction',
'duration': 'persistent',
'location': 'instrument_cluster'
},
'elapsed_sec': elapsed
}
else:
# 延迟通知(等待10秒)
return {
'action': 'pending',
'remaining_sec': self.notify_threshold_sec - elapsed
}

5. IMS开发落地指导

5.1 硬件选型建议

组件 推荐型号 参数要求 原因
850nm红外摄像头 OV2311 / STURDeCAM57 2MP, 850nm IR 墨镜穿透最佳
940nm红外摄像头 OV9282 1MP, 940nm IR 隐蔽性好,双波长融合
红外补光(850nm) ams OSRAM SFH 4740 850nm, 120mW/sr 墨镜穿透增强
红外补光(940nm) ams OSRAM SFH 4715S 940nm, 100mW/sr 隐蔽补光

5.2 测试场景清单

场景编号 检测项 测试条件 通过标准
OCCL-01 清墨镜检测 墨镜透光率>70% 性能降级≤5%
OCCL-02 浅墨镜检测 墨镜透光率30%-70% 性能降级≤10%
OCCL-03 暗墨镜通知 墨镜透光率<15% ≤10秒通知驾驶员
OCCL-04 口罩检测 医用口罩遮挡口鼻 性能降级≤15%
OCCL-05 帽子遮挡 帽子遮挡眼睛部分 ≤10秒通知驾驶员
OCCL-06 长头发遮挡 头发遮挡眼睛 ≤10秒通知驾驶员
OCCL-07 双波长融合 850nm+940nm交替 检测成功率提升≥10%
OCCL-08 遮挡解除 移除遮挡物 ≤5秒清除通知

6. 参考文献

  1. Euro NCAP Safe Driving Protocol v1.1 (2025-10-01), Section 6.2 Occlusion Robustness
  2. ams OSRAM (2026), FIREFLY™ IREDs for Eye Tracking in AR/VR
  3. Reflectacles (IR-Lenses), Anti Facial Recognition Glasses
  4. PatSnap Eureka (2026-05-27), Driver Monitoring Infrared Cameras: Occlusion, Eyewear Robustness, and Night Performance

IMS开发启示

优先级排序

优先级 任务 原因
P0(最高) 双波长红外摄像头 Euro NCAP墨镜鲁棒性核心
P1(高) 墨镜透光率检测 Euro NCAP通知要求
P2(中) 口罩关键点迁移 性能降级要求
P3(低) 遮挡通知系统 Euro NCAP≤10秒通知

下一步行动:

  1. 集成双波长红外摄像头(850nm+940nm)
  2. 实现墨镜透光率检测(RGB vs IR亮度对比)
  3. 实现口罩关键点迁移检测(下巴+眼眉轮廓)
  4. 设计遮挡通知系统(≤10秒触发)

DMS红外眼动鲁棒性:墨镜/口罩遮挡应对方案
https://dapalm.com/2026/07/03/2026-07-03-dms-sunglasses-mask-robustness-zh/
作者
Mars
发布于
2026年7月3日
许可协议