DMS 对抗攻击鲁棒性:太阳镜、反光与物理世界攻击

发布时间: 2026-04-14
关键词: Adversarial Attack、DMS、Robustness、太阳镜、物理攻击


对抗攻击威胁

什么是物理世界对抗攻击?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────┐
│ 对抗攻击类型 │
├─────────────────────────────────────────────────────┤
│ │
│ 数字域攻击 │
│ ────────── │
│ • 修改图像像素 │
│ • 添加噪声 │
│ • 在输入层欺骗模型 │
│ │
│ 物理世界攻击 │
│ ────────────── │
│ • 对抗眼镜(Adversarial Eyeglasses) │
│ • 对抗贴纸 │
│ • 对抗衣物 │
│ • 激光/强光干扰 │
│ │
│ DMS 面临的物理攻击: │
│ ──────────────────── │
│ 1. 对抗太阳镜:欺骗眼动追踪 │
│ 2. 反光干扰:强光照射摄像头 │
│ 3. 特殊图案:欺骗人脸检测 │
│ │
└─────────────────────────────────────────────────────┘

对抗眼镜攻击

攻击原理

研究显示,在眼镜上添加特定图案可以欺骗人脸识别系统:

攻击目标 攻击方式
人脸识别 识别为另一个人
眼动追踪 检测不到眼睛
疲劳检测 无法计算 PERCLOS

对抗眼镜示例

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
┌─────────────────────────────────────────────────────┐
│ 对抗眼镜攻击效果 │
├─────────────────────────────────────────────────────┤
│ │
│ 正常眼镜 │
│ ────────── │
│ ┌─────────────────────┐ │
│ │ ┌─────────────┐ │ │
│ │ │ ○───○ │ │ ← 眼睛可见 │
│ │ │ │ │ │ │ 正常检测 │
│ │ └─────────────┘ │ │
│ └─────────────────────┘ │
│ │
│ 对抗眼镜 │
│ ────────── │
│ ┌─────────────────────┐ │
│ │ ┌─────────────┐ │ │
│ │ │ ▓▓▓▓▓▓▓▓ │ │ ← 特殊图案 │
│ │ │ ▓▓▓▓▓▓▓▓ │ │ 检测失败 │
│ │ └─────────────┘ │ │
│ └─────────────────────┘ │
│ │
│ 结果:DMS 无法检测眼睛位置和视线方向 │
│ │
└─────────────────────────────────────────────────────┘

防御代码示例

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

class AdversarialGlassesDetector:
"""对抗眼镜检测器"""

def __init__(self):
self.face_detector = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
)
self.eye_detector = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_eye.xml'
)

def detect_adversarial(self, image: np.ndarray) -> dict:
"""检测对抗眼镜

Returns:
{
'has_glasses': bool,
'is_adversarial': bool,
'confidence': float,
'reason': str
}
"""
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 检测人脸
faces = self.face_detector.detectMultiScale(gray, 1.1, 4)

if len(faces) == 0:
return {
'has_glasses': False,
'is_adversarial': False,
'confidence': 0.0,
'reason': 'no_face'
}

# 取最大人脸
x, y, w, h = max(faces, key=lambda f: f[2] * f[3])
face_roi = gray[y:y+h, x:x+w]

# 检测眼睛
eyes = self.eye_detector.detectMultiScale(face_roi, 1.1, 4)

if len(eyes) < 2:
# 眼睛检测失败,可能是对抗眼镜
return {
'has_glasses': True,
'is_adversarial': True,
'confidence': 0.7,
'reason': 'eyes_not_detected'
}

# 分析眼镜区域纹理
left_eye = eyes[0]
right_eye = eyes[1]

# 提取眼镜区域(眼睛周围)
glasses_region = self._extract_glasses_region(
face_roi, left_eye, right_eye
)

# 检测异常纹理
texture_score = self._analyze_texture(glasses_region)

# 对抗眼镜通常有高纹理复杂度
if texture_score > 0.8:
return {
'has_glasses': True,
'is_adversarial': True,
'confidence': texture_score,
'reason': 'abnormal_texture'
}

return {
'has_glasses': True,
'is_adversarial': False,
'confidence': 1 - texture_score,
'reason': 'normal'
}

def _extract_glasses_region(self, face, left_eye, right_eye):
"""提取眼镜区域"""
# 简化:取两眼之间的区域
x1, y1, w1, h1 = left_eye
x2, y2, w2, h2 = right_eye

# 扩展到眼镜区域
margin = 10
x = min(x1, x2) - margin
y = min(y1, y2) - margin
w = max(x1 + w1, x2 + w2) - x + margin
h = max(y1 + h1, y2 + h2) - y + margin

return face[y:y+h, x:x+w]

def _analyze_texture(self, region: np.ndarray) -> float:
"""分析纹理复杂度"""
if region.size == 0:
return 0.0

# 使用拉普拉斯算子检测边缘
laplacian = cv2.Laplacian(region, cv2.CV_64F)

# 计算方差(纹理复杂度)
variance = laplacian.var()

# 归一化到 0-1
# 对抗眼镜的方差通常很高
score = min(variance / 1000, 1.0)

return score


class RobustDMS:
"""鲁棒 DMS(对抗攻击防御)"""

def __init__(self):
self.glasses_detector = AdversarialGlassesDetector()
self.gaze_estimator = GazeEstimator() # 假设已实现
self.head_pose_estimator = HeadPoseEstimator() # 假设已实现

def process(self, image: np.ndarray) -> dict:
"""处理图像,考虑对抗攻击"""

# 1. 检测对抗眼镜
glasses_result = self.glasses_detector.detect_adversarial(image)

# 2. 如果检测到对抗眼镜,切换到备用方案
if glasses_result['is_adversarial']:
# 使用头部姿态推断视线
head_pose = self.head_pose_estimator.estimate(image)
gaze = self._infer_gaze_from_head_pose(head_pose)

return {
'gaze': gaze,
'confidence': 0.5, # 较低置信度
'defense_triggered': True,
'defense_reason': 'adversarial_glasses',
'head_pose': head_pose
}

# 3. 正常流程
gaze = self.gaze_estimator.estimate(image)

return {
'gaze': gaze,
'confidence': 0.9,
'defense_triggered': False
}

def _infer_gaze_from_head_pose(self, head_pose: dict) -> tuple:
"""从头部姿态推断视线(粗略)"""
# 简化假设:视线方向 ≈ 头部朝向
return (head_pose['pitch'], head_pose['yaw'])

反光与强光干扰

干扰场景

场景 干扰方式 影响
阳光直射 太阳直接照射摄像头 过曝、人脸不可见
玻璃反光 车窗反射强光 摄像头眩光
LED 灯光 对向车灯、路灯 脉冲干扰
红外干扰 强红外源 IR 摄像头失效

防御策略

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
class GlareDetector:
"""强光检测器"""

def detect(self, image: np.ndarray) -> dict:
"""检测强光/眩光

Returns:
{
'has_glare': bool,
'intensity': float,
'location': tuple,
'affected_region': np.ndarray
}
"""
# 转换到灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 检测过曝区域
threshold = 250
overexposed = gray > threshold

# 计算过曝比例
overexposed_ratio = np.sum(overexposed) / overexposed.size

if overexposed_ratio > 0.05:
# 找到过曝区域中心
y_coords, x_coords = np.where(overexposed)
center = (int(np.mean(x_coords)), int(np.mean(y_coords)))

return {
'has_glare': True,
'intensity': overexposed_ratio,
'location': center,
'affected_region': overexposed
}

return {
'has_glare': False,
'intensity': 0.0,
'location': None,
'affected_region': None
}


class HDRProcessor:
"""HDR 处理器(应对强光)"""

def __init__(self, exposure_times: list = [0.01, 0.02, 0.05]):
self.exposure_times = exposure_times

def process(self, images: list) -> np.ndarray:
"""HDR 合成

Args:
images: 不同曝光时间的图像列表

Returns:
HDR 合成后的图像
"""
# 简化:使用加权平均
# 实际需要更复杂的 HDR 算法

result = np.zeros_like(images[0], dtype=np.float32)

for img, exp_time in zip(images, self.exposure_times):
# 权重:曝光时间适中时权重高
weight = np.exp(-((np.log(exp_time) - np.log(0.02)) ** 2))
result += img.astype(np.float32) * weight

result /= len(images)

return result.astype(np.uint8)

对抗训练防御

对抗训练流程

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

class AdversarialTrainer:
"""对抗训练器"""

def __init__(self, model, epsilon: float = 0.01):
self.model = model
self.epsilon = epsilon

def generate_adversarial(self,
images: torch.Tensor,
labels: torch.Tensor) -> torch.Tensor:
"""生成对抗样本(FGSM)"""

images.requires_grad = True

# 前向传播
outputs = self.model(images)
loss = F.cross_entropy(outputs, labels)

# 反向传播
self.model.zero_grad()
loss.backward()

# 生成对抗扰动
perturbation = self.epsilon * images.grad.sign()

# 添加扰动
adversarial_images = images + perturbation
adversarial_images = torch.clamp(adversarial_images, 0, 1)

return adversarial_images

def train_step(self,
images: torch.Tensor,
labels: torch.Tensor,
optimizer: torch.optim.Optimizer) -> float:
"""对抗训练一步"""

# 生成对抗样本
adversarial_images = self.generate_adversarial(images, labels)

# 混合训练
mixed_images = torch.cat([images, adversarial_images], dim=0)
mixed_labels = torch.cat([labels, labels], dim=0)

# 前向传播
outputs = self.model(mixed_images)
loss = F.cross_entropy(outputs, mixed_labels)

# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()

return loss.item()

Euro NCAP 对鲁棒性的要求

测试场景

场景 要求
太阳镜 透过率 > 10% 的太阳镜可检测
口罩 部分遮挡下仍可工作
帽子 不影响人脸检测
夜间 低光照下正常工作
逆光 强逆光下仍可检测

降级策略

场景 降级策略
完全遮挡 通知驾驶员 + 限制功能
部分遮挡 使用替代指标(如头部姿态)
强光干扰 降级检测 + 延长警告时间

参考资源