Add stratified watermark benchmark and resource profiling

This commit is contained in:
Victor Kuznetsov committed 2026-09-06 20:18:48 -07:00
1 parent dc8491a6c6
commit 68b56ece37
21 files changed
+1869 -256

No files matched your search

+25 -8
View File
@@ -35,7 +35,7 @@ import tempfile
import time
from collections import Counter
from dataclasses import dataclass
from functools import cache, lru_cache
from functools import cache
from pathlib import Path
from typing import TYPE_CHECKING, Any, Literal, Protocol, cast
@@ -352,10 +352,16 @@ def _detect_dwt_dct(path: Path, image: NDArray[Any]) -> str | None:
return detect_invisible_watermark(path, image=to_bgr(image))
def _detect_trustmark(path: Path, _image: NDArray[Any]) -> str | None:
from remove_ai_watermarks.trustmark_detector import detect_trustmark
def _detect_trustmark(path: Path, image: NDArray[Any]) -> str | None:
import cv2
import numpy as np
from PIL import Image
return detect_trustmark(path)
from remove_ai_watermarks.image_io import to_bgr
from remove_ai_watermarks.trustmark_detector import detect_trustmark_image
rgb = cv2.cvtColor(to_bgr(image), cv2.COLOR_BGR2RGB)
return detect_trustmark_image(Image.fromarray(np.ascontiguousarray(rgb), "RGB"), source=path)
def default_adapters() -> dict[str, DetectorAdapter]:
@@ -422,7 +428,7 @@ def _image_fidelity(
import numpy as np
reference = reference_decoder(case.reference_path)
reference = artifact if case.reference_path == case.path else reference_decoder(case.reference_path)
if artifact is None or reference is None:
return {"status": "not_measured", "reason": "decoded_pixels_unavailable"}
if artifact.shape != reference.shape:
@@ -505,6 +511,7 @@ def evaluate_case(
*,
adapters: Mapping[str, DetectorAdapter],
repository: Mapping[str, str | bool],
artifact_decoder: Callable[[Path], NDArray[Any] | None] = _decode_image,
reference_decoder: Callable[[Path], NDArray[Any] | None] = _decode_image,
clock_ns: Callable[[], int] = time.perf_counter_ns,
) -> dict[str, Any]:
@@ -513,7 +520,7 @@ def evaluate_case(
adapter = adapters[case.adapter]
except KeyError as exc:
raise ValueError(f"unknown adapter {case.adapter!r}") from exc
artifact = _decode_image(case.path)
artifact = artifact_decoder(case.path)
adapter_elapsed_ms: float | None = None
if artifact is None:
outcome = DetectorOutcome(status="error", label=None, error="artifact could not be decoded")
@@ -585,7 +592,16 @@ def run_benchmark(manifest: Path, output: Path) -> Counter[str]:
raise ValueError(f"unknown adapters: {', '.join(unknown)}")
repository = repository_state()
counts: Counter[str] = Counter()
reference_decoder = lru_cache(maxsize=8)(_decode_image)
path_counts = Counter(case.path for case in cases)
path_counts.update(case.reference_path for case in cases if case.reference_path is not None)
recurring_images: dict[Path, NDArray[Any] | None] = {}
def decode_image(path: Path) -> NDArray[Any] | None:
if path_counts[path] < 2:
return _decode_image(path)
if path not in recurring_images:
recurring_images[path] = _decode_image(path)
return recurring_images[path]
def records() -> Iterable[dict[str, Any]]:
for case in cases:
@@ -593,7 +609,8 @@ def run_benchmark(manifest: Path, output: Path) -> Counter[str]:
case,
adapters=adapters,
repository=repository,
reference_decoder=reference_decoder,
artifact_decoder=decode_image,
reference_decoder=decode_image,
)
counts[record["detection"]["status"]] += 1
yield record