Improve despill and add quality checks
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict, dataclass
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class QualityMetrics:
|
||||
path: str
|
||||
width: int
|
||||
height: int
|
||||
alpha_min: int
|
||||
alpha_max: int
|
||||
alpha_mean: float
|
||||
nonzero_alpha_pixels: int
|
||||
edge_pixels: int
|
||||
edge_green_excess_mean: float
|
||||
edge_green_excess_p95: float
|
||||
edge_green_excess_max: float
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return asdict(self)
|
||||
|
||||
|
||||
def measure_rgba(path: str | Path) -> QualityMetrics:
|
||||
image = Image.open(path).convert("RGBA")
|
||||
arr = np.asarray(image).astype(np.float32) / 255.0
|
||||
rgb = arr[..., :3]
|
||||
alpha = arr[..., 3]
|
||||
edge = (alpha > 0.02) & (alpha < 0.98)
|
||||
green_excess = np.maximum(rgb[..., 1] - np.maximum(rgb[..., 0], rgb[..., 2]), 0.0)
|
||||
edge_values = green_excess[edge]
|
||||
if edge_values.size:
|
||||
edge_mean = float(edge_values.mean())
|
||||
edge_p95 = float(np.percentile(edge_values, 95))
|
||||
edge_max = float(edge_values.max())
|
||||
else:
|
||||
edge_mean = edge_p95 = edge_max = 0.0
|
||||
|
||||
alpha_u8 = (alpha * 255.0).round().astype(np.uint8)
|
||||
return QualityMetrics(
|
||||
path=str(path),
|
||||
width=image.width,
|
||||
height=image.height,
|
||||
alpha_min=int(alpha_u8.min()),
|
||||
alpha_max=int(alpha_u8.max()),
|
||||
alpha_mean=float(alpha_u8.mean()),
|
||||
nonzero_alpha_pixels=int((alpha_u8 > 0).sum()),
|
||||
edge_pixels=int(edge.sum()),
|
||||
edge_green_excess_mean=edge_mean,
|
||||
edge_green_excess_p95=edge_p95,
|
||||
edge_green_excess_max=edge_max,
|
||||
)
|
||||
|
||||
|
||||
def assert_quality(
|
||||
metrics: QualityMetrics,
|
||||
max_edge_green_excess_p95: float | None = None,
|
||||
require_alpha_range: bool = True,
|
||||
) -> list[str]:
|
||||
failures: list[str] = []
|
||||
if require_alpha_range:
|
||||
if metrics.alpha_min != 0:
|
||||
failures.append(f"alpha_min is {metrics.alpha_min}, expected 0")
|
||||
if metrics.alpha_max != 255:
|
||||
failures.append(f"alpha_max is {metrics.alpha_max}, expected 255")
|
||||
if metrics.nonzero_alpha_pixels <= 0:
|
||||
failures.append("nonzero alpha pixel count is 0")
|
||||
if (
|
||||
max_edge_green_excess_p95 is not None
|
||||
and metrics.edge_green_excess_p95 > max_edge_green_excess_p95
|
||||
):
|
||||
failures.append(
|
||||
"edge_green_excess_p95 "
|
||||
f"{metrics.edge_green_excess_p95:.4f} exceeds {max_edge_green_excess_p95:.4f}"
|
||||
)
|
||||
return failures
|
||||
Reference in New Issue
Block a user