f7e12d3498
The green in the finger gap survives keying because it is dark and desaturated (brightness ~0.58, hue-shifted), so chroma confidence reads ~0 and the trimap leaves it in the unknown band, where ViTMatte fills the pocket as foreground. It is also connected to the exterior screen (an open notch), so neither confidence suppression nor classic hole-filling removes it. Add carve_background_holes (doc section 10): a pixel that is clearly green-dominant in the input *and* mostly surrounded by genuine (non-green) foreground is set to alpha 0. The surround cue separates such an intrusion (finger gaps, inter-strand pockets) from the outer hair edge, which has background on one side and is preserved. Runs after alpha cleanup. On TestImage the finger-gap survivors (green & alpha>0.5) drop 170 -> 28 with no visible loss of hair wisps; inter-strand green pockets clear too. Knobs in AlphaPostSettings (hole_*, default on, surround_min 0.4). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
97 lines
3.0 KiB
Python
97 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
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
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class TrimapSettings:
|
|
sure_bg_threshold: float = 0.92
|
|
sure_fg_threshold: float = 0.12
|
|
unknown_radius_ratio: float = 0.012
|
|
fg_safe_radius_ratio: float = 0.006
|
|
min_unknown_radius: int = 4
|
|
min_fg_safe_radius: int = 2
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AlphaPostSettings:
|
|
min_component_area_ratio: float = 0.00001
|
|
fill_hole_area_ratio: float = 0.00002
|
|
alpha_floor: float = 0.002
|
|
alpha_ceil: float = 0.998
|
|
# Chroma-guided alpha suppression: in the unknown band, pull alpha toward 0
|
|
# where background (green) confidence is high, clearing spill in gaps/holes.
|
|
chroma_suppress: bool = True
|
|
chroma_suppress_bg_low: float = 0.35
|
|
chroma_suppress_bg_high: float = 0.80
|
|
chroma_suppress_strength: float = 1.0
|
|
# Background-hole carving (doc section 10): remove green-dominant pixels that
|
|
# are embedded in the foreground (finger gaps, inter-strand pockets) where the
|
|
# green is too dark for the chroma confidence to flag.
|
|
hole_carve: bool = True
|
|
hole_green_dominance: float = 0.10
|
|
hole_fg_alpha: float = 0.5
|
|
hole_surround_radius_ratio: float = 0.012
|
|
hole_surround_min: float = 0.4
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ForegroundSettings:
|
|
enabled: bool = True
|
|
method: str = "ml" # "ml" (pymatting) or "unmix" (legacy heuristic)
|
|
fallback_to_unmix: bool = True
|
|
ml_regularization: float = 1e-5
|
|
# Legacy "unmix" method parameters (used only when method == "unmix").
|
|
edge_low: float = 0.005
|
|
edge_high: float = 0.995
|
|
min_unmix_alpha: float = 0.08
|
|
unmix_strength: float = 0.70
|
|
local_strength: float = 0.45
|
|
local_blur_radius: int = 11
|
|
local_alpha_threshold: float = 0.92
|
|
local_bg_confidence_max: float = 0.20
|
|
green_excess_margin: float = 0.015
|
|
bg_confidence_weight: float = 0.70
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class DespillSettings:
|
|
enabled: bool = True
|
|
edge_low: float = 0.005
|
|
strength: float = 0.92
|
|
green_excess_margin: float = 0.015
|
|
edge_expand_radius: int = 2
|
|
alpha_weight_floor: float = 0.35
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ModelSettings:
|
|
model_name: str = "hustvl/vitmatte-small-composition-1k"
|
|
device: str = "cuda"
|
|
matting_method: str = "vitmatte"
|
|
fallback_to_chroma_alpha: bool = False
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PipelineSettings:
|
|
chroma: ChromaSettings = ChromaSettings()
|
|
trimap: TrimapSettings = TrimapSettings()
|
|
alpha_post: AlphaPostSettings = AlphaPostSettings()
|
|
foreground: ForegroundSettings = ForegroundSettings()
|
|
despill: DespillSettings = DespillSettings()
|
|
model: ModelSettings = ModelSettings()
|