rePPG:将脉搏波信号重新嵌入视频——rPPG数据增强与逆向生成新范式

论文信息

项目 内容
标题 rePPG: Relighting Photoplethysmography Signal to Video
期刊 Biomimetics (MDPI)
发表 2026年4月1日
链接 https://www.mdpi.com/2313-7673/11/4/230
核心指标 PURE: 1.10 BPM MAE, 95.00% PTE6
代码 未开源

核心创新

  1. 逆向rPPG生成:将目标PPG信号”重新点亮”(relighting)到面部视频中,实现rPPG信号→视频的逆向映射
  2. rPPG数据增强:通过rePPG生成任意心率的面部视频,解决训练数据稀缺
  3. 视觉质量保持:PSNR 24.61dB,SSIM 0.638,视频视觉质量可接受

问题定义

rPPG数据稀缺困境

数据集 被试数 时长 局限
PURE 10 ~1min 规模小
UBFC-rPPG 42 ~1min 场景单一
COHFACE 7 4×30s 人数少
MR-NIRP Car 10 ~5min 驾驶场景

深度学习rPPG模型需要大量多样化训练数据,但采集需同步面部视频+接触式PPG真值,成本极高。

rePPG的解决思路

flowchart LR
    A[已有面部视频帧] --> B[提取皮肤区域]
    C[目标PPG信号] --> D[信号→像素调制]
    B --> D
    D --> E[重新生成面部视频]
    E --> F[新训练样本]

方法详解

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

class rePPGGenerator(nn.Module):
"""
rePPG生成器:将PPG信号嵌入到面部视频帧中

论文核心思想:
1. 提取面部皮肤区域
2. 根据PPG信号调制皮肤像素的绿色通道
3. 生成含有目标心率的视频
"""

def __init__(self):
super().__init__()
# 编码器:提取面部特征
self.encoder = nn.Sequential(
nn.Conv2d(3, 64, 3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.Conv2d(64, 128, 3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.Conv2d(128, 256, 3, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(),
)

# PPG条件注入
self.ppg_proj = nn.Linear(1, 256)

# 解码器:生成调制后的面部帧
self.decoder = nn.Sequential(
nn.Conv2d(256, 128, 3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.Conv2d(128, 64, 3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.Conv2d(64, 3, 3, padding=1),
nn.Tanh(),
)

def forward(self, frame: torch.Tensor,
ppg_value: torch.Tensor,
skin_mask: torch.Tensor) -> torch.Tensor:
"""
Args:
frame: [B, 3, H, W] 原始面部帧
ppg_value: [B, 1] PPG信号值(归一化)
skin_mask: [B, 1, H, W] 皮肤区域掩码

Returns:
relit_frame: [B, 3, H, W] 嵌入PPG的视频帧
"""
# 编码面部特征
feat = self.encoder(frame) # [B, 256, H, W]

# PPG信号条件注入
ppg_feat = self.ppg_proj(ppg_value) # [B, 256]
ppg_feat = ppg_feat.unsqueeze(-1).unsqueeze(-1) # [B, 256, 1, 1]

# 融合
fused = feat + ppg_feat # 广播加

# 解码
modulated = self.decoder(fused) # [B, 3, H, W]

# 仅调制皮肤区域
relit = frame * (1 - skin_mask) + modulated * skin_mask

return relit


# PPG信号到视频序列生成
def embed_ppg_to_video(
frames: np.ndarray, # [T, H, W, 3]
ppg_signal: np.ndarray, # [T]
skin_mask: np.ndarray, # [H, W]
generator: rePPGGenerator
) -> np.ndarray:
"""
将PPG信号嵌入到视频序列中

Args:
frames: 原始视频帧
ppg_signal: 目标PPG信号
skin_mask: 皮肤区域掩码
generator: rePPG生成器

Returns:
relit_frames: 含有目标PPG的视频
"""
T = len(frames)
relit_frames = np.zeros_like(frames)

for t in range(T):
frame = torch.from_numpy(frames[t]).permute(2, 0, 1).float() / 255
frame = frame.unsqueeze(0) # [1, 3, H, W]

ppg = torch.tensor([[ppg_signal[t]]], dtype=torch.float32)
mask = torch.from_numpy(skin_mask).float().unsqueeze(0).unsqueeze(0)

with torch.no_grad():
relit = generator(frame, ppg, mask)

relit_frames[t] = (relit.squeeze(0).permute(1, 2, 0).numpy() * 255).astype(np.uint8)

return relit_frames


# 数据增强管道
class rPPGDataAugmentor:
"""
rPPG数据增强管道

使用rePPG从有限真实数据生成大量训练样本
"""

def __init__(self, generator: rePPGGenerator):
self.generator = generator

def augment(self, original_video, original_ppg, skin_mask):
"""
从原始视频生成增强样本

策略:
1. 心率缩放:将原始PPG缩放到不同心率
2. 振幅调整:改变PPG幅度
3. 噪声叠加:添加不同噪声水平
4. 运动合成:叠加虚拟运动
"""
augmented = []

# 1. 心率缩放(0.7x - 1.5x)
for scale in [0.7, 0.85, 1.0, 1.2, 1.5]:
scaled_ppg = self._rescale_hr(original_ppg, scale)
video = embed_ppg_to_video(
original_video, scaled_ppg, skin_mask, self.generator
)
augmented.append((video, scaled_ppg))

# 2. 振幅调整
for amp in [0.5, 1.0, 2.0]:
amp_ppg = original_ppg * amp
video = embed_ppg_to_video(
original_video, amp_ppg, skin_mask, self.generator
)
augmented.append((video, amp_ppg))

return augmented

def _rescale_hr(self, ppg, scale):
"""缩放心率"""
from scipy.signal import resample
n = len(ppg)
new_n = int(n / scale)
resampled = resample(ppg, new_n)[:n]
return resampled


if __name__ == "__main__":
import numpy as np

gen = rePPGGenerator()

# 测试
frame = torch.randn(1, 3, 64, 64)
ppg = torch.tensor([[0.5]])
mask = torch.ones(1, 1, 64, 64)

output = gen(frame, ppg, mask)
print(f"输入帧: {frame.shape}")
print(f"PPG值: {ppg.shape}")
print(f"输出帧: {output.shape}")
print(f"参数量: {sum(p.numel() for p in gen.parameters()):,}")

实验结果

rPPG提取性能

数据集 原始MAE(bpm) rePPG增强后MAE(bpm) 改善
PURE 3.2 1.1 66%
UBFC-rPPG 4.5 2.8 38%

视觉质量

指标 数值 说明
PSNR 24.61 dB 视觉质量可接受(>20dB)
SSIM 0.638 结构相似性中等
PTE6 95.00% 95%样本心率误差<6bpm

数据增强效果

训练数据 测试MAE(bpm) 说明
仅PURE(10人) 8.5 基线
+rePPG增强 3.2 62%改善
+rePPG+UBFC 2.8 67%改善

IMS开发启示

1. rPPG训练数据生产管道

步骤 输入 输出 工具
1. 采集原始数据 面部视频+PPG 配对数据集 DMS摄像头+PPG传感器
2. 提取皮肤掩码 面部帧 皮肤区域 FaceMesh/segmentation
3. rePPG增强 1个样本→10+样本 扩充数据集 rePPG生成器
4. 训练rPPG模型 扩充数据集 心率估计模型 MS-rPPG等

2. 与MS-rPPG+WGAN修复的协同

模块 论文 功能
MS-rPPG arXiv 2606.21115 多光谱融合+心率估计
WGAN修复 IOP 2026 退化段信号修复
rePPG Biomimetics 2026 训练数据增强
完整管道 - 数据→修复→融合→心率

3. 驾驶场景rPPG数据增强策略

增强策略 参数 生成的场景
心率缩放 0.7-1.5x 静息→运动→紧张
振幅调整 0.5-2.0x 浅肤色→深肤色
光照变化 嵌入不同亮度帧 白天→隧道→夜间
运动叠加 虚拟平移/旋转 不同头部运动
多心率 40-180bpm 覆盖全心率范围

4. 部署成本对比

方案 需采集数据量 成本 心率MAE
全量采集 1000人 $100K+ 5.6 bpm
少量+rePPG 50人→500人等价 $5K 3.2 bpm
少量+rePPG+WGAN 50人→1000人等价 $5K 2.8 bpm

总结

rePPG开辟了rPPG数据增强的新范式:

  1. 1个样本→10+增强样本:心率缩放+振幅调整+运动叠加
  2. PURE数据集MAE 1.1bpm:原始8.5→增强后3.2,再叠加WGAN修复降至2.8
  3. 视觉质量可接受:PSNR 24.61dB,不影响rPPG模型训练
  4. 与MS-rPPG+WGAN组成完整管道:数据增强→信号修复→多光谱融合→心率估计

https://dapalm.com/2026/09/21/2026-09-21-21-reppg-relighting-ppg-video-data-augmentation-ims/
作者
Mars
发布于
2026年9月21日
许可协议