Automated anime NSFW mosaic/blur/scanline censorship pipeline.
censor runs an anime-trained YOLO instance-segmentation model over a folder of images,
turns the per-instance masks into a censored region, and renders a mosaic (or blur / scanlines /
pixelate) only over the anatomy you choose — leaving the rest of the picture intact. It is
model-agnostic: drop any Ultralytics -seg checkpoint into .models/ and it works.
Responsible use. This tool exists to add censorship for platform compliance (e.g. Pixiv, Japanese Article 175 mosaic conventions). Use it only on adult content you have the right to process. You are responsible for the legality of your source material.
Earlier iterations reconstructed a censor region from bounding boxes + SAM2 + morphology. A purpose-built anime segmentation model returns the exact shape directly, which removed an entire fragile subsystem. The pipeline is now:
Load → Segment → Mask union → QA / fail-closed gate → Render → Export
- Pluggable detector honoring a simple
load / detect / releasecontract. - Canonical label normalization so different models' class names (
pussy,Pussy,vagina,cleft of venus, …) all map to one vocabulary. - Per-run output folders with a provenance manifest.
- Fail-closed approval gate — an image with an empty mask is blocked, never exported raw.
| Stage | Name | Hardware | Artifacts |
|---|---|---|---|
| 1 | Asset Loader | CPU | metadata/<id>.json |
| 2 | ROI Segmentation (YOLO-seg) | GPU | stage2/<id>.json |
| 3 | Mask Generation / Union (+ erosion, censor_fully) |
CPU | stage4/<id>.png |
| 4 | QA Preview + Fail-Closed Approval | CPU | stage5/preview_<id>.png, stage5/approved.json |
| 5 | Render (mosaic / pixelate / blur / scanlines) | CPU | stage6/<id>.png |
| 6 | Post-Processing / Export (metadata strip) | CPU | output/<id>.png |
(Internal artifact directories keep historical stageN names; the segmentation path uses one GPU
stage and loads → processes → releases VRAM so it fits a 6 GB card.)
- Python 3.11+
- NVIDIA GPU with ≥ 6 GB VRAM (RTX 3050 or better) recommended; CPU works but is slow.
- Core deps:
ultralytics,opencv-python,pillow,numpy,pyyaml(Ultralytics pullstorch).
python -m venv .venv
# Windows: .venv\Scripts\activate | Linux/macOS: source .venv/bin/activate
pip install -e ".[dev,gui]"
pytest # optional: run the test suite (CPU-only, models are mocked)
# Optional: install extras for legacy detectors (anime, nudenet, gdino)
pip install -e ".[anime,nudenet,gdino]"Place your segmentation checkpoint(s) in .models/:
.models/
└── animeNSFWSegm_xlRes1280.pt
censor loads any Ultralytics YOLO -seg checkpoint. Verify a model with:
from ultralytics import YOLO
m = YOLO(".models/your_model.pt")
print(m.task) # must print "segment"Class names vary between models; censor/detectors/labels.py normalizes them:
| Canonical | Recognized raw labels |
|---|---|
vagina |
vagina, pussy, cleft of venus |
penis |
penis |
anus |
anus |
nipple |
nipple, nipples, nipple_f |
Add a new model's labels by extending ALIASES in labels.py. Unmapped labels are ignored
(fail-safe against over-coverage) — so audit a new model's class list before trusting it, since an
unmapped genitalia class would go uncensored.
A photoreal (real-life-trained) YOLO-seg model works too — just drop it in
.models/and pointmodel_pathat it. Add any new class names toALIASES.
# Run with defaults from config.yaml
censor
# Custom input / output directories
censor -i my_pics -w out
# Censor only specific classes, tighter masks, custom confidence
censor --classes vagina penis --erode 8 --threshold 0.35
# Different effects
censor --effect blur
censor --effect pixelate --scale 0.005
censor --effect scanlines --gap 24 --thickness 6
# Swap the model
censor -m .models/ntd11_anime_nsfw_segm_v5.pt
# Verbose (see per-image detections) / preview-only
censor -v
censor --dry-run -vrun.py is a thin wrapper if you prefer: python run.py --classes vagina penis.
| Flag | Purpose |
|---|---|
-i, --input |
Input image directory (default images) |
-w, --work |
Work/output root (default work) |
-c, --config |
Path to config.yaml |
-m, --model |
Override detector.model_path |
-t, --threshold |
Detection confidence (0–1) |
--classes |
Canonical labels to censor, e.g. --classes vagina penis |
--censor-fully |
Classes censored without erosion (full coverage), e.g. --censor-fully penis |
--imgsz |
Inference resolution (default 1280; auto-degrades on VRAM OOM) |
--ignore-left-visible |
Silence "detected but LEFT VISIBLE" warnings |
--renderer |
segmask / effect / mosaic / blur |
--effect |
mosaic / pixelate / blur / scanlines |
--scale |
Mosaic/pixelate block scale (× reference edge) |
--minimum, --maximum |
Block-size floor / ceiling (px) |
--interpolation |
nearest / bilinear / bicubic |
--blur-radius |
Blur strength |
--gap, --thickness |
Scanline spacing / bar thickness |
--erode |
Shrink mask inward (px); higher = less coverage |
--feather |
Soften mask edge (px) |
--run-id |
Name this run's folder (default: timestamp) |
-v, -vv |
Per-stage info / per-detection debug |
--dry-run |
Detect + log only; skip render/export |
CLI flags override config.yaml; the resolved config is recorded in each run's run.json.
censor includes a Gradio-based interactive web editor for real-time model tuning, live previewing, manual mask editing with brush tools, and session-wise exporting.
# Launch the web editor (opens automatically in browser at http://127.0.0.1:7860)
censor-gui
# Custom port or public Gradio share link
censor-gui --port 8080 --share- Tabbed Layout:
- 1. Setup & Detect: Load single or multiple images, configure detector checkpoints, target classes (
vagina,penis,anus,nipple), confidence thresholds, and execute GPU segmentation across the batch. - 2. Effect & Tuning: Dynamically adjust parameters for
mosaic,pixelate,blur, orscanlines(block scale, blur radius, line gap/thickness, erosion, and feathering) with sticky real-time visual previews.
- 1. Setup & Detect: Load single or multiple images, configure detector checkpoints, target classes (
- Manual Mask Editing (Brush):
- Select Add or Erase mode to draw directly on the image editor canvas.
- Manual brush edits seamlessly composite with detected model masks, allowing quick fixes for under-censored regions or false positives.
- Session-wise Export:
- Export the current image or all processed images into a session output folder (
work/gui_runs/session_<timestamp>/output/). - Session grouping keeps outputs organized during interactive editing sessions.
- Export the current image or all processed images into a session output folder (
config.yaml holds defaults, including per-effect profiles merged at render time:
detector:
primary: segmentation
model_path: .models/animeNSFWSegm_xlRes1280.pt
threshold: 0.25
classes: [vagina, penis, anus]
ignore_left_visible: false
censor_fully: [anus, penis] # full coverage (no erosion) for these
renderer:
type: effect
effect: mosaic # mosaic | pixelate | blur | scanlines
minimum: 4
maximum: null
reference: long_edge
color: [0, 0, 0]
mosaic: { scale: 0.004, erode: 15, minimum: 4, maximum: 16, feather: 0 }
pixelate: { scale: 0.001, erode: 10, feather: 0, interpolation: bilinear }
blur: { blur_radius: 2, erode: 4, feather: 0 }
scanlines: { gap: 30, thickness: 5, erode: 14, feather: 0 }
output:
compression: 9
runtime:
vram_lifecycle: load_process_release
batch_size: 2- mosaic / pixelate — block pixelation.
scalesets block size relative to the image edge (block =scale × long_edge, floored/clamped byminimum/maximum). Lowerscale= finer. - blur — Gaussian blur (
blur_radius). - scanlines — horizontal bars (
gap,thickness,color); region stays visible but censored, which sidesteps mask-undershoot on tricky poses.
erodeshrinks the mask inward (tighter coverage);censor_fullydisables erosion for a class (full coverage). Small masks are auto-protected from over-erosion.- Censorship strength is content-dependent — different images may want different settings. Use CLI overrides per batch; each run is isolated in its own folder.
work/
└── runs/
├── 2026-07-18_16-07-09_<pid>/
│ ├── run.json # config + timestamp + input dir (provenance)
│ ├── metadata/ stage2/ stage4/ stage5/ stage6/
│ └── output/ # final censored images for THIS run
└── latest # symlink/pointer to the newest run
Each run is self-contained — no stale state, and you can diff two runs' run.json to see what
changed. Final deliverables are always in <run>/output/.
ruff check . # lint
ruff format . # format
pytest # tests (model calls are mocked; no GPU needed)Architecture: detectors implement the Detector protocol (censor/detectors/base.py); renderers
apply an effect within a mask (censor/render/). Add a detector by dropping a class in
censor/detectors/ and registering it in Pipeline._get_detector.
MIT © 2026 Ishan Dev Shakya