Every pulse pushes blood into your face and shifts its color too faintly to see — but not too faintly to measure. PulseCam recovers your heart rate from an ordinary camera. No contact, no wearable. Runs locally on a laptop.
The same signal-processing chain used to clean up a physical PPG sensor — only the input is a camera array instead of a photodiode.
Detect the face each frame and lock a region of interest onto the forehead so we sample skin, not background.
Collapse the forehead to one number per frame — the mean green channel, where the blood-volume signal is strongest.
Detrend out lighting drift, then a Butterworth bandpass keeps only 0.75–3.5 Hz — the 45–210 BPM heart-rate band.
An FFT reports the dominant frequency of the cleaned wave. Multiply by 60 — that's your beats per minute.
A classical DSP baseline you can fully explain, and a PhysNet 3D-CNN trained on real data — run live, side by side, so the AI has to prove itself against a trusted number.
| Property | DSP baseline | PhysNet (AI) |
|---|---|---|
| Method | Bandpass + FFT | 3D-CNN → pulse waveform |
| Still & well-lit | Excellent | Excellent |
| Motion / talking | Breaks down | Robust |
| Uneven lighting | Noisy | Robust |
| Needs training data | No | Yes — UBFC-rPPG |
| Fully explainable | Yes | Black box |
Everything runs locally — your camera feed never leaves your laptop.
# 1. setup
git clone https://github.com/bshihab/rppg-poc
cd rppg-poc
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
# 2. DSP baseline — works immediately, no training
.venv/bin/python heart_rate.py
# 3. AI: download UBFC-rPPG into data/UBFC-rPPG, then train
.venv/bin/python -m rppg.train --data data/UBFC-rPPG
# 4. live AI vs DSP, side by side
.venv/bin/python -m rppg.live_ai