Minimal end-to-end pipeline that anonymizes egocentric (GoPro) video: every frame has faces and mobile phones blurred out, so neither identities nor on-screen conversations are visible.
pip install -r requirements.txt
python blur_pipeline.py GX010042.mp4 # writes GX010042_blurred.mp4That is the whole pipeline — push a video in, get the processed video back.
Detection models (YuNet face model + YOLOv8n) download automatically on the
first run into models/.
Tip: for a smaller CPU-only install, get the slim torch build first:
pip install torch --index-url https://download.pytorch.org/whl/cpu
- Frames are decoded with OpenCV and streamed one at a time (nothing is written to disk in between, so a 3.5 GB / 13 min 2.7K@60 file is fine).
- The video is processed in resumable chunks (default 10). Each finished
chunk appears as a playable
<output>.chunkNN.mp4— inspect the first one while the rest still runs. If the run crashes or is interrupted, re-running the same command picks up after the last completed chunk. At the end the chunks are concatenated losslessly (no re-encode), the source audio is muxed in, and the chunk files are removed. - Roughly 20 times per second of video (auto-scaled from the frame rate,
override with
--every) two fast detectors run:- Faces — YuNet on a 1920 px-wide downscale (finds noticeably more small/far faces than lower widths; measured on 2.7K frames).
- Phones — YOLOv8n (COCO class cell phone) at 960 px (640 px misses small/distant phones; measured, not guessed).
- Between detections, boxes are not just frozen: global camera motion is estimated per frame (phase correlation on a 1/8-scale grayscale, ~1 ms) and carried boxes are shifted with it — so fast egocentric head turns don't slide a face out from under its blur. Boxes are padded 20% on top.
- A box also survives a few missed detection cycles (
--keep, default 3) before it is dropped, so one flickered detection can't leak sharp frames. - Only the box regions are blurred (pixelated by default — irreversible;
--style gaussianfor a softer look, equally destructive). - Frames are piped straight into an ffmpeg
libx264encoder. Every chunk (and the final file) is written as a.part.mp4and renamed only after all of its frames made it through — a truncated run can't masquerade as a finished video.
| flag | default | meaning |
|---|---|---|
-o |
<input>_blurred.mp4 |
output path |
--every |
auto | detect every N frames (default fps/20; 1 = every frame) |
--chunks |
10 |
resumable chunks (finished chunks are skipped on re-run) |
--conf |
0.30 |
YOLO phone confidence (lower = blur more aggressively) |
--imgsz |
960 |
YOLO inference size (1280 catches even smaller phones) |
--model |
yolov8n.pt |
any ultralytics model; yolov8s.pt = better recall |
--pad |
0.2 |
padding around detected boxes |
--det-width |
1920 |
face-detection resolution (raise to catch tiny faces) |
--face-score |
0.5 |
YuNet score threshold (lower = more aggressive) |
--keep |
3 |
detection cycles a box survives without being re-found |
--style |
pixelate |
pixelate or gaussian |
--crf |
23 |
output quality (lower = better/bigger) |
--device |
auto |
cpu, CUDA index (e.g. 0), or auto |
- With an NVIDIA GPU (
--device 0or justauto) expect roughly realtime or better for 2.7K@60. The startup line prints which device YOLO is on; if it sayscpuand you have an NVIDIA card, install a CUDA torch build (pip install torch --index-url https://download.pytorch.org/whl/cu126) — it is by far the biggest speedup available. - CPU-only: measured ~7.5 fps end-to-end at 2704x1520 on a modest 4-core
box. On slower laptops,
--det-width 1280 --imgsz 640roughly doubles throughput at some cost in small/far face and phone recall, and a higher--every(e.g. fps/10) trades temporal precision for speed. - Tuning false blurs vs missed blurs:
--conf(phones) and--face-score(faces) are the two dials. The defaults balance the two; lower them (e.g.--conf 0.15 --face-score 0.35) if a real face or phone slips through, raise them if harmless objects keep getting blurred. Track memory (--keep) bridges detection cycles where confidence dips, so a phone only needs to clear--confoccasionally, not on every frame. Boxes carried between detections grow with camera motion but are capped at 1.6x their detected size, so one spurious detection can't balloon into a large blurred patch.--every 1gives frame-exact detection.