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
+8 -8
View File
@@ -5,16 +5,16 @@ from dataclasses import dataclass
@dataclass(frozen=True)
class ChromaSettings:
green_margin: float = 0.08
min_green_value: float = 0.22
min_saturation: float = 0.20
hue_low: float = 35.0
hue_high: float = 95.0
border_ratio: float = 0.04
min_samples: int = 2048
hue_sigma_min: float = 7.0
lab_sigma_min: float = 10.0
rgb_sigma_min: float = 0.08
# Background-colour auto-detection (used when screen_color is None): find the
# flat colour that dominates the image border; raise if none is clean enough.
detect_cluster_radius: float = 12.0 # Lab radius grouping border pixels into the background cluster
detect_min_border_share: float = 0.55 # min fraction of the border that must be this one colour
detect_corner_tol: float = 20.0 # max Lab distance a corner may sit from the cluster centre
@dataclass(frozen=True)
@@ -116,7 +116,7 @@ class PipelineSettings:
despill: DespillSettings = DespillSettings()
model: ModelSettings = ModelSettings()
segmentation: SegmentationSettings = SegmentationSettings()
# Background-colour prior. None = auto-detect a green screen (current default,
# unchanged). A hex string like "#CFEFFF" keys chroma + despill off that colour
# instead, for arbitrary (e.g. pastel) flat backgrounds.
# Background-colour prior. None = auto-detect the flat background colour from the
# image border (raises if there is no clean flat background). A hex string like
# "#CFEFFF" sets it explicitly.
screen_color: str | None = None