mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-08-19 20:17:12 +02:00
Add paired wavelet and spectral SynthID probes
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from itertools import combinations
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
@@ -101,3 +102,81 @@ def test_discovery_report_contains_cross_pair_ncc(tmp_path: Path):
|
||||
|
||||
assert report["pair_count"] == 2
|
||||
assert len(report["pairwise"]) == 1
|
||||
assert report["wavelet"]["wavelet"] == "db2"
|
||||
assert len(report["wavelet"]["bands"]) == 9
|
||||
assert report["spectral"]["peaks"]
|
||||
assert report["spectral"]["cepstral_peaks"]
|
||||
assert report["permutation_control"] is not None
|
||||
|
||||
|
||||
def test_wavelet_report_finds_repeatable_multiscale_carrier(tmp_path: Path):
|
||||
first = _write_pair(tmp_path, "first", (96, 96), 100)
|
||||
second = _write_pair(tmp_path, "second", (128, 80), 140)
|
||||
first_residual, _ = probe.pair_residual(*first, size=64)
|
||||
second_residual, _ = probe.pair_residual(*second, size=64)
|
||||
|
||||
report = probe.wavelet_report([first_residual, second_residual])
|
||||
|
||||
assert len(report["bands"]) == 9
|
||||
assert max(max(band["coefficient_ncc"]) for band in report["bands"]) > 0.7
|
||||
assert all(len(band["median_rms"]) == 3 for band in report["bands"])
|
||||
|
||||
|
||||
def test_streaming_pairwise_ncc_matches_explicit_pairs():
|
||||
rng = np.random.default_rng(7)
|
||||
arrays = [rng.normal(size=(16, 16, 3)) for _ in range(5)]
|
||||
normalized = [probe.normalized_channels(values) for values in arrays]
|
||||
|
||||
explicit = np.mean(
|
||||
[probe.channel_ncc(arrays[first], arrays[second]) for first, second in combinations(range(len(arrays)), 2)],
|
||||
axis=0,
|
||||
)
|
||||
squared_norm_sum = np.sum([np.sum(np.square(values), axis=(0, 1)) for values in normalized], axis=0)
|
||||
streamed = probe.pairwise_ncc_from_normalized_sum(
|
||||
np.sum(normalized, axis=0),
|
||||
squared_norm_sum,
|
||||
len(normalized),
|
||||
)
|
||||
|
||||
assert np.allclose(streamed, explicit)
|
||||
|
||||
|
||||
def test_streaming_pairwise_ncc_handles_zero_norm_channels():
|
||||
arrays = [np.zeros((8, 8, 3)), np.zeros((8, 8, 3))]
|
||||
normalized = [probe.normalized_channels(values) for values in arrays]
|
||||
|
||||
streamed = probe.pairwise_ncc_from_normalized_sum(
|
||||
np.sum(normalized, axis=0),
|
||||
np.zeros(3),
|
||||
len(normalized),
|
||||
)
|
||||
|
||||
assert streamed == (0.0, 0.0, 0.0)
|
||||
|
||||
|
||||
def test_spectral_report_finds_injected_frequency(tmp_path: Path):
|
||||
first = _write_pair(tmp_path, "first", (96, 96), 100)
|
||||
second = _write_pair(tmp_path, "second", (128, 80), 140)
|
||||
first_residual, _ = probe.pair_residual(*first, size=64)
|
||||
second_residual, _ = probe.pair_residual(*second, size=64)
|
||||
|
||||
report = probe.spectral_report([first_residual, second_residual])
|
||||
|
||||
assert any(abs(peak["dy"]) == 14 and abs(peak["dx"]) == 14 for peak in report["peaks"])
|
||||
assert report["phase_coherence_p95"] >= report["phase_coherence_median"]
|
||||
|
||||
|
||||
def test_permutation_control_breaks_exact_pair_repeatability(tmp_path: Path):
|
||||
first = _write_pair(tmp_path, "first", (96, 96), 100)
|
||||
second = _write_pair(tmp_path, "second", (128, 80), 140)
|
||||
first_residual, first_measurement = probe.pair_residual(*first, size=64)
|
||||
second_residual, second_measurement = probe.pair_residual(*second, size=64)
|
||||
|
||||
report = probe.permutation_control(
|
||||
[first_residual, second_residual],
|
||||
[first_measurement, second_measurement],
|
||||
)
|
||||
|
||||
assert report is not None
|
||||
assert np.mean(report["true_pair_ncc"]) > np.mean(report["mismatched_pair_ncc"])
|
||||
assert report["mismatched_median_rms"] > report["true_median_rms"]
|
||||
|
||||
Reference in New Issue
Block a user