Deface — Face Obfuscation
Deface is a privacy processor plugin modelled on
ORB-HD/deface: a Python worker runs
CenterFace face detection (the ONNX model deface itself uses) over the
app’s live HLS stream and streams normalized face boxes into the framework’s
plugin live-data channel.
The player overlay polls that channel and obfuscates each detected region
client-side — blur, mosaic or a solid mask.
| Plugin id | deface |
| Category | processor |
| UI slot | player-overlay |
| Needs worker | Yes |
HLS /hls/<app>/<room>/index.m3u8 │ (sampled at `fps`) ▼CenterFace (centerface.onnx — onnxruntime CPU/CUDA, or OpenCV DNN) │ (thresh filter → mask-scale expansion → normalize 0–1) ▼POST plugin live-data channel (worker → core, per-start ingest token) ▼GET /apps/:app/plugins/deface/live?room=<room> (public, no auth) ▼Player overlay: blur / mosaic / solid over each face (smoothed between polls)The worker POSTs every sampled frame — an empty faces list clears the
overlay masks (unlike yolo, which only posts on a hit). Boxes are already
expanded by maskScale before they’re sent, so the overlay never re-expands
them.
⚠️ Privacy caveat — read this first
Section titled “⚠️ Privacy caveat — read this first”Deface anonymizes the player only. The masks are drawn by the viewer’s
browser on top of the <video> element:
- the raw stream (WebRTC, HLS segments, RTMP restreams) still contains the faces — anyone consuming the stream outside the StreamHub player sees them;
- recordings, VODs and snapshots still contain the faces — nothing about the recording pipeline is touched;
- a viewer with DevTools can remove the overlay.
Treat it as a presentation-layer privacy feature (kiosk displays, public
embeds, demo screens) — not as anonymization of the media itself. Server-side
anonymization of recordings (re-encoding with the masks burned in, which is
what the original deface CLI does to files) is not implemented.
Configuration
Section titled “Configuration”Every field has a default — a fresh install is valid immediately; only room
must be set before the plugin can be enabled.
| Field | Type | Default | Description |
|---|---|---|---|
room |
string |
`` (empty) | Required. HLS room name to process — /hls/<app>/<room>/index.m3u8. |
thresh |
number |
0.2 |
Detection threshold, 0–1. Lower catches more faces but adds false positives; raise it if too much is masked. |
replacewith |
select |
blur |
Anonymization method. Options: blur (gaussian), mosaic (pixelate), solid (black fill), none (detect only). |
maskScale |
number |
1.3 |
Enlarge detected boxes by this factor (1–3) to cover hair/chin. Applied worker-side; the payload carries the value so the overlay never double-expands. |
boxes |
boolean |
false |
On draws rectangular masks; off (default) draws ellipses. |
mosaicSize |
number |
20 |
Pixel size of mosaic blocks (2–200). Only used when replacewith is mosaic. |
scale |
string |
`` (empty) | WxH to downscale frames for detection, e.g. 640x360. Empty = native size. A big CPU saver on HD sources at a small accuracy cost. |
backend |
select |
auto |
Inference backend. Options: auto (ONNX Runtime if importable, else OpenCV), onnxrt (ONNX Runtime), opencv (OpenCV DNN). |
cuda |
boolean |
false |
On uses the CUDA execution provider (needs onnxruntime-gpu); off runs on CPU. Falls back to CPU automatically — with a log note — when CUDA is unavailable. |
fps |
number |
2 |
Frames per second sampled from the stream (0.1–30, lower = less CPU). The overlay polls at ~this rate and smooths between updates. |
drawScores |
boolean |
false |
Show the detection confidence next to each mask (debugging). |
Render-side options (replacewith, boxes, mosaicSize, drawScores,
maskScale) reach the anonymous player through the sanitized public config
(GET /apps/:app/plugins/public); detection options are mapped to DEFACE_*
environment variables by the worker’s spawn(ctx).
The worker & model
Section titled “The worker & model”When enabled, the framework spawns the worker from the repo-root
deface-worker/ Python package:
python3 -m deface_worker --app <app>- Model —
centerface.onnx(~7.4 MB) is downloaded on first run to<DATA_DIR>/models/deface/(shared across every app on the node), the same patternyolouses for its weights. Override the source withDEFACE_MODEL_URL, or pre-seed the file for air-gapped hosts. - Backend & GPU fallback — CenterFace is much lighter than YOLO, so CPU
handles a few FPS comfortably.
backend: autopicks ONNX Runtime when it’s importable, otherwise OpenCV DNN. Settingcuda: trueuses the CUDA execution provider (requiresonnxruntime-gpuin the worker’s Python env) and is only worth it for highfps(>10) or many simultaneous rooms — if CUDA can’t initialize, the worker logs a note and continues on CPU; it never crash-loops over a missing GPU. - Live-data channel — the worker-hook injects a fresh
STREAMHUB_INGEST_URL/STREAMHUB_INGEST_TOKENper start; the worker POSTs its detections there. An operator can divert the feed withDEFACE_CALLBACK_URL(same payload shape). - Overridable env:
PLUGIN_PYTHON(interpreter, defaultpython3) andDEFACE_WORKER_DIR(path to thedeface-worker/checkout, defaults to the copy at the repo root).
Lifecycle is framework-owned, exactly like every needsWorker plugin: enabling
(re)starts the worker, disabling stops it, and start/stop/status/logs are
exposed over the API.
Enable and configure
Section titled “Enable and configure”Dashboard: open the app’s Plugins tab → Install Deface — Face Obfuscation → Configure the room (required) plus the mask style, thresholds and backend → toggle Active to start the worker. Use the plugin’s Logs to watch the worker output.
API:
curl -X PATCH https://YOUR-DOMAIN/api/v1/apps/live/plugins/deface \ -H "Authorization: Bearer sk_..." \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "config": { "room": "live", "thresh": 0.2, "replacewith": "blur", "maskScale": 1.3, "boxes": false, "mosaicSize": 20, "scale": "640x360", "backend": "auto", "cuda": false, "fps": 2, "drawScores": false } }'Worker lifecycle and logs use the same routes as every worker plugin:
curl -X POST https://YOUR-DOMAIN/api/v1/apps/live/plugins/deface/worker/start \ -H "Authorization: Bearer sk_..."curl https://YOUR-DOMAIN/api/v1/apps/live/plugins/deface/worker/status \ -H "Authorization: Bearer sk_..."curl "https://YOUR-DOMAIN/api/v1/apps/live/plugins/deface/logs?limit=200" \ -H "Authorization: Bearer sk_..."