Revert "Carve background green embedded in the foreground (hole handling)"
This reverts commit f7e12d3.
The carve set alpha to 0 on a colour-thresholded mask across the whole
foreground, which cannot distinguish background green from green the AI
generator bled onto the subject. It therefore (1) deleted green-tinted hair
strands and (2) hard-cut the green-spill silhouette edge, replacing ViTMatte's
anti-aliased edge with a jagged one. Local cues (surround, opacity, thinness,
connectivity, neighbour colour) could not reliably separate green hair from
green holes, so the mask is not fixable by tuning. Reverting restores intact
hair and smooth edges; the finger-gap green stays a minor residual.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user