mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-08-31 17:50:35 +02:00
Add calibrated SynthID pixel detector
This commit is contained in:
@@ -1,50 +1,12 @@
|
||||
"""Shared periodic-residual helpers for SynthID research probes."""
|
||||
"""Compatibility imports for shared periodic-residual helpers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from remove_ai_watermarks.synthid_detector import fold_residual_template, unit_tile
|
||||
|
||||
def fold_residual_template(
|
||||
pixels: np.ndarray,
|
||||
*,
|
||||
tile_height: int,
|
||||
tile_width: int,
|
||||
denoise_sigma: float,
|
||||
) -> np.ndarray:
|
||||
"""Estimate a zero-mean periodic residual template by modulo folding."""
|
||||
if pixels.ndim != 3 or pixels.shape[2] != 3:
|
||||
raise ValueError("pixels must have shape (height, width, 3)")
|
||||
if tile_height < 1 or tile_width < 1 or denoise_sigma <= 0.0:
|
||||
raise ValueError("tile dimensions and denoise sigma must be positive")
|
||||
height, width = pixels.shape[:2]
|
||||
if height % tile_height != 0 or width % tile_width != 0:
|
||||
raise ValueError("image geometry must be divisible by the tile geometry")
|
||||
source = pixels.astype(np.float32)
|
||||
denoised = cv2.GaussianBlur(
|
||||
source,
|
||||
(0, 0),
|
||||
sigmaX=denoise_sigma,
|
||||
sigmaY=denoise_sigma,
|
||||
borderType=cv2.BORDER_REFLECT_101,
|
||||
)
|
||||
residual = source - denoised
|
||||
repeats_y = height // tile_height
|
||||
repeats_x = width // tile_width
|
||||
folded = residual.reshape(repeats_y, tile_height, repeats_x, tile_width, 3).mean(
|
||||
axis=(0, 2),
|
||||
dtype=np.float64,
|
||||
)
|
||||
return folded - np.mean(folded, axis=(0, 1), keepdims=True)
|
||||
|
||||
|
||||
def unit_tile(tile: np.ndarray) -> tuple[np.ndarray, float]:
|
||||
"""Return TILE normalized by its L2 norm and the original norm."""
|
||||
norm = float(np.linalg.norm(tile))
|
||||
if norm == 0.0:
|
||||
return np.zeros_like(tile, dtype=np.float64), 0.0
|
||||
return np.asarray(tile, dtype=np.float64) / norm, norm
|
||||
__all__ = ["cyclic_tile_correlations", "fold_residual_template", "unit_tile"]
|
||||
|
||||
|
||||
def cyclic_tile_correlations(template: np.ndarray, tile: np.ndarray) -> np.ndarray:
|
||||
|
||||
Reference in New Issue
Block a user