# anime-facesaver Scene-gated still extractor for building anime training datasets from video. Fork of `facesaver`, created Oct 2026. ## Why this fork exists The original facesaver ran stock COCO `yolov11l.pt` and accepted class 0 — **`person`** — as a "proxy for face" (their comment, not ours). COCO has no face class, so every frame containing a large enough person passed: full-body shots, headless crops, a hand at 75% confidence. That is why the old Gabriel Dropout output contained stills of shoes. anime-facesaver uses a dedicated anime-face detector instead: [`yolov8x6_animeface`](https://huggingface.co/Fuyucchi/yolov8_animeface) — yolov8x6 fine-tuned at 1280px on 10k manually annotated anime images (P=0.957 R=0.924 mAP50=0.955 on its test set). It detects faces. Only faces. The scene-change gate from the original is preserved: at most one still is saved per detected scene, which keeps near-duplicates out of the dataset. ## Setup ```bash uv venv --python 3.12 .venv # or: python3.12 -m venv .venv source .venv/bin/activate pip install -r requirements.txt # add --index-url for your CUDA ver python anime_facesaver.py --download-model ... # fetches weights once ``` Weights land in `models/yolov8x6_animeface.pt` (~195 MB, AGPL-3.0). ## Usage ```bash python anime_facesaver.py \ -I /home/alex/Documents/image-training-datasets/gabriel-dropout-show \ -O /home/alex/Documents/image-training-datasets/gabriel-dropout-v2 \ --gpu 1 \ --preview-dir /home/alex/Documents/image-training-datasets/gabriel-dropout-v2-preview ``` ### GPU pinning (important on the shared .80 box) `--gpu` sets `CUDA_VISIBLE_DEVICES` **before** torch initializes, so no context leaks onto the wrong card: | flag | effect | |-----------|-----------------------------------------------| | `--gpu 1` | pin to physical GPU 1 (recommended on .80) | | `--gpu 0` | pin to GPU 0 — OOMs while Strata holds it | | `--gpu cpu` | force CPU | | `--gpu auto` | let torch pick | ### Key options | flag | default | meaning | |------|---------|---------| | `--conf` | 0.3 | detector confidence (model's own recommendation; it is high-precision) | | `--min-width` / `--min-height` | 100 | minimum face box size in px | | `--min-face-fraction` | 0.005 | face box area as fraction of frame — kills distant background extras; `0` disables | | `--max-face-fraction` | 0.30 | face box area upper cap — kills detector meltdowns on full-frame ED/OP effects (feather storms etc.); `0` disables | | `--min-aspect` / `--max-aspect` | 0.45 / 1.6 | face box W/H ratio window — effect blobs rarely keep face proportions | | `--edge-margin` | 0 | require faces this far inside frame edges; `0` accepts edge-touching faces (original hard-rejected them) | | `--scene-threshold` | 30.0 | PySceneDetect ContentDetector threshold (same as original) | | `--imgsz` | 1280 | inference size; model was trained at 1280, `640` is faster at some recall cost | | `--all-files` | off | also scan OP/ED files. Off by default: music videos are full of stylized graphics (feather storms, transformation emblems) that false-positive as face-shaped; episodes carry the real character close-ups | | `--preview-dir` | off | also write annotated copies (green boxes) of every saved frame for eyeball QC | ## Notes - Runs every frame of every scene until a face qualifies, then waits for the next scene start. That is the original behavior and it is why dense scenes don't flood the output. - The detector ships as `yolov8x6` — big and a little slow (it was trained to be precise, not cheap). On a 3090 at 1280px expect roughly 8-12 fps; an hour of 24fps anime is ~15 min of inference per GPU. - **License**: the model weights are AGPL-3.0 (Fuyucchi); ultralytics is AGPL-3.0 too. Fine for personal/research dataset building; if this ever ships in a product, revisit. ## QC: auditing an existing collection `audit_stills.py` runs the same detector over a directory of stills and reports how many contain no face at all — e.g. measuring the damage the old person-proxy pipeline did: ```bash python audit_stills.py -I ~/Documents/image-training-datasets/gabriel-dropout \ --gpu 1 --write-report old_run_report.csv ``` ## Verified run (Gabriel Dropout, Oct 18 2026) 12 episodes + 2 specials, OP/ED skipped: **3,526 stills** vs 887 from the old person-proxy run (~4x yield — chibi reaction faces no longer missed). QC: full box-size distribution audited (p5=0.7%, median 6.6%, max 29.9%); 5 largest and 5 smallest saves inspected with annotated copies — all real faces; zero faceless images found. The 5 largest sit against the 30% area cap and are legitimate extreme close-ups (crying faces count). ## Verification workflow Always run with `--preview-dir` and eyeball the `_ann.png` files: every saved frame should show a green box on a real face. Pay attention to saves clustered *against* a gate (e.g. many boxes at ~max area) — that pattern means the gate is doing work and deserves a look. For a known-dirty legacy collection, `audit_stills.py` quantifies the damage. Recipe: ```bash python anime_facesaver.py -I -O --gpu \ --preview-dir -preview ```