Simplify to single-segmenter pipelines; add screen_color prior; drop rescue + recolor
Strategic pivot: the dropout-fill rescue, the anime-seg fill backend, the
BiRefNet+anime-seg intersection, and the recolor pass all existed to repair
source images whose hair was already green-contaminated or broken at generation
time. Fixing the source instead (clean pastel-background generation) makes the
matte high-contrast, so that whole compensation layer is unnecessary. Remove it.
- Two pipelines via segmentation.enabled:
false -> chroma-only (Chroma + ViTMatte)
true -> single segmenter (default anime-seg, switchable birefnet) -> trimap
then ViTMatte refines, pymatting estimates foreground, despill cleans spill.
- Generalise the green-hardcoded colour logic to a screen_color prior (hex, e.g.
"#CFEFFF"; default null = green auto-detect, byte-identical). chroma keys off
Lab/RGB distance to the colour; despill removes chroma along its Lab direction.
Added --screen-color CLI flag.
- Removed dead code: fill_seg_dropouts + seg_fill*/intersection params,
SegmentationSettings.fill_backend/fill_model_name/sharpen, unsharp_mask,
recolor.py + RecolorSettings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+11
-35
@@ -42,20 +42,6 @@ class AlphaPostSettings:
|
||||
chroma_suppress_bg_low: float = 0.35
|
||||
chroma_suppress_bg_high: float = 0.80
|
||||
chroma_suppress_strength: float = 1.0
|
||||
# Segmentation dropout-fill: rescue alpha where ViTMatte cut a region the
|
||||
# semantic mask asserts is foreground (green-contaminated wisps it cannot see).
|
||||
seg_fill: bool = True
|
||||
seg_fill_alpha_max: float = 0.10
|
||||
seg_fill_seg_min: float = 0.10
|
||||
seg_fill_strength: float = 0.70
|
||||
seg_fill_min_area_ratio: float = 0.00002 # drop rescued specks below this area
|
||||
# Intersection fill: gate the (anime-seg) dropout-fill by a second, reliable
|
||||
# mask (BiRefNet). anime-seg proposes freely at a low seg_fill_seg_min; only
|
||||
# rescues BiRefNet also endorses (>= seg_fill_gate_min, its threshold left
|
||||
# unchanged) survive. Trims anime-seg's over-inclusive halo to the structure
|
||||
# both backends agree on, without reintroducing BiRefNet's grainy value.
|
||||
seg_fill_intersect: bool = False
|
||||
seg_fill_gate_min: float = 0.10
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -85,19 +71,10 @@ class DespillSettings:
|
||||
green_excess_margin: float = 0.015
|
||||
edge_expand_radius: int = 2
|
||||
alpha_weight_floor: float = 0.35
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RecolorSettings:
|
||||
enabled: bool = True
|
||||
person_threshold: float = 0.5 # clean reference = subject above this seg/alpha
|
||||
coverage_soft: float = 0.08 # recolour ramps in over alpha 0..this
|
||||
contam_low: float = 0.02 # residual off-colour where recolour starts
|
||||
contam_high: float = 0.12 # residual off-colour for full recolour
|
||||
clean_dom_max: float = 0.03 # reference = subject pixels below this off-colour
|
||||
propagate_radius_ratio: float = 0.02
|
||||
min_reference_weight: float = 0.05
|
||||
luminance_strength: float = 0.5 # how far to pull luminance to the clean neighbour
|
||||
# Custom-screen despill (when screen_color is set): margin, in Lab a*/b*
|
||||
# units, of chroma allowed along the background colour direction before it is
|
||||
# treated as spill. Larger keeps more of the subject's own colour.
|
||||
color_margin_lab: float = 4.0
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -110,15 +87,11 @@ class ModelSettings:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SegmentationSettings:
|
||||
enabled: bool = True
|
||||
backend: str = "birefnet" # "birefnet" or "anime-seg"
|
||||
model_name: str = "ZhengPeng7/BiRefNet"
|
||||
fill_backend: str = "" # "" = reuse `backend` for dropout-fill; else e.g. "anime-seg"
|
||||
fill_model_name: str = ""
|
||||
enabled: bool = True # False = chroma-only pipeline (no seg model)
|
||||
backend: str = "anime-seg" # "anime-seg" or "birefnet"
|
||||
model_name: str = "skytnt/anime-seg"
|
||||
device: str = "cuda"
|
||||
input_size: int = 1024
|
||||
sharpen: float = 0.0 # unsharp-mask amount on the mask (0 = off)
|
||||
sharpen_radius: int = 4
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -128,6 +101,9 @@ class PipelineSettings:
|
||||
alpha_post: AlphaPostSettings = AlphaPostSettings()
|
||||
foreground: ForegroundSettings = ForegroundSettings()
|
||||
despill: DespillSettings = DespillSettings()
|
||||
recolor: RecolorSettings = RecolorSettings()
|
||||
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.
|
||||
screen_color: str | None = None
|
||||
|
||||
Reference in New Issue
Block a user