Auto-detect the background colour (default); drop the green heuristic

Replace the hardcoded green-screen auto-detection with a general flat-colour
detector. When screen_color is null the background colour is now detected from the
image border (dominant colour of the border strip) and used directly as the chroma
model, with a failure gate that raises when the border is not one clean flat colour
(gradient / texture / subject filling the frame).

- chroma: add detect_background_color + _background_border_cluster; the null case of
  estimate_background_model samples the detected cluster directly (no seed search);
  compute_bg_confidence is now always perceptual (Lab/RGB distance). Removed the green
  heuristic (initial_green_candidates), the green multiplicative gating, the now-unused
  _smoothstep, and five green-only ChromaSettings fields.
- pipeline: reuse the detected colour for de-spill in the auto case.
- settings / default.yaml: add detect_* tuning fields; refresh screen_color docs.
- README: document auto-detection + the failure gate, trimap modes, birefnet config.

A supplied --screen-color hex still uses the seed-search refinement. Validated:
detects green / pastel / text samples correctly, raises on gradient / two-colour, CLI
exits 1 on failure, green and pastel mattes unchanged in quality.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 20:34:31 +08:00
parent 7308730528
commit 62f175948e
6 changed files with 117 additions and 83 deletions
+27 -13
View File
@@ -1,12 +1,12 @@
# BgFilter
Offline character matting for AI-generated images on a flat-colour background.
Green screen is the default; any flat colour (e.g. a pastel `#CFEFFF`) works via a
`screen_color` prior.
The background colour is **auto-detected** from the image border (green, pastel, any
flat colour); pass `--screen-color` to set it explicitly.
```text
RGB input
-> chroma bg-confidence (keyed to the screen colour)
-> 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
@@ -20,24 +20,37 @@ Two pipelines, selected by `segmentation.enabled` in the config:
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: `anime-seg` (default, ONNX) or `birefnet` (needs `trust_remote_code`).
switchable: `anime-seg` (default, ONNX, for anime characters) or `birefnet` (general
salient objects — text, logos, photos; needs `trust_remote_code`). Use
`--config configs\birefnet.yaml` for the BiRefNet backend.
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
Default is green auto-detection. For any other flat background, pass the colour as a
hex prior so both the chroma key and the de-spill work off it:
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:
```powershell
... --screen-color "#CFEFFF"
```
or set `screen_color: "#CFEFFF"` in the config (`null` = green auto-detect). The
chroma key then scores pixels by perceptual (Lab/RGB) distance to that colour, and
de-spill removes chroma along that colour's direction instead of the green channel.
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
@@ -62,13 +75,14 @@ D:\MiniConda\envs\lightML\python.exe -m bgfilter.cli `
--output Outputs\TestImage_rgba.png `
--debug-dir Outputs\TestImage_debug `
--config configs\default.yaml `
--screen-color "#CFEFFF" `
--device cuda
```
The CLI reads `configs/default.yaml` when `--config` is provided. Command-line
options override config values, so tuning usually happens in YAML while runtime
choices such as `--device cpu` or `--screen-color` stay on the command line.
No `--screen-color` is needed — the background colour is auto-detected. Add
`--screen-color "#CFEFFF"` only to override it. The CLI reads `configs/default.yaml`
when `--config` is provided; command-line options override config values, so tuning
usually happens in YAML while runtime choices (`--device`, `--screen-color`,
`--trimap-mode`) stay on the command line.
## Batch