Remove dead code: unused detect_background_color and ForegroundEstimate extras
- chroma.detect_background_color had no callers anywhere (auto-detection goes through estimate_background_model / _background_border_cluster). - ForegroundEstimate.background and .correction were computed on every image but never consumed; only .rgb was used. estimate_foreground_rgb now returns the foreground array directly and the dataclass is gone, which also drops pymatting return_background work and a per-image correction-norm pass. Verified: CLI output on samples/TestImage3.png is byte-identical (SHA256) to the pre-cleanup baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -112,22 +112,6 @@ def _background_border_cluster(
|
||||
return full, share, agree
|
||||
|
||||
|
||||
def detect_background_color(
|
||||
rgb: np.ndarray, settings: ChromaSettings | None = None
|
||||
) -> tuple[float, float, float]:
|
||||
"""Detect a single flat background colour from the image border.
|
||||
|
||||
Returns the colour as a 0..1 RGB triple. Raises RuntimeError (via
|
||||
:func:`_background_border_cluster`) if the border is not dominated by one flat
|
||||
colour, so callers fail loudly rather than matting against a wrong colour.
|
||||
Pure: reads pixels only, with no matting side effects.
|
||||
"""
|
||||
settings = settings or ChromaSettings()
|
||||
rgb_f, lab = convert_color_spaces(rgb)
|
||||
mask, _, _ = _background_border_cluster(lab, settings)
|
||||
return tuple(float(x) for x in np.median(rgb_f[mask], axis=0))
|
||||
|
||||
|
||||
def estimate_background_model(
|
||||
rgb: np.ndarray,
|
||||
settings: ChromaSettings,
|
||||
|
||||
+8
-36
@@ -1,7 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .chroma import BackgroundModel
|
||||
@@ -9,27 +7,16 @@ from .deps import require_cv2
|
||||
from .settings import ForegroundSettings
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ForegroundEstimate:
|
||||
rgb: np.ndarray # estimated foreground colour F (uint8, HxWx3)
|
||||
background: np.ndarray # estimated background colour B (uint8, HxWx3)
|
||||
correction: np.ndarray # per-pixel |F - input| magnitude, 0..1 (float32, HxW)
|
||||
|
||||
|
||||
def estimate_foreground_rgb(
|
||||
rgb: np.ndarray,
|
||||
alpha: np.ndarray,
|
||||
bg_confidence: np.ndarray,
|
||||
model: BackgroundModel,
|
||||
settings: ForegroundSettings,
|
||||
) -> ForegroundEstimate:
|
||||
) -> np.ndarray:
|
||||
"""Estimated foreground colour F (uint8 HxWx3) for compositing over alpha."""
|
||||
if not settings.enabled:
|
||||
bg = np.broadcast_to(np.asarray(model.rgb_center, dtype=np.float32), rgb.shape)
|
||||
return ForegroundEstimate(
|
||||
rgb=rgb.copy(),
|
||||
background=np.clip(bg * 255.0, 0, 255).astype(np.uint8),
|
||||
correction=np.zeros(alpha.shape, dtype=np.float32),
|
||||
)
|
||||
return rgb.copy()
|
||||
|
||||
method = settings.method
|
||||
if method == "ml":
|
||||
@@ -48,7 +35,7 @@ def estimate_foreground_rgb(
|
||||
|
||||
def _estimate_ml(
|
||||
rgb: np.ndarray, alpha: np.ndarray, settings: ForegroundSettings
|
||||
) -> ForegroundEstimate:
|
||||
) -> np.ndarray:
|
||||
"""Multi-level closed-form foreground/background estimation (pymatting).
|
||||
|
||||
Solves image = alpha * F + (1 - alpha) * B with spatial smoothness, so the
|
||||
@@ -66,17 +53,8 @@ def _estimate_ml(
|
||||
|
||||
image = rgb.astype(np.float64) / 255.0
|
||||
a = np.clip(alpha.astype(np.float64), 0.0, 1.0)
|
||||
foreground, background = estimate_foreground_ml(
|
||||
image, a, regularization=settings.ml_regularization, return_background=True
|
||||
)
|
||||
foreground = np.clip(foreground, 0.0, 1.0)
|
||||
background = np.clip(background, 0.0, 1.0)
|
||||
correction = np.linalg.norm(foreground - image, axis=2) / np.sqrt(3.0)
|
||||
return ForegroundEstimate(
|
||||
rgb=np.clip(foreground * 255.0, 0, 255).astype(np.uint8),
|
||||
background=np.clip(background * 255.0, 0, 255).astype(np.uint8),
|
||||
correction=correction.astype(np.float32),
|
||||
)
|
||||
foreground = estimate_foreground_ml(image, a, regularization=settings.ml_regularization)
|
||||
return np.clip(foreground * 255.0, 0, 255).astype(np.uint8)
|
||||
|
||||
|
||||
def _weighted_blur(values: np.ndarray, weights: np.ndarray, radius: int) -> np.ndarray:
|
||||
@@ -97,7 +75,7 @@ def _estimate_unmix(
|
||||
bg_confidence: np.ndarray,
|
||||
model: BackgroundModel,
|
||||
settings: ForegroundSettings,
|
||||
) -> ForegroundEstimate:
|
||||
) -> np.ndarray:
|
||||
"""Legacy heuristic: edge-band alpha unmix plus local foreground blur."""
|
||||
rgb_f = rgb.astype(np.float32) / 255.0
|
||||
r = rgb_f[..., 0]
|
||||
@@ -131,10 +109,4 @@ def _estimate_unmix(
|
||||
local_mask = base_mask * settings.local_strength * low_alpha_weight
|
||||
out = out * (1.0 - local_mask[..., None]) + local_fg * local_mask[..., None]
|
||||
|
||||
background = np.broadcast_to(bg, rgb_f.shape)
|
||||
correction = np.linalg.norm(out - rgb_f, axis=2) / np.sqrt(3.0)
|
||||
return ForegroundEstimate(
|
||||
rgb=np.clip(out * 255.0, 0, 255).astype(np.uint8),
|
||||
background=np.clip(background * 255.0, 0, 255).astype(np.uint8),
|
||||
correction=correction.astype(np.float32),
|
||||
)
|
||||
return np.clip(out * 255.0, 0, 255).astype(np.uint8)
|
||||
|
||||
@@ -178,7 +178,7 @@ def _process_rgb(rgb: np.ndarray, pipeline: MattingPipeline) -> MattingResult:
|
||||
foreground = estimate_foreground_rgb(
|
||||
rgb, alpha, bg_confidence, model, settings.foreground
|
||||
)
|
||||
corrected_rgb, color_mask = despill(foreground.rgb, alpha, model, settings.despill)
|
||||
corrected_rgb, color_mask = despill(foreground, alpha, model, settings.despill)
|
||||
|
||||
metadata = {
|
||||
"alpha_source": alpha_source,
|
||||
|
||||
Reference in New Issue
Block a user