Inspiration
Your heart rate is one of the most useful numbers about your body, and you need a gadget to get it. I wanted to see how far a plain webcam could go. Every heartbeat pushes a little blood into your face, and your skin changes color very slightly. You can't see it, but a camera can. So I asked whether I could read a pulse from a face on a screen, with nothing to wear and nothing to install.
What it does PulseCam (pulsecam.site) is a web app. You press Start camera, sit still for about 15 seconds, and it shows your:
❤️ heart rate, in BPM 📈 heart-rate variability (RMSSD and SDNN) 🌬️ breathing rate
It also draws your pulse waveform live. A validation panel lets you type in a reading from a real pulse oximeter and see how far off PulseCam is.
Your video never leaves your device. Everything runs in your browser.
How I built it
Find the face. MediaPipe tracks the face and crops it to $72 \times 72$ pixels. Read the pulse. A pretrained neural network, EfficientPhys, turns the crops into a pulse signal. It runs in the browser through ONNX Runtime Web. Clean the signal. I band-pass filter it to $0.7$–$3.5,\text{Hz}$ (42–210 BPM) and take an FFT. Pick the beat. The strongest peak in the spectrum is the heart rate: $$\text{HR} = 60 \cdot f_0 \quad \text{(BPM)}$$
It's plain HTML, CSS and JavaScript with no backend, hosted free on GitHub Pages.
Challenges
The model's output looks like noise. The network outputs the change in the pulse, not the pulse itself. Integrating it fully makes random noise look like a strong slow heartbeat around 45 BPM. The fix was a "half integration" that divides the spectrum by $\sqrt{f}$. It keeps real pulses and removes the bias. Cameras fight you. Auto-exposure shifts pixel values by more than the pulse itself does. I added an exposure lock, plus a safety net that undoes it if the image goes dark. Heads move. I score head motion every frame and throw out the shaky ones. If the signal is weak, the number greys out and holds its last value, so it never shows a confident wrong answer. My own deployment bug. After I put the site on a custom domain, the camera refused to start. Browsers only allow getUserMedia on HTTPS pages, so I had to turn on HTTPS for the domain.
What I learned
Signal processing is mostly about not trusting your data. Most of the work went into deciding when not to show a number. A neural network is only half the pipeline. The filtering around it decides whether the result is any good. Shipping to real devices teaches you things a laptop never will, like HTTPS rules, different cameras and lighting.
What's next
Better accuracy for darker skin tones and low light, and testing on more phones.
⚠️ PulseCam is a school project and not a medical device.
Built With
- css3
- efficientphys
- html5
- javascript
- mediapipe-face-landmarker
- pytorch
Log in or sign up for Devpost to join the conversation.