All notes

【TECH】Detecting whether a finger really covers the camera

How MonoPump uses color ratios, brightness bounds, red dominance, and frame smoothing to decide when measurement can begin.

computer visionPPGcamerasignal quality
【TECH】Detecting whether a finger really covers the camera

The first naive version of finger detection was tempting: if the frame is red, the finger is there. It worked on my desk for about five minutes, then failed the moment the phone angle changed. A red object, a dark room, or a leaking edge of light could all pass one simple check.

A phone camera covered by a fingertip with a translucent sampling grid
Coverage detection starts with cheap frame metrics before any BPM is calculated.

So the practical question became narrower: what does a usable fingertip frame look like, and how do we reject the frames that merely look reddish?

I stopped trusting one number

A covered camera frame is not only red. It has enough brightness, not too much brightness, a red channel that leads green and blue, and enough pixels where red is dominant. MonoPump combines those clues instead of betting on a single threshold.

Flow diagram Preparing diagram
View diagram source
flowchart TD
    A[Sample center region] --> B[Compute average RGB]
    B --> C[Brightness in usable range?]
    C -- no --> D[tooDark or tooBright]
    C -- yes --> E[Red ratio high enough?]
    E -- no --> F[no finger]
    E -- yes --> G[Red dominance and red pixels strong?]
    G -- weak --> H[weak coverage]
    G -- strong --> I[good coverage]

The center crop is intentional. The edges of the preview are where light leaks, finger curvature, and motion produce unstable color. Sampling the center makes the detector behave more like a tiny contact sensor.

The metrics that matter

MonoPump computes a small set of cheap metrics directly from the BGRA pixel buffer. That matters because this runs every frame.

brightness = (avgRed + avgGreen + avgBlue) / 3
redRatio = avgRed / max((avgGreen + avgBlue) / 2, 1)
redDominance = avgRed / max(avgGreen, avgBlue)
dominantRedPixelFraction = redDominantPixels / sampledPixels

Brightness catches the obvious failures. Red ratio catches the fingertip color shift. Red-dominant pixel fraction prevents a few bright red pixels from fooling the detector.

Good, weak, none is better than yes or no

The UI needs more than a Boolean. If the app only says not detected, the user has no idea whether to press harder, reduce pressure, cover the flash, or simply wait. MonoPump classifies coverage into practical states: none, too dark, too bright, weak coverage, and good.

State diagram Preparing diagram
View diagram source
stateDiagram-v2
    [*] --> none
    none --> weakCoverage: red appears but signal is weak
    weakCoverage --> good: red dominance becomes stable
    good --> weakCoverage: pressure or alignment changes
    weakCoverage --> none: red ratio drops
    none --> tooDark: brightness below lower bound
    none --> tooBright: brightness above upper bound

The final trick is frame smoothing. One bad frame should not reset the whole measurement, and one good frame should not start it. Loose thresholds improve success rate but admit bad signals; strict thresholds improve confidence but frustrate real users. The better boundary is starting only when the next seconds are likely to produce a useful waveform.

From MonoWare

MonoPump has more context behind this note.

Open the product site or keep reading notes filtered to MonoPump.

Newsletter

Privacy and product engineering notes, sent occasionally.