Fuse semantic segmentation mask into the trimap
Wire BiRefNet into the pipeline (lazy-loaded) and build the trimap from the semantic subject mask refined by the green key, used when segmentation is enabled. generate_trimap (chroma-only) stays as the no-segmentation fallback. Authority split: the mask decides subject topology (keeps green-tinted hair as foreground, drops see-through holes), the bright-green key sharpens the screen boundary, ViTMatte refines a small protective band. Background follows the mask directly so interior holes survive; the band is small so it does not swallow finger gaps. End-to-end on the samples: green hair preserved, finger-gap green 99% transparent (BiRefNet marks it background; was 100% foreground before), leg edges smooth -- topology/colour/edge problems local cues could not solve, with no hard alpha surgery. - SegmentationSettings wired into PipelineSettings/config; --device propagates. - TrimapSettings: seg_core_threshold, seg_loose_threshold. - New debug output seg_mask.png. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+8
-1
@@ -11,6 +11,7 @@ from .settings import (
|
||||
ForegroundSettings,
|
||||
ModelSettings,
|
||||
PipelineSettings,
|
||||
SegmentationSettings,
|
||||
TrimapSettings,
|
||||
)
|
||||
|
||||
@@ -42,7 +43,7 @@ def _update_dataclass(instance: T, values: dict[str, Any] | None) -> T:
|
||||
|
||||
|
||||
def settings_from_dict(data: dict[str, Any]) -> PipelineSettings:
|
||||
allowed_sections = {"chroma", "trimap", "alpha_post", "foreground", "despill", "model"}
|
||||
allowed_sections = {"chroma", "trimap", "alpha_post", "foreground", "despill", "model", "segmentation"}
|
||||
unknown_sections = sorted(set(data) - allowed_sections)
|
||||
if unknown_sections:
|
||||
raise ValueError(f"Unknown config section(s): {', '.join(unknown_sections)}")
|
||||
@@ -54,6 +55,7 @@ def settings_from_dict(data: dict[str, Any]) -> PipelineSettings:
|
||||
foreground=_update_dataclass(ForegroundSettings(), data.get("foreground")),
|
||||
despill=_update_dataclass(DespillSettings(), data.get("despill")),
|
||||
model=_update_dataclass(ModelSettings(), data.get("model")),
|
||||
segmentation=_update_dataclass(SegmentationSettings(), data.get("segmentation")),
|
||||
)
|
||||
|
||||
|
||||
@@ -70,6 +72,7 @@ def override_settings(settings: PipelineSettings, **overrides: Any) -> PipelineS
|
||||
foreground = settings.foreground
|
||||
despill = settings.despill
|
||||
model = settings.model
|
||||
segmentation = settings.segmentation
|
||||
|
||||
model_updates = {
|
||||
key: overrides[key]
|
||||
@@ -89,6 +92,9 @@ def override_settings(settings: PipelineSettings, **overrides: Any) -> PipelineS
|
||||
despill_updates: dict[str, Any] = {}
|
||||
if overrides.get("despill") is not None:
|
||||
despill_updates["enabled"] = overrides["despill"]
|
||||
seg_updates: dict[str, Any] = {}
|
||||
if overrides.get("device") is not None:
|
||||
seg_updates["device"] = overrides["device"]
|
||||
|
||||
return PipelineSettings(
|
||||
chroma=chroma,
|
||||
@@ -97,4 +103,5 @@ def override_settings(settings: PipelineSettings, **overrides: Any) -> PipelineS
|
||||
foreground=foreground,
|
||||
despill=_update_dataclass(despill, despill_updates),
|
||||
model=_update_dataclass(model, model_updates),
|
||||
segmentation=_update_dataclass(segmentation, seg_updates),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user