DMS 传感器融合:RGB + IR + 雷达打造鲁棒舱内感知

发布时间: 2026-04-14
关键词: Sensor Fusion、DMS、RGB、IR、mmWave Radar、多模态


为什么需要传感器融合?

单传感器的局限

传感器 优势 局限性
RGB 摄像头 成本低、信息丰富 光照敏感、夜间失效
IR 摄像头 夜间可用、穿透太阳镜 无色彩信息、成本较高
mmWave 雷达 穿透遮挡、全天候 分辨率低、无法识别人脸

融合的价值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────┐
│ 多传感器融合优势 │
├─────────────────────────────────────────────────────┤
│ │
│ 单传感器覆盖范围 │
│ ─────────────────── │
│ RGB: ░░░░░░░░░░████████████████░░░░░░░░░░ │
│ (夜间失效) │
│ │
│ IR: ████████████████████████████████████ │
│ (全天候,但无色彩) │
│ │
│ Radar: ████████████████████████████████████ │
│ (全天候,穿透遮挡) │
│ │
│ 融合后: │
│ ──────── │
│ ████████████████████████████████████████████ │
│ (全天候 + 高精度 + 鲁棒) │
│ │
└─────────────────────────────────────────────────────┘

融合架构

早期融合 vs 晚期融合

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
┌─────────────────────────────────────────────────────┐
│ 融合策略对比 │
├─────────────────────────────────────────────────────┤
│ │
│ 早期融合 (Early Fusion) │
│ ───────────────────────── │
│ ┌───────┐ │
│ │ RGB │────┐ │
│ └───────┘ │ │
│ ┌───────┐ ├──► 特征拼接 ──► 统一模型 ──► 输出│
│ │ IR │────┤ │
│ └───────┘ │ │
│ ┌───────┐ │ │
│ │ Radar │────┘ │
│ └───────┘ │
│ │
│ 优点:信息保留完整 │
│ 缺点:需要同步、对齐 │
│ │
│ 晚期融合 (Late Fusion) │
│ ────────────────────── │
│ ┌───────┐ ┌───────┐ │
│ │ RGB │────►│ Model │────┐ │
│ └───────┘ └───────┘ │ │
│ ┌───────┐ ┌───────┐ │ │
│ │ IR │────►│ Model │────┼──► 决策融合 ──► 输出│
│ └───────┘ └───────┘ │ │
│ ┌───────┐ ┌───────┐ │ │
│ │ Radar │────►│ Model │────┘ │
│ └───────┘ └───────┘ │
│ │
│ 优点:模块化、易扩展 │
│ 缺点:信息损失 │
│ │
└─────────────────────────────────────────────────────┘

RTSFN:实时时空融合网络

论文核心方法

2025 年发表的 RTSFN(Real-Time Spatiotemporal Fusion Network)提出了跨门控融合机制:

特点 说明
跨门控融合 动态整合多模态信息
边缘部署 支持实时推理
行为 + 生理 同时检测行为和生理信号

架构代码

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

class CrossGatedFusion(nn.Module):
"""跨门控融合模块"""

def __init__(self,
vision_dim: int = 256,
radar_dim: int = 128,
fusion_dim: int = 256):
super().__init__()

# 视觉 -> 雷达 门控
self.vision_gate = nn.Sequential(
nn.Linear(vision_dim, fusion_dim),
nn.Sigmoid()
)

# 雷达 -> 视觉 门控
self.radar_gate = nn.Sequential(
nn.Linear(radar_dim, fusion_dim),
nn.Sigmoid()
)

# 特征变换
self.vision_transform = nn.Linear(vision_dim, fusion_dim)
self.radar_transform = nn.Linear(radar_dim, fusion_dim)

# 输出
self.output_layer = nn.Linear(fusion_dim * 2, fusion_dim)

def forward(self,
vision_features: torch.Tensor,
radar_features: torch.Tensor) -> torch.Tensor:
"""
Args:
vision_features: (B, T, vision_dim) 视觉特征序列
radar_features: (B, T, radar_dim) 雷达特征序列

Returns:
(B, T, fusion_dim) 融合特征
"""
# 门控权重
vision_gate = self.vision_gate(vision_features)
radar_gate = self.radar_gate(radar_features)

# 门控变换
vision_transformed = self.vision_transform(vision_features) * radar_gate
radar_transformed = self.radar_transform(radar_features) * vision_gate

# 拼接融合
fused = torch.cat([vision_transformed, radar_transformed], dim=-1)

return self.output_layer(fused)


class RTSFN(nn.Module):
"""实时时空融合网络"""

def __init__(self,
vision_backbone: str = 'resnet18',
radar_processor: str = 'cnn',
num_behavior_classes: int = 17,
use_physiological: bool = True):
super().__init__()

self.use_physiological = use_physiological

# 视觉编码器
self.vision_encoder = VisionEncoder(backbone=vision_backbone)

# 雷达编码器
self.radar_encoder = RadarEncoder(processor=radar_processor)

# 跨门控融合
self.fusion = CrossGatedFusion(
vision_dim=256,
radar_dim=128,
fusion_dim=256
)

# 时序建模
self.temporal_model = nn.LSTM(
input_size=256,
hidden_size=256,
num_layers=2,
batch_first=True,
bidirectional=True
)

# 行为分类头
self.behavior_head = nn.Sequential(
nn.Linear(512, 256),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(256, num_behavior_classes)
)

# 生理信号头(可选)
if use_physiological:
self.heart_rate_head = nn.Sequential(
nn.Linear(512, 128),
nn.ReLU(),
nn.Linear(128, 1) # 心率预测
)

self.breathing_rate_head = nn.Sequential(
nn.Linear(512, 128),
nn.ReLU(),
nn.Linear(128, 1) # 呼吸频率预测
)

def forward(self,
vision_input: torch.Tensor,
radar_input: torch.Tensor) -> dict:
"""
Args:
vision_input: (B, T, C, H, W) 视频序列
radar_input: (B, T, ...) 雷达数据序列

Returns:
{
'behavior_logits': (B, T, num_classes),
'heart_rate': (B, T, 1) [可选],
'breathing_rate': (B, T, 1) [可选]
}
"""
B, T = vision_input.shape[:2]

# 视觉特征提取
vision_features = []
for t in range(T):
feat = self.vision_encoder(vision_input[:, t])
vision_features.append(feat)
vision_features = torch.stack(vision_features, dim=1) # (B, T, 256)

# 雷达特征提取
radar_features = []
for t in range(T):
feat = self.radar_encoder(radar_input[:, t])
radar_features.append(feat)
radar_features = torch.stack(radar_features, dim=1) # (B, T, 128)

# 跨门控融合
fused_features = self.fusion(vision_features, radar_features)

# 时序建模
temporal_features, _ = self.temporal_model(fused_features)

# 输出
behavior_logits = self.behavior_head(temporal_features)

result = {'behavior_logits': behavior_logits}

if self.use_physiological:
result['heart_rate'] = self.heart_rate_head(temporal_features)
result['breathing_rate'] = self.breathing_rate_head(temporal_features)

return result


class VisionEncoder(nn.Module):
"""视觉特征编码器"""

def __init__(self, backbone: str = 'resnet18'):
super().__init__()

# 加载预训练骨干网络
self.backbone = torch.hub.load(
'pytorch/vision:v0.10.0',
backbone,
pretrained=True
)

# 移除分类头
self.backbone = nn.Sequential(*list(self.backbone.children())[:-1])

# 投影层
self.projection = nn.Linear(512, 256)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: (B, C, H, W) 单帧图像

Returns:
(B, 256) 特征向量
"""
features = self.backbone(x)
features = features.flatten(1)
return self.projection(features)


class RadarEncoder(nn.Module):
"""雷达特征编码器"""

def __init__(self, processor: str = 'cnn'):
super().__init__()

# 雷达数据通常为 Range-Doppler 图
self.conv_layers = nn.Sequential(
nn.Conv2d(2, 32, kernel_size=3, padding=1), # 2 通道:实部 + 虚部
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(2),

nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2),

nn.Conv2d(64, 128, kernel_size=3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.AdaptiveAvgPool2d(1)
)

self.projection = nn.Linear(128, 128)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: (B, 2, H, W) Range-Doppler 图(实部 + 虚部)

Returns:
(B, 128) 特征向量
"""
features = self.conv_layers(x)
features = features.flatten(1)
return self.projection(features)

Tobii + TI 雷达-摄像头融合方案

系统架构

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
┌─────────────────────────────────────────────────────┐
│ Tobii + TI 融合方案 │
├─────────────────────────────────────────────────────┤
│ │
│ Tobii 眼动追踪 │
│ ──────────────── │
│ ┌─────────────────┐ │
│ │ DMS 摄像头 │ 视线估计、眼动特征 │
│ │ (RGB-IR) │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Tobii 算法 │ 准确视线追踪 │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ 智能融合层 │ │
│ │ │ │
│ │ • 动态置信度加权 │ │
│ │ • 冲突解决 │ │
│ │ • 场景感知 │ │
│ │ │ │
│ └────────┬────────────────────────────────┘ │
│ ▲ │
│ │ │
│ ┌────────┴────────┐ │
│ │ TI 60GHz 雷达 │ 微动检测、生理信号 │
│ │ (IWR6843AOP) │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘

融合策略

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
class IntelligentFusion:
"""智能融合层"""

def __init__(self):
# 各传感器的可靠性权重
self.camera_weight = 0.6
self.radar_weight = 0.4

def fuse(self,
camera_result: dict,
radar_result: dict,
context: dict) -> dict:
"""智能融合

Args:
camera_result: {
'gaze': (pitch, yaw),
'confidence': float,
'face_detected': bool
}
radar_result: {
'vital_signs': {'heart_rate': float, 'breathing_rate': float},
'motion': np.ndarray,
'occupancy': bool
}
context: {
'lighting': 'day' | 'night' | 'backlight',
'occlusion': bool,
'scenario': str
}

Returns:
融合后的检测结果
"""
# 根据环境动态调整权重
if context['lighting'] == 'night':
# 夜间:降低摄像头权重
self.camera_weight = 0.4
self.radar_weight = 0.6
elif context['occlusion']:
# 遮挡:大幅降低摄像头权重
self.camera_weight = 0.2
self.radar_weight = 0.8
else:
# 正常光照:摄像头权重高
self.camera_weight = 0.6
self.radar_weight = 0.4

# 融合视线估计
if camera_result['face_detected']:
gaze = camera_result['gaze']
gaze_confidence = camera_result['confidence'] * self.camera_weight
else:
# 无法检测人脸,使用头部姿态推断
gaze = self._infer_from_radar(radar_result)
gaze_confidence = 0.3 * self.radar_weight

# 融合生理信号
vital_signs = radar_result['vital_signs']

# 融合行为检测
if radar_result['motion'].sum() > 0.5:
# 检测到运动,可能是操作行为
behavior = 'active'
else:
behavior = 'static'

return {
'gaze': gaze,
'gaze_confidence': gaze_confidence,
'vital_signs': vital_signs,
'behavior': behavior,
'fusion_weights': {
'camera': self.camera_weight,
'radar': self.radar_weight
}
}

def _infer_from_radar(self, radar_result: dict) -> tuple:
"""从雷达数据推断视线(粗略)"""
# 根据运动方向推断头部朝向
motion = radar_result['motion']

# 简化:假设运动方向对应头部朝向
# 实际需要更复杂的建模

pitch = 0.0 # 简化
yaw = 0.0

return (pitch, yaw)

Anyverse 合成数据验证

为什么需要合成数据?

挑战 真实数据局限 合成数据优势
极端场景 难以采集(如遮挡、极端光照) 可模拟任意场景
传感器同步 时间同步困难 完美同步
标注成本 人工标注昂贵 自动生成真值
多样性 受限于采集条件 可控制所有变量

Anyverse 多模态合成

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
# Anyverse 合成数据生成示例(伪代码)

class AnyverseSyntheticGenerator:
"""Anyverse 合成数据生成器"""

def generate_scene(self, config: dict) -> dict:
"""生成多模态场景

Args:
config: {
'driver': {'gender': 'male', 'age': 35, 'skin_tone': 3},
'behavior': 'phone_talk_left',
'lighting': 'night',
'occlusion': {'type': 'sunglasses'},
'camera': {'type': 'RGB-IR', 'position': 'steering_column'},
'radar': {'type': '60GHz', 'position': 'overhead'}
}

Returns:
{
'rgb_image': np.ndarray,
'ir_image': np.ndarray,
'radar_point_cloud': np.ndarray,
'radar_range_doppler': np.ndarray,
'annotations': {
'gaze': (pitch, yaw),
'behavior': str,
'vital_signs': {'heart_rate': float, 'breathing_rate': float}
}
}
"""
# 调用 Anyverse API(伪代码)
pass

融合系统部署

硬件配置

组件 型号 功能
DMS 摄像头 STURDeCAM57 RGB-IR 视觉感知
60GHz 雷达 TI IWR6843AOP 生理信号 + 运动检测
处理单元 Qualcomm QCS8255 融合计算

软件架构

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
class FusionSystem:
"""融合系统主控"""

def __init__(self):
self.camera = CameraInterface()
self.radar = RadarInterface()
self.fusion_model = RTSFN()
self.decision = DecisionEngine()

def run(self):
"""主循环"""
while True:
# 获取传感器数据
vision_data = self.camera.capture()
radar_data = self.radar.capture()

# 融合推理
result = self.fusion_model(vision_data, radar_data)

# 决策
alert = self.decision.process(result)

if alert:
self._issue_alert(alert)

def _issue_alert(self, alert: dict):
"""发出警告"""
print(f"Alert: {alert['type']} - {alert['message']}")

参考资源