Headless Mode
Free · open source

redactcam

Face and license-plate redaction for video, with a second pass that proves the blur landed

In real use since

What separates a license plate from a road sign

This figure is drawn in your browser from a JSON file in this repository. Without JavaScript the chart and table below stay empty — the same numbers are readable directly in that JSON file.

Shaded region: boxes the plate gate accepts — the aspect and area window. Numbered rectangles are the measured ranges for four kinds of road object.

  • 10%
  • 1%
  • 0.1%
  • 0.01%
Aspect ratio against box area for four road objects.
  • 1:1
  • 2:1
  • 4:1
  • 8:1
  • 16:1
Each object's measured box shape, and what the gate does with it. Both axes on the figure are logarithmic.
ObjectAspectAreaGate

    Thresholds read verbatim from redactcam. The plotted rectangles are the ranges that preset's own comments record from real forward-facing 4K road footage — per-class ranges, illustrative of the decision the gate makes. They are not detections from any one video, and nothing here is a result.

    Confidence cannot tell a plate from a sign

    A plate detector fires hard on rectangular signage. A place-name sign scores about 0.6 — above any confidence threshold you can actually use without losing real plates. Raise the number and you start missing plates; lower it and you blur every sign on the road. There is no setting on that dial that separates the two, which is why the dial is the wrong control.

    The axes that do separate them are geometric, and the figure above is them. A real plate is wide but bounded — around 2.4–3:1 seen at an angle, up to about 4.7:1 head-on — while signs box near-square and shorelines and bridge railings box at about 13:1. And a real plate is a tiny fraction of a 4K frame, never more than about 0.4%, while a stone wall the model misreads covers several percent. Either axis alone lets something through: the wall sits squarely inside the aspect window, and only the area ceiling drops it. Both together leave a window that keeps every real plate and rejects all three of the others.

    The same problem turns up on faces, where the separable axis is time rather than shape. Foliage and shadows score 0.5–0.7, comfortably above a genuine small face at 0.19, so no confidence threshold works there either. But a real face re-detects across consecutive samples while a texture artifact fires once and stops. That is why the face confidence is set very low and paired with a rule that a track must accumulate several detections before it is emitted — lowering the confidence without that pairing gives you a video full of blurred hedges.

    The blur is tracked, not stamped

    Detection is expensive, so it runs on a sample of frames. The naive fix is to hold each detection’s box until the next one, or to union the two endpoints. Either way a plate caught in one sample has its box frozen for a fraction of a second while the car keeps moving: the blur covers empty road ahead of the plate, and the plate itself drives out from under it in plain view.

    redactcam propagates each box on every frame with Lucas-Kanade optical flow — a standard way of following where a patch of pixels moved between two frames — plus a RANSAC scale term, a fit that ignores the points that disagree with the rest, so an approaching object’s box grows with it. Each new detection snaps the box back to ground truth. Detection stays sparse; propagation costs milliseconds. Occupants get a different treatment again — face detection through a moving windscreen latches onto reflections and roof lines at any confidence, so the cabin is covered geometrically instead: detect the whole vehicle, blur the top band of its box, which is where people sit at every viewing angle.

    Verifying after the render is verifying too late

    Once a multi-gigabyte file is encoded and shipped, discovering that the blur missed a driver costs a re-encode and a takedown. So the check runs before the encode, and it does not trust any stage above it. It re-runs detection from scratch on the source frames, corroborates each vehicle with a license plate — so it chases cars rather than billboards — and confirms that the mask covers each corroborated car’s cabin. A cabin the mask leaves uncovered raises CoverageError instead of producing a file.

    Checking the mask rather than the finished render is deliberate. A render usually carries other changes too — grading, overlays, a different codec — so differencing it against the source cannot isolate the blur. The mask is exactly what the blur will cover, which makes mask coverage equal to output coverage without the confound, and it exists before the expensive, irreversible step rather than after it.

    What this page is and is not

    The gate thresholds in the figure are read straight from the library’s tuned preset for forward-facing 4K road footage. The rectangles are the ranges that preset’s own comments record from real footage, drawn to show the decision the gate makes — they are per-class ranges rather than detections from any one video, and no output here is presented as a result. There is no blurred video on this page on purpose: the interesting claim is not that a detector found a face, it is what happens when one does not.

    Command line

    To skip the Windows installer above and install straight from the source: pip install git+https://github.com/Back-Road-Creative/redactcam.

    1redactcam dashcam.mp4 -o dashcam_redacted.mp4 -v
    

    --no-render stops after the mask and the coverage check, for when you would rather bring your own encode. Exit code 2 means that check failed and nothing was rendered.

    Requirements

    Python 3.11 or newer, and an ffmpeg/ffprobe binary on the path — the mask render and the blur composite both shell out to it.

    The Windows installer above is redactcam frozen into one executable, so it needs no Python, and it is a large download: opencv and onnxruntime are frozen in with it. Two things it does not carry. It does not bundle ffmpeg, and redactcam cannot render anything without it — winget install -e --id Gyan.FFmpeg puts both binaries on PATH, and choco install ffmpeg works too. It does not bundle model weights either, so the first run needs a network connection: roughly 110 MB of ONNX files, fetched once over HTTPS, checksum-verified and cached. A machine that will never reach the internet needs those files supplied instead, through --model.

    Documentation

    redactcam’s documentation lives in its repository, next to the code it describes — the README is the manual.

    The code is MIT, but the weights redactcam downloads by default are not, and several are copyleft. Read the README’s license section before deploying anything — it sets the terms out in full.

    ← All software