非接触心理压力检测AI模型Meta分析:rPPG/热成像/雷达三模态 pooled准确率81.3%

论文信息

  • 标题: Performance of artificial intelligence models for monitoring psychological stress using noncontact physiological signals: a systematic review and meta-analysis
  • 来源: Frontiers in Psychiatry, 2026
  • DOI: 10.3389/fpsyt.2026.1938767
  • 检索时间: 2026年5月6日(PubMed/IEEE/WoS/Embase/PsycINFO)
  • 纳入研究: 21篇,meta分析8篇(17个模型级估计, 13,910样本)
  • 链接: https://www.frontiersin.org/journals/psychiatry/articles/10.3389/fpsyt.2026.1938767/full

核心发现

指标 Pooled值 95% CI
准确率 81.3% 68.4%-91.5%
F1-score 0.791 -
敏感度 0.809 -
特异度 0.697 -

三种非接触感知模态的分布:

  • rPPG/iPPG(摄像头提取心率)→ 最常见
  • 热成像(面部温度分布)→ 自主神经活动代理
  • 无线雷达(呼吸/微动)→ 非视觉隐私保护

对IMS的核心价值

这篇meta分析是非接触压力检测走向实用的里程碑证据。对IMS意味着:

  1. DMS摄像头可直接做压力检测:rPPG从面部视频提取心率/HRV,无需额外传感器
  2. 81.3%准确率已达可用门槛:但特异度仅69.7%——误报率偏高
  3. 驾驶场景已有验证:21篇研究中包含驾驶环境相关压力检测
  4. 关键局限:绝大多数在实验室环境,真实场景验证不足

三种非接触模态详解

模态对比

维度 rPPG 热成像 无线雷达
传感器 摄像头(已有DMS) 红外热像仪 mmWave/UWB
额外硬件 ❌ 无 ✅ 需要 ✅ 需要
隐私 ⚠️ 面部视频 ✅ 无面部细节 ✅ 完全非视觉
暗光性能 ❌ 需要光照 ✅ 不需要 ✅ 不需要
心率精度 ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐
呼吸精度 ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
成本增量 $0(复用DMS) ~$120 ~$30(已有CPD雷达)
IMS推荐度 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐

rPPG压力检测实现

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
"""
基于rPPG的非接触压力检测框架

复现meta分析中的主流rPPG方法
"""
import numpy as np
import torch
import torch.nn as nn

class rPPGStressDetector(nn.Module):
"""
rPPG压力检测模型

流程:
1. 面部检测+ROI提取(额头/双颊)
2. 像素平均→时间序列(原始rPPG信号)
3. 滤波→心率/HRV特征
4. 时序模型→压力分类
"""

def __init__(self, fps=30, window_sec=60):
super().__init__()
self.fps = fps
self.window = int(window_sec * fps)

# 信号处理参数
self.hr_band = (0.7, 3.5) # 42-210 bpm

# 时序模型
self.lstm = nn.LSTM(input_size=32, hidden_size=64,
num_layers=2, batch_first=True)
self.classifier = nn.Sequential(
nn.Linear(64, 32),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(32, 2), # binary: stressed/not
)

def extract_rppg_signal(self, video_frames, facial_rois):
"""
从视频帧提取rPPG信号

方法:POS (Plane Orthogonal to Skin)

Args:
video_frames: shape=(T, H, W, 3), RGB视频帧
facial_rois: list of (x,y,w,h), 面部ROI区域

Returns:
rppg_signal: shape=(T,), 原始rPPG信号
"""
T = len(video_frames)
rppg = np.zeros(T)

for t in range(T):
frame = video_frames[t]
roi = facial_rois[t]
x, y, w, h = roi

# 提取ROI区域
patch = frame[y:y+h, x:x+w, :]

# 空间平均
r_mean = np.mean(patch[:,:,0])
g_mean = np.mean(patch[:,:,1])
b_mean = np.mean(patch[:,:,2])

# POS投影
# C = [3x1] 颜色均值
# 投影到与皮肤色调正交的平面
s = np.array([3*r_mean - 2*g_mean,
-1.5*r_mean + g_mean + 1.5*b_mean])
rppg[t] = s[0] # 取第一分量

# 去趋势+带通滤波
from scipy.signal import detrend, butter, filtfilt
rppg = detrend(rppg)
nyq = self.fps / 2
b, a = butter(3, [self.hr_band[0]/nyq, self.hr_band[1]/nyq],
btype='band')
rppg = filtfilt(b, a, rppg)

return rppg

def extract_hrv_features(self, rppg_signal):
"""提取HRV特征"""
# 峰值检测(心跳)
from scipy.signal import find_peaks
peaks, _ = find_peaks(rppg_signal, distance=self.fps*0.4)

if len(peaks) < 10:
return np.zeros(32) # 不足

# RR间隔
rr_intervals = np.diff(peaks) / self.fps * 1000 # ms

features = np.zeros(32)
# 时域特征
features[0] = np.mean(rr_intervals) # mean RR
features[1] = np.std(rr_intervals) # SDNN
features[2] = np.sqrt(np.mean(np.diff(rr_intervals)**2)) # RMSSD
features[3] = len(peaks) / (len(rppg_signal)/self.fps) * 60 # HR

# 频域特征
from scipy.signal import periodogram
f, pxx = periodogram(rr_intervals, fs=1.0/np.mean(rr_intervals)*1000)
vlf = np.sum(pxx[(f<0.04)]) # VLF
lf = np.sum(pxx[(f>=0.04)&(f<0.15)]) # LF
hf = np.sum(pxx[(f>=0.15)&(f<0.4)]) # HF
features[4] = lf
features[5] = hf
features[6] = lf/hf if hf > 0 else 0 # LF/HF ratio

return features

def forward(self, rppg_signal):
"""压力分类"""
# 提取特征序列(滑动窗口)
features = self.extract_hrv_features(rppg_signal)

# LSTM分类
x = torch.tensor(features, dtype=torch.float32).unsqueeze(0).unsqueeze(0)
out, _ = self.lstm(x)
out = self.classifier(out[:, -1, :])
return torch.softmax(out, dim=1)

关键局限与IMS落地改进

论文指出的问题

局限 对IMS的影响 改进方向
小样本 21篇研究,多数<50人 需大规模驾驶数据集
实验室为主 压力诱导不等于真实驾驶压力 自然驾驶数据采集
标签异质 压力标签来源不一(问卷/生理/任务) 标准化驾驶压力标签
缺乏被试独立验证 多数研究被试间不独立 留一被试交叉验证
特异度低 69.7% → 误报率~30% 多模态融合提升
真实场景不足 无驾驶环境长期验证 需实车验证

IMS多模态融合改进方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"""
IMS非接触压力检测融合方案

rPPG + 热成像 + 驾驶行为 三模态融合
预期:准确率>88%, 特异度>85%
"""
class MultiModalStressDetector:
def __init__(self):
self.rppg_model = rPPGStressDetector()
self.thermal_model = ThermalStressModel()
self.driving_model = DrivingBehaviorStressModel()

def predict(self, video, thermal, can_signals):
"""三模态融合"""
rppg_prob = self.rppg_model(video)
thermal_prob = self.thermal_model(thermal)
driving_prob = self.driving_model(can_signals)

# 加权融合
weights = [0.5, 0.3, 0.2] # rPPG最可靠
fused = (weights[0]*rppg_prob + weights[1]*thermal_prob
+ weights[2]*driving_prob)
return fused

Euro NCAP和驾驶员压力检测的关系

Euro NCAP 2026不直接评分”压力检测”,但压力检测间接影响:

NCAP要求 压力检测的间接价值
疲劳检测 压力→疲劳加速→PERCLOS恶化
认知分心 压力→注意力收窄→认知脱离
酒驾损伤 压力+酒精→损伤加重
驾驶员干预 压力过高→安全停车建议

总结

这篇meta分析确认了非接触压力检测的技术可行性(81.3% pooled准确率),但暴露了真实场景验证不足的短板。对IMS:

  1. rPPG是首选方案:复用DMS摄像头,零额外硬件
  2. 多模态融合必要:单模态特异度太低(69.7%),需融合热成像/驾驶行为
  3. 驾驶场景需要实车验证:实验室压力≠驾驶压力
  4. 标签标准化是下一步:建立驾驶压力的客观标签体系

优先级: 🟡 P2——在疲劳/分心/OOP检测稳定后,rPPG压力检测作为增强功能引入,提升IMS整体驾驶员状态评估维度。