Upload 5 files
Browse files- Dockerfile +23 -0
- LICENSE +33 -0
- README.md +248 -12
- dockerignore +12 -0
- requirements.txt +11 -0
Dockerfile
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.10-slim
|
| 2 |
+
|
| 3 |
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
| 4 |
+
PYTHONUNBUFFERED=1 \
|
| 5 |
+
PIP_NO_CACHE_DIR=1
|
| 6 |
+
|
| 7 |
+
WORKDIR /app
|
| 8 |
+
|
| 9 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 10 |
+
ffmpeg \
|
| 11 |
+
libgl1 \
|
| 12 |
+
libglib2.0-0 \
|
| 13 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 14 |
+
|
| 15 |
+
COPY requirements.txt /app/requirements.txt
|
| 16 |
+
RUN python -m pip install --upgrade pip && \
|
| 17 |
+
python -m pip install -r /app/requirements.txt
|
| 18 |
+
|
| 19 |
+
COPY . /app
|
| 20 |
+
|
| 21 |
+
EXPOSE 7860
|
| 22 |
+
|
| 23 |
+
CMD ["sh", "-c", "python web_demo/app.py --host 0.0.0.0 --port ${PORT:-7860}"]
|
LICENSE
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) [2025]
|
| 4 |
+
|
| 5 |
+
## Licensing Notice
|
| 6 |
+
|
| 7 |
+
This repository includes source code and tools released under the [MIT License](LICENSE).
|
| 8 |
+
|
| 9 |
+
However, **pretrained models and model configurations** provided in this repository
|
| 10 |
+
are the intellectual property of their respective authors and are licensed under the
|
| 11 |
+
terms specified by the **original papers**. Please refer to the respective publications
|
| 12 |
+
and their repositories for license details before using these models in your work.
|
| 13 |
+
We do **not** claim ownership or rights to redistribute third-party models unless explicitly
|
| 14 |
+
stated.
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 18 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 19 |
+
in the Software without restriction, including without limitation the rights
|
| 20 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 21 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 22 |
+
furnished to do so, subject to the following conditions:
|
| 23 |
+
|
| 24 |
+
The above copyright notice and this permission notice shall be included in
|
| 25 |
+
all copies or substantial portions of the Software.
|
| 26 |
+
|
| 27 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 28 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 29 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 30 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 31 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 32 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
| 33 |
+
THE SOFTWARE.
|
README.md
CHANGED
|
@@ -1,12 +1,248 @@
|
|
| 1 |
-
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open-rppg
|
| 2 |
+
|
| 3 |
+
Open-rppg is a comprehensive Python toolbox designed for Remote Photoplethysmography (rPPG) inference. It provides a unified interface for state-of-the-art deep learning models, enabling physiological signal measurement (such as heart rate and heart rate variability) from facial videos. The toolkit supports both offline video processing and low-latency real-time inference using JAX.
|
| 4 |
+
|
| 5 |
+
> API document [https://kegangwangccnu.github.io/open-rppg/](https://kegangwangccnu.github.io/open-rppg/)
|
| 6 |
+
|
| 7 |
+
<img width="948" height="250" alt="image" src="https://github.com/user-attachments/assets/5c945368-67bf-4ccb-8822-fa359a787cdd" />
|
| 8 |
+
|
| 9 |
+
## Installation
|
| 10 |
+
|
| 11 |
+
This package requires Python 3.9 through 3.13.
|
| 12 |
+
|
| 13 |
+
To install the standard version:
|
| 14 |
+
|
| 15 |
+
```bash
|
| 16 |
+
pip install open-rppg
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
To enable GPU acceleration (Linux/CUDA), install the CUDA-supported version of JAX:
|
| 20 |
+
|
| 21 |
+
```bash
|
| 22 |
+
pip install jax[cuda]
|
| 23 |
+
```
|
| 24 |
+
|
| 25 |
+
## Quick Start
|
| 26 |
+
|
| 27 |
+
The core interface is managed through the `Model` class. By default, it initializes a robust, general-purpose model (`FacePhys.rlap`).
|
| 28 |
+
|
| 29 |
+
```python
|
| 30 |
+
import rppg
|
| 31 |
+
|
| 32 |
+
# Initialize the model
|
| 33 |
+
model = rppg.Model()
|
| 34 |
+
|
| 35 |
+
# Process a video file
|
| 36 |
+
results = model.process_video("path/to/video.mkv")
|
| 37 |
+
|
| 38 |
+
# Display the heart rate
|
| 39 |
+
print(f"Estimated Heart Rate: {results['hr']} BPM")
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## Usage Guide
|
| 43 |
+
|
| 44 |
+
### 1. Offline Video Processing
|
| 45 |
+
To analyze a pre-recorded video file, use the `process_video` method. This method handles frame extraction, face detection, and signal inference automatically.
|
| 46 |
+
|
| 47 |
+
```python
|
| 48 |
+
results = model.process_video("subject_test.mkv")
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
**Output Structure:**
|
| 52 |
+
The returned dictionary contains the following keys:
|
| 53 |
+
|
| 54 |
+
* **hr**: Heart Rate estimated via the frequency domain (FFT).
|
| 55 |
+
* **SQI**: Signal Quality Index (0.0 to 1.0), indicating the reliability of the measurement.
|
| 56 |
+
* **latency**: Inference latency (primarily relevant for real-time streams).
|
| 57 |
+
* **hrv**: A dictionary of Heart Rate Variability metrics calculated in the time domain:
|
| 58 |
+
* *bpm*: Heart rate derived from peak detection.
|
| 59 |
+
* *ibi*: Inter-Beat Interval (milliseconds).
|
| 60 |
+
* *sdnn*: Standard deviation of NN intervals.
|
| 61 |
+
* *rmssd*: Root mean square of successive differences.
|
| 62 |
+
* *pnn50*: Proportion of NN50 > 50ms.
|
| 63 |
+
* *LF/HF*: Ratio of Low Frequency to High Frequency power.
|
| 64 |
+
* *breathingrate*: Estimated respiration rate.
|
| 65 |
+
|
| 66 |
+
### 2. Real-Time Inference
|
| 67 |
+
Open-rppg includes a threaded pipeline optimized for real-time webcam inference. Use the `video_capture` context manager to handle the video stream safely.
|
| 68 |
+
|
| 69 |
+
```python
|
| 70 |
+
import rppg
|
| 71 |
+
import time
|
| 72 |
+
import cv2
|
| 73 |
+
|
| 74 |
+
model = rppg.Model()
|
| 75 |
+
# Open the default camera (index 0)
|
| 76 |
+
with model.video_capture(0):
|
| 77 |
+
last_process_time = 0
|
| 78 |
+
current_hr = None
|
| 79 |
+
|
| 80 |
+
# Iterate through the preview generator (this is the main loop)
|
| 81 |
+
for frame, box in model.preview:
|
| 82 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
|
| 83 |
+
|
| 84 |
+
# 1. Calculate HR every 1 second to avoid lag
|
| 85 |
+
now = time.time()
|
| 86 |
+
if now - last_process_time > 1.0:
|
| 87 |
+
result = model.hr(start=-10)
|
| 88 |
+
if result and result['hr']:
|
| 89 |
+
current_hr = result['hr']
|
| 90 |
+
print(f"Real-time HR: {current_hr:.1f} BPM")
|
| 91 |
+
last_process_time = now
|
| 92 |
+
|
| 93 |
+
# 2. Visualization
|
| 94 |
+
if box is not None:
|
| 95 |
+
# box format: [[row_min, row_max], [col_min, col_max]]
|
| 96 |
+
y1, y2 = box[0]
|
| 97 |
+
x1, x2 = box[1]
|
| 98 |
+
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
| 99 |
+
|
| 100 |
+
# Display HR on the frame if available
|
| 101 |
+
if current_hr is not None:
|
| 102 |
+
cv2.putText(frame, f"HR: {current_hr:.1f}", (x1, y1 - 10),
|
| 103 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
|
| 104 |
+
|
| 105 |
+
cv2.imshow("rPPG Monitor", frame)
|
| 106 |
+
|
| 107 |
+
if cv2.waitKey(1) & 0xFF == ord('q'):
|
| 108 |
+
break
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
## Advanced API
|
| 112 |
+
|
| 113 |
+
### Retrieving Raw Signals
|
| 114 |
+
You can extract the underlying Blood Volume Pulse (BVP) waveform for further analysis or plotting.
|
| 115 |
+
|
| 116 |
+
```python
|
| 117 |
+
# Retrieve the full BVP signal and corresponding timestamps
|
| 118 |
+
bvp, timestamps = model.bvp()
|
| 119 |
+
|
| 120 |
+
# Retrieve the raw, unfiltered BVP signal
|
| 121 |
+
raw_bvp, timestamps = model.bvp(raw=True)
|
| 122 |
+
```
|
| 123 |
+
|
| 124 |
+
### Time Slicing
|
| 125 |
+
The toolbox allows specific time windows to be analyzed within the buffer.
|
| 126 |
+
|
| 127 |
+
```python
|
| 128 |
+
# Get signal from t=10s to t=20s
|
| 129 |
+
bvp_slice, ts_slice = model.bvp(start=10, end=20)
|
| 130 |
+
|
| 131 |
+
# Get metrics for the last 15 seconds
|
| 132 |
+
metrics = model.hr(start=-15)
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
### Tensor Inputs
|
| 136 |
+
For integration into existing pipelines where frames are already loaded as memory arrays, use the tensor processing methods.
|
| 137 |
+
|
| 138 |
+
* **Input Format:** `uint8` array with shape `(Frames, Height, Width, 3)`.
|
| 139 |
+
|
| 140 |
+
```python
|
| 141 |
+
import numpy as np
|
| 142 |
+
|
| 143 |
+
# tensor shape: (T, H, W, 3)
|
| 144 |
+
video_tensor = np.zeros((300, 480, 640, 3), dtype='uint8') # 480p video
|
| 145 |
+
|
| 146 |
+
result = model.process_video_tensor(video_tensor, fps=30.0)
|
| 147 |
+
|
| 148 |
+
faces_tensor = np.zeros((300, 128, 128, 3), dtype='uint8') # face array
|
| 149 |
+
|
| 150 |
+
result = model.process_faces_tensor(faces_tensor, fps=30.0)
|
| 151 |
+
|
| 152 |
+
```
|
| 153 |
+
|
| 154 |
+
### Model Selection
|
| 155 |
+
You can specify different architectures during initialization. The models are categorized by architecture and training configuration (`rlap` or `pure`).
|
| 156 |
+
|
| 157 |
+
```python
|
| 158 |
+
# Example: Initialize the PhysMamba model
|
| 159 |
+
model = rppg.Model('PhysMamba.pure')
|
| 160 |
+
```
|
| 161 |
+
|
| 162 |
+
## Model Zoo
|
| 163 |
+
|
| 164 |
+
The following architectures are supported.
|
| 165 |
+
|
| 166 |
+
| Model Name | Description | Reference |
|
| 167 |
+
| :--- | :--- | :--- |
|
| 168 |
+
| **ME-chunk** | State-space model rPPG (chunk inference) | arXiv 2025 |
|
| 169 |
+
| **ME-flow** | State-space model rPPG (low-latency flow) | arXiv 2025 |
|
| 170 |
+
| **PhysMamba** | Dual-branch Mamba architecture | CCBR 2024 |
|
| 171 |
+
| **RhythmMamba**| Frequency-domain constrained Mamba | AAAI 2025 |
|
| 172 |
+
| **PhysFormer** | Temporal Difference Transformer | CVPR 2022 |
|
| 173 |
+
| **TSCAN** | Temporal Shift Convolutional Attention Network | NeurIPS 2020 |
|
| 174 |
+
| **EfficientPhys**| Self-attention variant of TSCAN | WACV 2023 |
|
| 175 |
+
| **PhysNet** | 3D Convolutional Encoder-Decoder | BMVC 2019 |
|
| 176 |
+
| **FacePhys** | Optimized state-space model | - |
|
| 177 |
+
|
| 178 |
+
*Note: Suffixes `.rlap` and `.pure` indicate different training protocols/weights.*
|
| 179 |
+
|
| 180 |
+
## Licensing
|
| 181 |
+
|
| 182 |
+
The source code and tools in this repository are released under the **MIT License**.
|
| 183 |
+
|
| 184 |
+
**Important:** Pretrained models and model configurations provided in this repository are derived from academic research. They are the intellectual property of their respective authors and are subject to the license terms specified in their original publications. Please refer to the citations below for details.
|
| 185 |
+
|
| 186 |
+
## Citation
|
| 187 |
+
|
| 188 |
+
If you use this toolkit or the included models in your research, please cite the relevant papers:
|
| 189 |
+
|
| 190 |
+
```bibtex
|
| 191 |
+
@article{yu2019remote,
|
| 192 |
+
title={Remote photoplethysmograph signal measurement from facial videos using spatio-temporal networks},
|
| 193 |
+
author={Yu, Zitong and Li, Xiaobai and Zhao, Guoying},
|
| 194 |
+
journal={arXiv preprint arXiv:1905.02419},
|
| 195 |
+
year={2019}
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
@article{liu2020multi,
|
| 199 |
+
title={Multi-task temporal shift attention networks for on-device contactless vitals measurement},
|
| 200 |
+
author={Liu, Xin and Fromm, Josh and Patel, Shwetak and McDuff, Daniel},
|
| 201 |
+
journal={Advances in Neural Information Processing Systems},
|
| 202 |
+
volume={33},
|
| 203 |
+
pages={19400--19411},
|
| 204 |
+
year={2020}
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
@inproceedings{liu2023efficientphys,
|
| 208 |
+
title={Efficientphys: Enabling simple, fast and accurate camera-based cardiac measurement},
|
| 209 |
+
author={Liu, Xin and Hill, Brian and Jiang, Ziheng and Patel, Shwetak and McDuff, Daniel},
|
| 210 |
+
booktitle={Proceedings of the IEEE/CVF winter conference on applications of computer vision},
|
| 211 |
+
pages={5008--5017},
|
| 212 |
+
year={2023}
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
@inproceedings{yu2022physformer,
|
| 216 |
+
title={Physformer: Facial video-based physiological measurement with temporal difference transformer},
|
| 217 |
+
author={Yu, Zitong and Shen, Yuming and Shi, Jingang and Zhao, Hengshuang and Torr, Philip HS and Zhao, Guoying},
|
| 218 |
+
booktitle={Proceedings of the IEEE/CVF conference on computer vision and pattern recognition},
|
| 219 |
+
pages={4186--4196},
|
| 220 |
+
year={2022}
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
@inproceedings{luo2024physmamba,
|
| 224 |
+
title={PhysMamba: Efficient Remote Physiological Measurement with SlowFast Temporal Difference Mamba},
|
| 225 |
+
author={Luo, Chaoqi and Xie, Yiping and Yu, Zitong},
|
| 226 |
+
booktitle={Chinese Conference on Biometric Recognition},
|
| 227 |
+
pages={248--259},
|
| 228 |
+
year={2024},
|
| 229 |
+
organization={Springer}
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
@inproceedings{zou2025rhythmmamba,
|
| 233 |
+
title={RhythmMamba: Fast, Lightweight, and Accurate Remote Physiological Measurement},
|
| 234 |
+
author={Zou, Bochao and Guo, Zizheng and Hu, Xiaocheng and Ma, Huimin},
|
| 235 |
+
booktitle={Proceedings of the AAAI Conference on Artificial Intelligence},
|
| 236 |
+
volume={39},
|
| 237 |
+
number={10},
|
| 238 |
+
pages={11077--11085},
|
| 239 |
+
year={2025}
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
@article{wang2025memory,
|
| 243 |
+
title={Memory-efficient Low-latency Remote Photoplethysmography through Temporal-Spatial State Space Duality},
|
| 244 |
+
author={Wang, Kegang and Tang, Jiankai and Fan, Yuxuan and Ji, Jiatong and Shi, Yuanchun and Wang, Yuntao},
|
| 245 |
+
journal={arXiv preprint arXiv:2504.01774},
|
| 246 |
+
year={2025}
|
| 247 |
+
}
|
| 248 |
+
```
|
dockerignore
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.git
|
| 2 |
+
.github
|
| 3 |
+
__pycache__
|
| 4 |
+
*.pyc
|
| 5 |
+
*.pyo
|
| 6 |
+
*.pyd
|
| 7 |
+
.DS_Store
|
| 8 |
+
.pytest_cache
|
| 9 |
+
.mypy_cache
|
| 10 |
+
.venv
|
| 11 |
+
venv
|
| 12 |
+
node_modules
|
requirements.txt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flask>=3.0
|
| 2 |
+
numpy>=1.24
|
| 3 |
+
heartpy>=1.2
|
| 4 |
+
jax>=0.4.26
|
| 5 |
+
keras>=3.5.0
|
| 6 |
+
onnxruntime>=1.8
|
| 7 |
+
opencv_python>=4.5.5.64
|
| 8 |
+
scipy>=1.8
|
| 9 |
+
einops>=0.8
|
| 10 |
+
av>=13
|
| 11 |
+
#matplotlib<=3.9
|