Klaus Clawd
Initial public release: VEIL-PGD v0.1
c793f45
Raw
History Blame Contribute Delete
1.59 kB
"""The hard stealth gate: pass/fail against configured thresholds."""
from __future__ import annotations
from typing import Callable, Optional
from PIL import Image
from veil_pgd.config import StealthThresholds, get_settings
from veil_pgd.stealth import metrics as m
from veil_pgd.types import StealthReport
# A LPIPS provider is injected (klaus-3 service). If absent, LPIPS is skipped
# (treated as passing) and noted so the gate degrades gracefully offline.
LpipsFn = Callable[[Image.Image, Image.Image], float]
def evaluate_stealth(
orig: Image.Image,
mod: Image.Image,
box: Optional[tuple[int, int, int, int]] = None,
thresholds: Optional[StealthThresholds] = None,
lpips_fn: Optional[LpipsFn] = None,
) -> StealthReport:
th = thresholds or get_settings().stealth
psnr_v = m.psnr(orig, mod)
ssim_v = m.ssim(orig, mod)
de_v = m.delta_e_p95(orig, mod, box)
lpips_v = lpips_fn(orig, mod) if lpips_fn is not None else float("nan")
failures: list[str] = []
if psnr_v < th.psnr_min:
failures.append(f"psnr {psnr_v:.1f}<{th.psnr_min}")
if ssim_v < th.ssim_min:
failures.append(f"ssim {ssim_v:.3f}<{th.ssim_min}")
if de_v > th.delta_e_p95_max:
failures.append(f"dE {de_v:.2f}>{th.delta_e_p95_max}")
if lpips_fn is not None and lpips_v > th.lpips_max:
failures.append(f"lpips {lpips_v:.3f}>{th.lpips_max}")
return StealthReport(
psnr=psnr_v,
ssim=ssim_v,
lpips=lpips_v,
delta_e_p95=de_v,
passed=len(failures) == 0,
failures=failures,
)