lhk229 da4164e95a Support loading model weights from local project folders
Add bgfilter/weights.py: resolve_model_source() maps a HuggingFace repo id
to a local folder under the weights dir (models/ by default, override with
BGFILTER_WEIGHTS_DIR) when one named after the repo basename exists; otherwise
the repo id is returned unchanged. Opt-in and backward compatible.

- vitmatte_infer.py / segmentation.py resolve model_name through it; anime-seg
  reads <dir>/isnetis.onnx directly instead of hf_hub_download when local.
- .gitignore: models/, model-cache/
- README: document bundling weights as plain project folders.

Verified: anime-seg loads from a local models/anime-seg/ folder offline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 02:50:19 +00:00
2026-07-02 12:26:20 +00:00

BgFilter

Offline character matting for AI-generated images on a flat-colour background. The background colour is auto-detected from the image border (green, pastel, any flat colour); pass --screen-color to set it explicitly.

RGB input
  -> chroma bg-confidence (keyed to the auto-detected or given colour)
  -> [optional] semantic segmentation mask
  -> trimap -> ViTMatte -> alpha cleanup
  -> pymatting foreground -> despill -> RGBA PNG -> QA previews

Pipelines

Two pipelines, selected by segmentation.enabled in the config:

  • Chroma-only (enabled: false) — Chroma + ViTMatte, no segmentation model. Lightest / fastest; leans entirely on the colour key for topology.
  • Single segmenter (enabled: true, default) — one segmentation model drives the trimap topology (holes, hair), ViTMatte then refines the soft edges. Backend is switchable: birefnet (default, general salient objects — text, logos, photos; needs trust_remote_code) or anime-seg (ONNX, tuned for anime characters). Switch at runtime with --seg-backend anime-seg (it also selects the matching weights).

Both share pymatting foreground estimation and a colour de-spill. There is no green-contamination rescue / recolour layer — with clean source images it is unnecessary, so it was removed.

The segmentation trimap defaults to directional mode (chroma + seg + a hue-direction split: it keeps a background-coloured garment such as a white shirt while dropping a background-hued residual such as blue trapped between hair strands). Switch with --trimap-mode seg (topology only, no hue split) or directional-hard-bg (aggressive — hard-removes background-hued pixels; can eat cool/shadowed white cloth).

Background colour

By default (screen_color: null) the background colour is auto-detected from the image border: the dominant flat colour of the border strip becomes the key colour. If the border is not one clean flat colour — a gradient, texture, or a subject filling the frame — detection fails with an error; pass --screen-color explicitly in that case.

To set it yourself, give a hex prior:

... --screen-color "#CFEFFF"

or screen_color: "#CFEFFF" in the config. Either way the chroma key scores pixels by perceptual (Lab/RGB) distance to the colour, and de-spill removes chroma along that colour's direction. (A supplied hex is refined against nearby border pixels; an auto-detected colour is used directly.)

Environment

Use the conda environment lightML.

conda activate lightML
pip install -r requirements.txt

If the shell is not activated, call the environment Python directly:

D:\MiniConda\envs\lightML\python.exe -m bgfilter.cli --help

Single Image

D:\MiniConda\envs\lightML\python.exe -m bgfilter.cli `
  --input Samples\TestImage.png `
  --output Outputs\TestImage_rgba.png `
  --debug-dir Outputs\TestImage_debug

No --config is needed — the built-in defaults are identical to configs/default.yaml. Pass --config configs\default.yaml only after you edit that file to tune the detailed parameters. Runtime choices stay on the command line: --device (default CPU; use --device cuda for GPU), --seg-backend (default birefnet; anime-seg for anime characters), --screen-color (default: auto-detect the flat background), and --trimap-mode.

Batch

D:\MiniConda\envs\lightML\python.exe -m bgfilter.cli `
  --input-dir Samples `
  --output-dir Outputs `
  --debug-dir Outputs\debug

Chroma-alpha debug mode

--matting-method chroma skips ViTMatte and uses chroma confidence directly as the alpha seed. Useful for fast inspection of chroma confidence, trimap, and despill. (Distinct from the chroma-only pipeline above, which still runs ViTMatte.)

D:\MiniConda\envs\lightML\python.exe -m bgfilter.cli `
  --input-dir Samples `
  --output-dir Outputs\chroma `
  --debug-dir Outputs\chroma_debug `
  --matting-method chroma `
  --device cpu

Outputs

For each processed image, the CLI writes an RGBA PNG and optional debug files:

bg_confidence.png
trimap.png
seg_mask.png          # segmentation pipeline only
alpha.png
foreground_rgb.png    # despilled foreground colour
color_mask.png        # per-pixel despill weight
preview_black.png
preview_white.png
preview_gray.png
preview_red.png
preview_blue.png
qa_grid.png
metadata.json

HTTP service

An HTTP wrapper (app.py + bgfilter/service.py) exposes the pipeline as a long-running FastAPI service. Models load once and are reused across requests.

D:\MiniConda\envs\lightML\python.exe -m uvicorn app:app `
  --host 127.0.0.1 --port 18083 --workers 1

Two endpoints:

  • GET /healthz — liveness/config JSON.
  • POST /remove-backgroundmultipart/form-data, returns image/png.
    • file (required) — the source image. The field name is fixed as file.
    • screen_color (optional) — #RRGGBB prior; omit/empty for auto-detect.
    • seg_model (optional) — birefnet (default) or anime-seg.
# default (birefnet + auto background colour)
curl -sS -F "file=@input.png" \
  http://127.0.0.1:18083/remove-background -o output.png

# explicit background colour + anime segmenter
curl -sS \
  -F "file=@input.png" \
  -F "screen_color=#CFEFFF" \
  -F "seg_model=anime-seg" \
  http://127.0.0.1:18083/remove-background -o output.png

Config comes from BGFILTER_CONFIG (defaults to configs/default.yaml when present); BGFILTER_DEVICE overrides both model and segmentation device; BGFILTER_MAX_IMAGE_PIXELS caps input size (default ~4MP → 413); BGFILTER_PRELOAD=1 loads the default models at startup. Run a single worker (--workers 1) — each worker loads its own copy of the models.

Quality Check

The quality checker measures alpha validity and edge spill on semi-transparent edge pixels.

D:\MiniConda\envs\lightML\python.exe -m bgfilter.quality_cli `
  Outputs\TestImage_rgba.png `
  --max-edge-green-excess-p95 0.30

Run the bundled sample smoke check:

D:\MiniConda\envs\lightML\python.exe scripts\smoke_samples.py `
  --samples-dir Samples `
  --output-dir Outputs\smoke_samples `
  --config configs\default.yaml `
  --device cpu `
  --fallback-to-chroma-alpha `
  --max-edge-green-excess-p95 0.30

Notes

  • Samples/ and Outputs/ are ignored by Git.
  • ViTMatte and segmentation weights load from Hugging Face on first use. anime-seg (skytnt/anime-seg) is a plain ONNX download; birefnet (ZhengPeng7/BiRefNet) ships custom modelling code so it needs trust_remote_code=True plus timm / einops / kornia.
  • Downloading the weights behind a firewall — the reliable combination is the hf-mirror.com mirror with the local proxy bypassed and Xet disabled:
    $env:HF_ENDPOINT      = "https://hf-mirror.com"  # domestic mirror
    $env:NO_PROXY         = "*"                       # bypass the proxy; the mirror is direct
    $env:HF_HUB_DISABLE_XET = "1"                     # these repos are Xet-backed; force classic HTTP
    
    Two gotchas this avoids: (1) mirror + an overseas proxy makes the mirror's resolve bounce back to huggingface.co, which recent huggingface_hub rejects with FileMetadataError; (2) with hf-xet installed the Xet download path fails instantly. Once the weights are cached, run offline with HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 (as the service does in production).
  • Bundling weights in the project — instead of the HF cache, drop each model into a plain folder named after the repo basename under models/: models/vitmatte-base-composition-1k, models/BiRefNet, models/anime-seg. The loader prefers a matching local folder and falls back to the HF repo id / cache when absent, so it is opt-in. Populate them with e.g. hf download ZhengPeng7/BiRefNet --local-dir models/BiRefNet. Override the base directory with BGFILTER_WEIGHTS_DIR. models/ is gitignored.
  • Foreground colour estimation uses pymatting's estimate_foreground_ml to propagate clean foreground colour into semi-transparent edges before de-spill. Set foreground.method: unmix to fall back to the legacy heuristic.
  • docs/green_screen_matting_workflow.md is the original phase-1 green-screen spec; this README reflects the current, generalised architecture.
S
Description
No description provided
Readme 1 MiB
Languages
Python 100%