Skip to main content

Blur immodestly dressed people in videos. Video in, video out.

Project description

OCCLUDE

OCCLUDE is a command-line tool that takes a video file and writes back the same video with immodestly dressed people blurred out, audio left intact. It's for muslims who want to watch otherwise-fine content (documentaries, lectures, talks) without the immodest imagery that gets mixed into it.

I kept skipping videos I was genuinely curious about because of what was in frame, not what was being said. The friction is the imagery, not the subject, so I wanted something that hands me back the same file with the unwanted imagery blurred. Great real-time browser blockers like HaramBlur exist and are really needed, but processing every frame live forces accuracy tradeoffs (flicker, missed frames, false positives). OCCLUDE runs offline on a whole file instead, so it can take its time and get it right.

occlude --input documentary.mp4
# writes documentary_occluded.mp4 next to the input

What gets blurred

The decision is per person and binary: someone is either fully blurred or not at all. There's no partial blur of a single body part. When a person is blurred, the blur traces their silhouette with a soft feathered edge rather than a hard rectangle.

For men, the whole person is blurred if skin shows between the navel and the knee. Shirtless is the main case; shorts and bare thighs are the secondary one.

For women, the whole person is blurred if any of these is visible: uncovered hair, bare arms, bare legs, or exposed neck and chest.

People dressed modestly are left as is: a woman in full hijab, a man in a t-shirt and full-length trousers. Faces of modestly dressed people, backgrounds, objects, animals, cartoon/CGI figures, and text overlays are not touched. A person who appears to be a child (under 13) is never blurred. When the judgment is genuinely uncertain about a real adult, OCCLUDE leans toward blurring rather than missing.

How it works (v0.1 — offline, three passes)

OCCLUDE has the whole file on disk, so it does not process frame-by-frame like a live filter. It runs three passes, each free to use the whole video:

input.mp4
  Pass 1  detect + track   RT-DETR finds people every frame; IoU association
                           links them into per-person "tracklets", split at
                           shot cuts.
  Pass 2  judge            a vision-language model (Qwen2.5-VL) looks at each
                           tracklet's clearest frames once and returns a
                           structured verdict: real human? male/female?
                           child? modest or not?  One decision per person.
  Pass 3  render           the verdict is applied across the person's entire
                           on-screen span; SAM2 cuts a clean silhouette for
                           the people being blurred; ffmpeg muxes the audio.
output_occluded.mp4

Deciding once per person and applying it across their whole span is what removes the flicker and the "blurs a second late" problem that a streaming filter has — there is no per-frame decision to wobble, and a person flagged on frame 200 is blurred from frame 1 of that shot. Letting a model that can actually reason make the modesty call (instead of stacking a clothing segmenter and a brittle gender classifier) is what fixes the subtler errors: a clean-shaven man read as a woman, a CGI character treated as a person, a crowd shown from behind blurred into mud.

Install

pip install occlude

You also need ffmpeg on your PATH (used to copy the original audio onto the output):

brew install ffmpeg        # macOS

For clean silhouette-shaped blur you also want SAM2, which isn't on PyPI:

pip install "git+https://github.com/facebookresearch/sam2.git"

Without SAM2, run with --no-sam2 and the blur falls back to a soft feathered box around each person.

Python 3.10+. A CUDA GPU is strongly recommended — OCCLUDE runs a heavy detector, SAM2, and a 7B vision-language model. On a single A100/H100 a feature-length video takes a few hours; on CPU/Apple Silicon it is only practical for short clips. Model weights download on first run.

Usage

occlude --input video.mp4

The output lands next to the input as video_occluded.mp4. Common options:

occlude --input video.mp4 --output cleaned.mp4              # custom output path
occlude --input video.mp4 --device cuda                     # force CUDA
occlude --input video.mp4 --blur-strength 99                # Gaussian kernel, odd, default 199
occlude --input video.mp4 --judge-batch 16                  # crops per VLM pass (throughput knob)
occlude --input video.mp4 --judge-frames 5                  # frames judged per person (accuracy knob)
occlude --input video.mp4 --judge-model Qwen/Qwen2.5-VL-7B-Instruct
occlude --input video.mp4 --detector rtdetr-x.pt            # swap the person detector
occlude --input video.mp4 --no-sam2                         # box blur instead of silhouette

--judge-batch is the main speed knob: it sets how many person-crops the VLM judges in one forward pass. --judge-frames trades a little speed for accuracy by judging more views of each person. --detector accepts any Ultralytics RT-DETR or YOLO weights.

Running on Colab

OCCLUDE is compute-heavy, so for anything long run it on a Colab GPU runtime. notebooks/occlude_colab.ipynb is set up for that: open it in Colab (GPU runtime), point it at your video, run the cells. It installs occlude, SAM2, and the model weights.

Known limitations

It works and is usable, but it's early (version 0.1.0) and is a ground-up rearchitecture of the earlier per-frame version.

  • Accuracy is best on clear cases and worst on hard ones: tiny/distant people, heavy occlusion, low resolution, motion blur.
  • It biases toward over-blurring under uncertainty, so expect occasional false positives (a modestly dressed person blurred now and then) more often than misses.
  • Age estimation near the under-13 line is the least reliable signal; the child exemption is gated on the model agreeing across multiple frames.
  • It's terminal only, takes a local file (no YouTube URLs), and is not a general people-blur tool — the blur only fires when the modesty rules are triggered.
  • Hijab vs. uncovered-hair from behind / in profile remains the hardest case.

Start with a short clip to confirm the output is what you want before committing to a full-length file.

Credits and license

OCCLUDE is glue around three pretrained models:

  • person detection: RT-DETR via Ultralytics
  • segment + silhouette: SAM 2 (Segment Anything 2) from Meta
  • modesty / sex / age judgment: Qwen2.5-VL

Plus PyTorch, Transformers, OpenCV, NumPy, Pillow, tqdm, and rich.

MIT licensed (note the upstream model weights carry their own licenses). Issues and PRs welcome at https://github.com/anaxoniclabs/OCCLUDE/issues. If a fellow muslim developer takes this further than I could, that's the outcome I'd be happiest with.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

occlude-0.0.3.tar.gz (41.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

occlude-0.0.3-py3-none-any.whl (35.8 kB view details)

Uploaded Python 3

File details

Details for the file occlude-0.0.3.tar.gz.

File metadata

  • Download URL: occlude-0.0.3.tar.gz
  • Upload date:
  • Size: 41.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for occlude-0.0.3.tar.gz
Algorithm Hash digest
SHA256 0768c1e1647cd31985f95d54a7a548a57646e8654f7c31a43c6af6dd5e7c2f9b
MD5 9e8fb0e536eab3d77587384b170bb8b4
BLAKE2b-256 02b5949c973856d1fbe89a163c650c2d601c9e3b9c132d27a2febc1d0c85521a

See more details on using hashes here.

File details

Details for the file occlude-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: occlude-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 35.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for occlude-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 5bb8c86fc933e857c92763544cca632e06f909ce5758cc93c6a4f85bc13ae58f
MD5 b882730f8d717147c0912d8660f5452d
BLAKE2b-256 b67c0530cc6048c64f8caa8fa8d7ad1e7613e317641149836de15926e7032b5d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page