Filter speckle noise from the segmentation dropout-fill

The rescue floored alpha with BiRefNet's soft mask verbatim, which sprinkled
~800 isolated <10px specks (burrs) across the matte from the mask's scattered
low-confidence noise. Drop rescued connected components below a min area, keeping
only the connected wisp structures.

On TestImage2 the rescued components fall from 900 (818 isolated specks) to 91
and the added pixels from 5124 to 1886 -- the genuine wisp strands stay, the
burrs go. smoke still passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 23:29:14 +08:00
parent b0a634dfd4
commit 26b0bc8388
3 changed files with 8 additions and 0 deletions
+6
View File
@@ -104,5 +104,11 @@ def fill_seg_dropouts(
out = alpha.astype(np.float32).copy()
rescued = settings.seg_fill_strength * np.clip(seg_mask, 0.0, 1.0)
dropout = (out < settings.seg_fill_alpha_max) & (seg_mask >= settings.seg_fill_seg_min)
# The segmentation mask carries scattered low-confidence noise; rescuing it
# verbatim sprinkles isolated specks (burrs) over the matte. Keep only
# connected structures (genuine wisps), drop the isolated specks.
if settings.seg_fill_min_area_ratio > 0:
min_area = max(4, int(round(alpha.size * settings.seg_fill_min_area_ratio)))
dropout = _remove_small_components(dropout, min_area)
out[dropout] = np.maximum(out[dropout], rescued[dropout])
return np.clip(out, 0.0, 1.0)
+1
View File
@@ -48,6 +48,7 @@ class AlphaPostSettings:
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
@dataclass(frozen=True)
+1
View File
@@ -27,6 +27,7 @@ alpha_post:
seg_fill_alpha_max: 0.10
seg_fill_seg_min: 0.10
seg_fill_strength: 0.70
seg_fill_min_area_ratio: 0.00002
foreground:
enabled: true