mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-09-01 02:00:36 +02:00
Record pipeline-lattice reframing and registered-v3 phase lock
Document that the pixel route detects an origin-anchored lattice rather than the watermark, and record the registered-v3 two-pixel phase-lock measurement: a 2px diagonal crop killed all 36 tested detections (28 foreign-generator, 8 Google) with recovery only at offsets that are multiples of four. Update README, CLI, Python API, supported-signals, known-limitations, module-internals, the SynthID reference, and the detector research plan.
This commit is contained in:
+53
-21
@@ -57,36 +57,58 @@ remove-ai-watermarks identify image.png --no-visible
|
||||
```
|
||||
|
||||
Despite the historical option name, `--no-visible` skips all pixel detectors,
|
||||
including the supported SynthID carrier, visible marks, open DWT-DCT, and
|
||||
including the pipeline lattice described below, visible marks, open DWT-DCT, and
|
||||
TrustMark. Metadata inspection still runs.
|
||||
|
||||
## Detect the supported SynthID pixel carrier
|
||||
## Detect the generation-pipeline pixel lattice (experimental)
|
||||
|
||||
```bash
|
||||
remove-ai-watermarks detect-synthid image.png
|
||||
remove-ai-watermarks detect-synthid image.png --json
|
||||
remove-ai-watermarks detect-synthid resized.png --register-scale
|
||||
remove-ai-watermarks detect-synthid native-period.png --fixed-period
|
||||
```
|
||||
|
||||
The command returns one of `detected`, `not_detected`, or `unsupported`. The
|
||||
runtime detector covers one frozen periodic carrier family in the
|
||||
This route is experimental. Signed provenance, read by `identify` and confirmed
|
||||
against the provider by `verify-openai-synthid`, remains the supported way to
|
||||
establish SynthID. The command returns one of `detected`, `indeterminate`, or
|
||||
`unsupported`, and it does not detect the SynthID watermark: its statistic disappears when the image
|
||||
is cropped off the tile grid, and it changes when the generator's pipeline
|
||||
changes, so read a positive as evidence about the pipeline and never as a
|
||||
watermark claim. The JSON carries `identifies_watermark` and
|
||||
`tile_aligned_crop_required` for exactly this reason. The
|
||||
runtime detector covers one frozen periodic lattice family in the
|
||||
[calibrated image-size range](synthid.md#32-how-our-tool-detects-the-supported-carrier)
|
||||
and needs the `pixels` extra. The native default uses the fixed fold from
|
||||
1,000,000 through 10,000,000 decoded pixels and the separately challenged
|
||||
opponent-color large branch above 10,000,000 through 18,000,000 pixels when
|
||||
both sides are at least 2,048 pixels. It never resizes the input and does not
|
||||
register a carrier whose sampling period changed through spatial resampling.
|
||||
`--register-scale` enables a substantially slower bounded search over measured
|
||||
carrier periods for images from 250,000 through 10,000,000 decoded pixels, with
|
||||
both sides at least 64 pixels. It is opt-in and is not used by `identify`.
|
||||
The measured positive scale range is approximately 0.65 through 1.5; 0.5x
|
||||
resizes are not reliably detected.
|
||||
The native large branch is also codec-sensitive: same-size JPEG-95 and JPEG-90
|
||||
re-encoding reduced its seven official large positives from 7/7 to 0/7. A miss
|
||||
on a lossy re-encode is therefore inconclusive.
|
||||
It is positive-only: `not_detected` means the score stayed below this detector's
|
||||
threshold, while `unsupported` means the image geometry is outside its scope.
|
||||
Neither result proves that another SynthID epoch or payload is absent.
|
||||
and needs the `pixels` extra. The production default uses registered-v3 from
|
||||
250,000 through 10,000,000 decoded pixels with both sides at least 256 pixels.
|
||||
An opponent-registered-v1 fallback covers 1 through 10 megapixels, both sides
|
||||
at least 768 pixels, and selected carrier periods 7.9 through 12.0. Period-8
|
||||
candidates must also pass an opponent-color block-edge veto for the native JPEG
|
||||
lattice. The
|
||||
separately challenged opponent-color large-v1 branch covers above 10,000,000
|
||||
through 18,000,000 pixels when both sides are at least 2,048 pixels.
|
||||
Registered-v3 performs a bounded carrier-period search and independent split-
|
||||
patch confirmation. Its measured positive
|
||||
scale range is approximately 0.65 through 1.5. The fallback recovered 49/49
|
||||
lossless 0.5x-0.75x views from seven official positives. Its period-8 veto
|
||||
rejected 1,790 codec-lattice crossings, and 350 matched 0.5x controls produced no
|
||||
base crossing. The earlier period-band rule accepted 0/1,000 post-freeze Picsum
|
||||
controls. `identify` uses this production router.
|
||||
|
||||
`--fixed-period` explicitly selects the faster legacy fixed-v2 diagnostic below
|
||||
10 megapixels. It does not resize or register the carrier and is not a
|
||||
production positive route. `--register-scale` forces the registered-v3 cascade,
|
||||
including its opponent fallback, on geometry where the default would select
|
||||
large-v1.
|
||||
The native large and opponent-registered branches are codec-sensitive. The
|
||||
large branch fell from 7/7 to 0/7 after same-size JPEG-95 or JPEG-90; the
|
||||
fallback retained 0/63 JPEG-95, JPEG-85, and WebP-95 views. A miss on a lossy
|
||||
re-encode is therefore inconclusive.
|
||||
It is positive-only: `indeterminate` means the score stayed below this
|
||||
detector's threshold, while `unsupported` means the image geometry is outside
|
||||
its scope. Neither result proves that another SynthID epoch or payload is
|
||||
absent.
|
||||
JSON output includes the exact reason plus provider scope, backend, pixel
|
||||
preservation, and metadata-use audit fields.
|
||||
|
||||
## Verify OpenAI SynthID from pixels
|
||||
|
||||
@@ -110,6 +132,16 @@ Retention, `--acknowledge-upload` is mandatory. This command is never called by
|
||||
`identify`. `not_detected` means only that OpenAI's verifier did not recognize a
|
||||
supported watermark in this file; it is not proof of human authorship.
|
||||
|
||||
The built-in client bounds the request at 120 seconds and disables automatic
|
||||
SDK retries, so one acknowledgement cannot silently upload the media multiple
|
||||
times. A timeout, disconnect, malformed response, access failure, or rate limit
|
||||
is an error, never a negative watermark verdict. API failures expose status,
|
||||
error code, request id, `Retry-After`, and whether an explicit caller-controlled
|
||||
retry is appropriate through `OpenAIProvenanceError`; the verifier itself never
|
||||
retries an upload.
|
||||
The JSON result uses the same provider-scope, backend, pixel-preservation, and
|
||||
metadata-use audit fields as the local detector.
|
||||
|
||||
The Python API enforces the same boundary with the required explicit intent
|
||||
flag `verify_openai_synthid(path, acknowledge_upload=True)`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user