diff --git a/bgfilter/alpha_post.py b/bgfilter/alpha_post.py index 468929d..5151c32 100644 --- a/bgfilter/alpha_post.py +++ b/bgfilter/alpha_post.py @@ -45,36 +45,6 @@ def suppress_alpha_by_chroma( return np.clip(out, 0.0, 1.0) -def carve_background_holes( - alpha: np.ndarray, rgb: np.ndarray, settings: AlphaPostSettings -) -> np.ndarray: - """Remove green-dominant pixels that are embedded inside the foreground. - - Targets background green that pokes into the silhouette (gaps between fingers, - pockets between hair strands) where the green is too dark/desaturated for the - chroma confidence to flag, so the matte wrongly fills it as foreground. A pixel - is carved when it is clearly green-dominant *and* mostly surrounded by genuine - (non-green) foreground, which separates such an intrusion from the outer hair - edge (background on one side) that must be preserved. - """ - if not settings.hole_carve: - return alpha - cv2 = require_cv2() - rgb_f = rgb.astype(np.float32) / 255.0 - dom = rgb_f[..., 1] - np.maximum(rgb_f[..., 0], rgb_f[..., 2]) - green = dom > settings.hole_green_dominance - # Foreground that is genuinely opaque and not itself green, so the surround - # measure reflects real body/hair rather than the green we want to remove. - solid_fg = ((alpha > settings.hole_fg_alpha) & ~green).astype(np.float32) - radius = max(1, int(round(max(alpha.shape) * settings.hole_surround_radius_ratio))) - ksize = radius * 2 + 1 - surround = cv2.GaussianBlur(solid_fg, (ksize, ksize), 0) - carve = green & (surround > settings.hole_surround_min) - out = alpha.astype(np.float32).copy() - out[carve] = 0.0 - return np.clip(out, 0.0, 1.0) - - def _remove_small_components(mask: np.ndarray, min_area: int) -> np.ndarray: cv2 = require_cv2() count, labels, stats, _ = cv2.connectedComponentsWithStats(mask.astype(np.uint8), 8) diff --git a/bgfilter/pipeline.py b/bgfilter/pipeline.py index 3612b2f..298d50f 100644 --- a/bgfilter/pipeline.py +++ b/bgfilter/pipeline.py @@ -6,12 +6,7 @@ from pathlib import Path import numpy as np -from .alpha_post import ( - carve_background_holes, - clean_alpha, - enforce_trimap, - suppress_alpha_by_chroma, -) +from .alpha_post import clean_alpha, enforce_trimap, suppress_alpha_by_chroma from .chroma import compute_bg_confidence from .despill import despill_green from .foreground import estimate_foreground_rgb @@ -78,7 +73,6 @@ def _run_image( alpha = enforce_trimap(alpha, trimap) alpha = suppress_alpha_by_chroma(alpha, bg_confidence, trimap, settings.alpha_post) alpha = clean_alpha(alpha, trimap, settings.alpha_post) - alpha = carve_background_holes(alpha, rgb, settings.alpha_post) foreground = estimate_foreground_rgb( rgb, alpha, bg_confidence, model, settings.foreground ) diff --git a/bgfilter/settings.py b/bgfilter/settings.py index f68716d..9fb2c30 100644 --- a/bgfilter/settings.py +++ b/bgfilter/settings.py @@ -39,14 +39,6 @@ class AlphaPostSettings: 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) diff --git a/configs/default.yaml b/configs/default.yaml index f0e8abc..2ec8849 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -15,11 +15,6 @@ alpha_post: chroma_suppress_bg_low: 0.35 chroma_suppress_bg_high: 0.80 chroma_suppress_strength: 1.0 - hole_carve: true - hole_green_dominance: 0.10 - hole_fg_alpha: 0.5 - hole_surround_radius_ratio: 0.012 - hole_surround_min: 0.4 foreground: enabled: true