热成像姿态估计在座舱的应用:隐私保护+暗光鲁棒的OOP检测新方案

论文信息

  • 标题: Accelerator-Free Thermal Pose Estimation: Accuracy–Efficiency Trade-Offs on the Raspberry Pi 5
  • 来源: Sensors (MDPI), 2026, 26(16), 5188
  • 链接: https://www.mdpi.com/1424-8220/26/16/5188
  • 发表时间: 2026年8月

核心价值

该论文验证了在无NPU加速的Raspberry Pi 5上实时运行热成像姿态估计的可行性。8-bit量化+Edge TPU推理实现了实时低功耗运行。

对IMS的核心价值:

  1. 隐私保护:热成像捕获热模式而非可见外观,无肤色/面部细节泄露
  2. 暗光鲁棒:完全不需要环境光,夜间驾驶场景完美适配
  3. 低成本:Raspberry Pi 5级别算力即可运行,无需高端NPU
  4. OOP检测:姿态估计可直接用于异常坐姿检测

方法详解

1. 热成像 vs 可见光对比

对比表

维度 可见光RGB 热成像Thermal
暗光性能 ❌ 需要补光 ✅ 完全不依赖环境光
隐私保护 ❌ 面部细节清晰 ✅ 无面部细节
眼动检测 ✅ 高精度 ❌ 分辨率不足
姿态检测 ✅ 高精度 ✅ 足够精度
OOP检测 ⚠️ 受遮挡影响 ✅ 穿透衣物
成本 ~$5-15 ~$30-80
分辨率 1080p+ 80×60 ~ 640×480
帧率 30-60fps 9-30fps

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
"""
热成像传感器选型对比

对座舱DMS/OMS的适配分析
"""
THERMAL_SENSOR_OPTIONS = {
'FLIR Lepton 3.5': {
'resolution': (160, 120),
'fps': 8.7,
'wavelength': '8-14μm (LWIR)',
'fov': 50,
'power': 150, # mW
'cost': '$200-300',
'interface': 'SPI',
'cabin_suitability': '⚠️ 帧率低,分辨率不足'
},
'FLIR Lepton 4.0': {
'resolution': (160, 120),
'fps': 30, # 新提升
'wavelength': '8-14μm',
'fov': 50,
'power': 200,
'cost': '$250-350',
'interface': 'MIPI CSI-2',
'cabin_suitability': '✅ 帧率足够,分辨率适中'
},
'Melexis MLX90640': {
'resolution': (32, 24),
'fps': 4, # 太低
'wavelength': '8-14μm',
'fov': 110,
'power': 50,
'cost': '$30-50',
'interface': 'I2C',
'cabin_suitability': '❌ 分辨率和帧率都太低'
},
'GridEYE AMG8833': {
'resolution': (8, 8),
'fps': 1, # 极低
'wavelength': '8-14μm',
'fov': 60,
'power': 25,
'cost': '$15-30',
'interface': 'I2C',
'cabin_suitability': '❌ 仅适合存在检测,不能姿态估计'
},
'InfiRay IR099': {
'resolution': (256, 192),
'fps': 25,
'wavelength': '8-14μm',
'fov': 50,
'power': 300,
'cost': '$100-150',
'interface': 'MIPI/USB',
'cabin_suitability': '✅ 分辨率和帧率适合姿态估计'
},
'InfiRay P2 Pro (手机级)': {
'resolution': (256, 192),
'fps': 25,
'wavelength': '8-14μm',
'power': 250,
'cost': '$80-120',
'interface': 'USB-C',
'cabin_suitability': '✅ 成本适中'
},
}

# 推荐方案
RECOMMENDED = {
'budget': 'InfiRay IR099 (256×192, 25fps, $100-150)',
'performance': 'FLIR Lepton 4.0 (160×120, 30fps, $250-350)',
'multi_function': 'RGB-IR双模传感器 (可见光+红外, 如OV2311)',
}

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
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
"""
热成像姿态估计模型

基于论文方法:在Raspberry Pi 5上运行
无NPU加速,纯CPU/Edge TPU推理
"""
import torch
import torch.nn as nn
import numpy as np

class ThermalPoseEstimator(nn.Module):
"""
热成像人体姿态估计模型

输入:热成像图 (1, 1, H, W) — 单通道温度分布
输出:关键点热力图 (K, H', W') — K个关键点

关键点定义(座舱简化版,13点):
0: 头顶, 1: 左肩, 2: 右肩, 3: 左肘, 4: 右肘
5: 左腕, 6: 右腕, 7: 躯干中心, 8: 左髋, 9: 右髋
10: 左膝, 11: 右膝, 12: 面部中心
"""

def __init__(self, n_keypoints=13, input_size=(1, 96, 96)):
super().__init__()
self.n_keypoints = n_keypoints

# 轻量级CNN主干(MobileNetV3-Small变体)
self.backbone = nn.Sequential(
# Stage 1: 96×96 → 48×48
nn.Conv2d(1, 16, 3, stride=2, padding=1),
nn.BatchNorm2d(16),
nn.ReLU6(inplace=True),

# Stage 2: 48×48 → 24×24
nn.Conv2d(16, 32, 3, stride=2, padding=1),
nn.BatchNorm2d(32),
nn.ReLU6(inplace=True),

# Stage 3: 24×24 → 12×12 (深度可分离卷积)
nn.Conv2d(32, 32, 3, groups=32, padding=1),
nn.Conv2d(32, 64, 1),
nn.BatchNorm2d(64),
nn.ReLU6(inplace=True),
nn.MaxPool2d(2),

# Stage 4: 12×12 → 6×6
nn.Conv2d(64, 64, 3, groups=64, padding=1),
nn.Conv2d(64, 96, 1),
nn.BatchNorm2d(96),
nn.ReLU6(inplace=True),
nn.MaxPool2d(2),
)

# 关键点回归头
self.head = nn.Sequential(
nn.ConvTranspose2d(96, 64, 4, stride=2, padding=1), # 6→12
nn.ReLU6(inplace=True),
nn.ConvTranspose2d(64, 32, 4, stride=2, padding=1), # 12→24
nn.ReLU6(inplace=True),
nn.ConvTranspose2d(32, n_keypoints, 4, stride=2, padding=1), # 24→48
)

def forward(self, x):
features = self.backbone(x)
heatmaps = self.head(features)
return heatmaps

def predict_keypoints(self, thermal_image):
"""
从热成像图预测关键点

Args:
thermal_image: shape=(1, 1, 96, 96), 归一化温度图

Returns:
keypoints: shape=(13, 2), 各关键点(x,y)坐标
confidences: shape=(13,), 各关键点置信度
"""
with torch.no_grad():
heatmaps = self.forward(thermal_image)

keypoints = np.zeros((self.n_keypoints, 2))
confidences = np.zeros(self.n_keypoints)

for k in range(self.n_keypoints):
hm = heatmaps[0, k].cpu().numpy()
# argmax找关键点
idx = np.unravel_index(np.argmax(hm), hm.shape)
confidences[k] = hm[idx]
# 映射回原图坐标
scale_x = 96 / hm.shape[1]
scale_y = 96 / hm.shape[0]
keypoints[k] = [idx[1] * scale_x, idx[0] * scale_y]

return keypoints, confidences


# 量化部署
class QuantizedThermalPose:
"""量化后的热成像姿态估计模型"""

def __init__(self):
self.model = ThermalPoseEstimator()
self.model_size_fp32 = sum(p.numel() * 4 for p in self.model.parameters()) / 1e6
# 约 0.5MB (FP32)

def quantize_int8(self):
"""INT8量化"""
# 动态量化
quantized = torch.quantization.quantize_dynamic(
self.model,
{nn.Conv2d, nn.Linear},
dtype=torch.qint8
)
self.model_size_int8 = sum(
p.element_size() * p.numel()
for p in quantized.parameters()
) / 1e6
return quantized

def benchmark_rpi5(self):
"""
Raspberry Pi 5 性能基准

预期结果(论文参考):
- FP32: ~150ms/frame, 6.7fps
- INT8: ~45ms/frame, 22fps
- INT8 + Edge TPU: ~15ms/frame, 67fps
"""
results = {
'fp32_cpu': {'latency_ms': 150, 'fps': 6.7, 'size_mb': 0.5},
'int8_cpu': {'latency_ms': 45, 'fps': 22, 'size_mb': 0.15},
'int8_edge_tpu': {'latency_ms': 15, 'fps': 67, 'size_mb': 0.15},
}
return results

4. OOP检测应用

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
"""
基于热成像姿态估计的OOP检测

座舱OOP场景:
1. 后仰(Recline > 45°)
2. 侧倾(Leaning)
3. 前倾(Forward lean)
4. 非标准坐姿(Unconventional)
5. 离座(Empty seat)
"""

class ThermalOOPDetector:
"""基于热成像的OOP检测器"""

def __init__(self):
self.pose_model = ThermalPoseEstimator()
self.oop_classifier = OOPClassifier()

def detect_oop(self, thermal_image):
"""
OOP检测流程

Args:
thermal_image: shape=(1, 1, 96, 96)

Returns:
oop_result: dict
"""
# Step 1: 姿态估计
keypoints, confidences = self.pose_model.predict_keypoints(thermal_image)

# Step 2: 特征提取
features = self._extract_posture_features(keypoints, confidences)

# Step 3: OOP分类
oop_state = self.oop_classifier.predict(features)

return {
'oop_state': oop_state,
'keypoints': keypoints,
'confidences': confidences,
'features': features
}

def _extract_posture_features(self, kp, conf):
"""从关键点提取姿态特征"""
features = {}

# 1. 躯干角度(肩膀-髋部连线与垂直方向的夹角)
if conf[1] > 0.3 and conf[8] > 0.3 and conf[9] > 0.3:
shoulder_mid = (kp[1] + kp[2]) / 2
hip_mid = (kp[8] + kp[9]) / 2
trunk_angle = np.arctan2(
shoulder_mid[0] - hip_mid[0],
shoulder_mid[1] - hip_mid[1]
) * 180 / np.pi
features['trunk_angle'] = trunk_angle

# 2. 头部偏移(面部中心相对于躯干中心)
if conf[12] > 0.3 and conf[7] > 0.3:
head_offset_x = kp[12][0] - kp[7][0]
head_offset_y = kp[12][1] - kp[7][1]
features['head_offset_x'] = head_offset_x
features['head_offset_y'] = head_offset_y

# 3. 占座检测(整体热辐射量)
features['thermal_intensity'] = np.mean(conf)

# 4. 对称性(左右关键点镜像)
left_side = kp[[1, 3, 5, 8, 10]]
right_side = kp[[2, 4, 6, 9, 11]]
features['asymmetry'] = np.mean(np.abs(left_side - right_side[:, [::-1]]))

return features


class OOPClassifier:
"""OOP状态分类器"""

def predict(self, features):
"""基于规则的OOP分类"""
trunk_angle = features.get('trunk_angle', 0)
head_offset_x = features.get('head_offset_x', 0)
asymmetry = features.get('asymmetry', 0)
intensity = features.get('thermal_intensity', 0)

# 离座检测
if intensity < 0.1:
return 'empty_seat'

# 后仰
if trunk_angle > 35:
return 'reclined'

# 前倾
if trunk_angle < -15:
return 'forward_lean'

# 侧倾
if abs(head_offset_x) > 15:
return 'leaning'

# 非标准坐姿
if asymmetry > 20:
return 'unconventional'

return 'normal'

5. RGB-Thermal融合方案

融合系统代码

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
class RGBThermalFusionDMS:
"""RGB+热成像融合DMS系统"""

def __init__(self):
self.rgb_module = RGBDMSModule() # 可见光DMS
self.thermal_module = ThermalOOPDetector() # 热成像OOP

def process(self, rgb_frame, thermal_frame):
"""融合处理"""
# RGB分支
rgb_result = self.rgb_module.process(rgb_frame)
# 输出: {perclos, gaze_x, gaze_y, blink_rate, head_pose}

# Thermal分支
thermal_result = self.thermal_module.detect_oop(thermal_frame)
# 输出: {oop_state, keypoints, thermal_intensity}

# 融合决策
risk_level = self._fuse(rgb_result, thermal_result)

return {
'dms_state': rgb_result,
'oop_state': thermal_result,
'risk_level': risk_level,
}

def _fuse(self, rgb, thermal):
"""融合决策"""
fatigue = rgb.get('perclos', 0) > 0.3
distracted = abs(rgb.get('gaze_x', 0)) > 15
oop = thermal.get('oop_state', 'normal') != 'normal'
empty = thermal.get('oop_state') == 'empty_seat'

if empty:
return 0 # 离座,不评估
if fatigue and oop:
return 3 # 最高风险
if fatigue or oop:
return 2 if oop else 1
if distracted:
return 1
return 0

6. 对IMS的落地建议

6.1 部署方案

方案 传感器 算力 功能 成本 推荐度
纯热成像 InfiRay IR099 RP5级 姿态+OOP+占座 ~$120 ⭐⭐⭐
纯RGB OV2311 QCS8550 眼动+PERCLOS+姿态 ~$15 ⭐⭐⭐⭐
RGB+Thermal融合 OV2311+IR099 QCS8550 全功能 ~$135 ⭐⭐⭐⭐⭐

6.2 落地优先级

优先级 任务 时间 预算
🔴 P0 采购InfiRay IR099评估热成像质量 2026 Q4 ~$150
🔴 P0 热成像姿态估计原型验证 2026 Q4 内部
🟡 P1 RGB-Thermal融合DMS原型 2027 Q1 内部
🟡 P1 暗光场景对比测试 2027 Q1 内部
🟢 P2 量产方案设计 2027 Q2 ~$5K

6.3 对Euro NCAP的映射

NCAP要求 热成像方案覆盖 优势
OOP检测 ✅ 姿态估计 暗光/遮挡鲁棒
占座检测 ✅ 热辐射检测 无隐私问题
隐私保护 ✅ 无面部细节 天生隐私保护
暗光性能 ✅ 不依赖环境光 夜间完美
疲劳检测 ❌ 需要RGB 热成像精度不足
分心检测 ❌ 需要RGB 眼动分辨率不足

总结

热成像姿态估计在座舱中的核心价值是补齐可见光DMS的两个短板:暗光和隐私。

  1. 互补而非替代:热成像做姿态/OOP/占座,RGB做眼动/疲劳/分心
  2. Raspberry Pi 5级算力足够:INT8量化后22fps,Edge TPU后67fps
  3. 成本可控:InfiRay IR099约$120,加上RGB总成本约$135
  4. Euro NCAP OOP要求:热成像姿态估计是暗光场景下的最优解

优先级建议: 🟡 P1——在RGB DMS稳定运行后,增加热成像传感器作为暗光/OOP增强。如果预算有限,优先确保RGB+IR方案在暗光下通过补光解决,热成像作为Phase 2增强。