Industrial-grade invisible watermarking for images and video. Survives crop, rotate, JPEG and screenshots — recovers a key-bound message — runs entirely on CPU.
PhantomMark embeds an imperceptible, cryptographically-keyed watermark into an image using four redundant signal layers (spatial / DCT / DWT / LSB). It was built to fix the one failure that kills classical frequency-domain watermarks — phase sensitivity to crop and rotation — while keeping detection purely mathematical (Pearson r → p-value, folded-NCC) so anyone can verify a mark without a GPU or a neural detector.
from phantommark import PhantomMarkV7
key = b"32-byte-secret-key-here!!" # your tenant secret
wm = PhantomMarkV7(secret_key=key)
result = wm.embed(image, message="Copyright Acme 2026")
detection = wm.detect(result.watermarked)
detection.detected # True
detection.message # "Copyright Acme 2026"
detection.confidence # folded-NCC score after geometric alignmentEvery watermarking family has a fatal hole. PhantomMark is a hybrid that avoids each one.
| Family | Examples | Fatal weakness |
|---|---|---|
| Pixel-space | SynthID, StegaStamp | regeneration / adversarial, needs a neural detector |
| Frequency-domain | classic DWT/DCT | phase-sensitive — crop/rotate/scale zero the correlation |
| Neural decoder | Stable Signature, TrustMark | GPU required, white-box adversarial attack |
| Semantic (initial-noise) | Tree-Ring | needs model inversion, weak multi-key, SemanticRegen |
PhantomMark keeps the verifiability and CPU-only footprint of the frequency domain, but adds a geometric sync layer so the mark survives the spatial attacks that destroy pure frequency schemes.
| # | Feature | Why it matters |
|---|---|---|
| 1 | Geometric robustness | folded-NCC sync + bounded angle×scale search — survives crop/rotate/scale/screenshot |
| 2 | Four redundant layers | spatial + DCT + DWT + LSB — no single attack removes all of them |
| 3 | Perceptual masking (v7) | texture-aware energy placement — invisible on flat regions, no grain |
| 4 | Mathematical detection | Pearson r → p-value, folded-NCC — no GPU, no trainable detector to adversarially fool |
| 5 | Multi-tenant keys | HMAC-derived per-tenant marks that never cross-detect |
| 6 | Message recovery | 16-byte payload + Reed-Solomon ECC + HMAC integrity |
| 7 | Video support | per-frame embedding + temporal HMAC binding against frame-drop |
| 8 | Zero ML dependencies | pure NumPy/SciPy/OpenCV — runs anywhere, auditable end-to-end |
Four signal layers are embedded sequentially into the luminance channel, each tuned to survive a different attack class:
flowchart TD
IMG[Image] --> YC[RGB → YCrCb, luminance Y]
YC --> L0[L0 · Spatial sync pilot<br/>full amplitude, tiled 64×64]
L0 --> L1[L1 · Block DCT 8×8<br/>mid-frequency coefficients]
L1 --> L2[L2 · DWT Haar ×3<br/>wavelet coefficients]
L2 --> L3[L3 · LSB + Reed-Solomon ECC<br/>message recovery]
L3 --> OUT[Watermarked image]
Detection first aligns the image (recovering rotation and scale), then correlates each layer independently:
flowchart LR
I[Image] --> A[align<br/>folded-NCC × angle/scale search]
A --> INV[invert geometry]
INV --> S[sync score]
INV --> D[DCT correlation]
INV --> W[DWT correlation]
INV --> L[LSB + ECC + HMAC]
S --> C{consensus}
D --> C
W --> C
L --> C
C --> R[DetectionResult]
Perceptual masking (v7) redistributes energy toward high-texture regions, keeping the mark invisible on flat areas without losing total signal:
flowchart LR
Y[Luminance Y] --> S[Sobel gradient]
S --> G[Gaussian blur 21×21]
G --> N[Normalize · 95th percentile]
N --> F[Clip to floor]
F --> M[Mask M ∈ 0.15..1]
M --> E[Weight every layer by M]
pip install -e ".[dev]" # installs numpy, opencv, scipy, pywavelets, pillowimport hashlib
from phantommark import PhantomMarkV7
from phantommark.attacks import attack, load_image
wm = PhantomMarkV7(secret_key=hashlib.sha256(b"tenant-a").digest())
image = load_image("demo/stock_1062.jpg")
result = wm.embed(image, message="Copyright Acme")
print(f"PSNR {result.psnr:.1f} dB, SSIM {result.ssim:.4f}")
for atype, strength in [("jpeg", 0.7), ("rotate", 0.5), ("crop", 0.3)]:
attacked = attack(result.watermarked, atype, strength)
d = wm.detect(attacked)
print(f"{atype:8s} {strength:.1f} → detected={d.detected}")pytest # unit suite (16 tests)
python scripts/benchmark.py # v6 vs v7 across 34 attacks
python scripts/cross_key_test.pyReproducible numbers from scripts/benchmark.py (34 attacks, identical set):
| Metric | v5 | v6 | v7 |
|---|---|---|---|
| Survival | 47% (16/34) | 91% (31/34) | 91% (31/34) |
| PSNR (dB) | 47.7 | 36.0 | ~36.0 |
| Crop | ❌ | ✅ | ✅ |
| Rotate (2.25°–40.5°) | ❌ | ✅ | ✅ |
| JPEG 0.5 / 0.7, blur, regenerate, median | ❌ | ✅ | ✅ |
| Flat-region visibility | — | grain | much cleaner |
Visual proof — original vs watermarked (v7), difference amplified ×8 and ×20 to show the mark is invisible at normal viewing and concentrated in texture:
Each row marks its leader in bold — the system that is strongest on that criterion. This is an honest cross-section: no scheme wins everything.
| Criterion | PhantomMark | SynthID | Stable Sig. | Tree-Ring | StegaStamp | TrustMark | Digimarc | DWT/DCT |
|---|---|---|---|---|---|---|---|---|
| Open source | ✅ MIT | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| CPU-only (no GPU/ML) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ? | ✅ |
| JPEG / compression | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Crop / rotate / scale | ✅ | ✅ | ✅ | ✅ | ❌ | |||
| Print → camera | ❌ | ❌ | ❌ | ❌ | ✅ 98.7% | ✅ | ❌ | |
| Regeneration resistance | ❌ | ❌ | ❌ | ❌ | ? | ❌ | ||
| Adversarial (gradient) | ❌ | ❌ | ❌ | ? | ❌ | |||
| False positives | ✅ p<1e-5 | ✅ | ✅ FPR<1e-6 | ✅ | ✅ | ? | ||
| Multi-tenant keys | ✅ HMAC | ❌ | ? | |||||
| Payload | 16 B | presence | 48 bit | presence | 56 bit | 100 bit | ? | ~100 bit |
| Year | 2026 | 2023 | 2023 | 2023 | 2020 | 2023 | 1995+ | 1990s |
Reading the table:
- Open + CPU-only — PhantomMark is the only scheme you can fully audit and run without a neural runtime; SynthID and Digimarc are closed.
- Geometry — Tree-Ring's semantic rings are the strongest against rotation/crop in isolation, but they require model inversion and break under multi-key use (RingID).
- Print→camera — StegaStamp is the gold standard (trained end-to-end on the print-scan channel); PhantomMark targets digital→digital.
- Regeneration & adversarial — nobody survives a determined regeneration; PhantomMark's DCT/DWT layers and mathematical detector hold out longer than neural/pixel schemes, which is why those cells are the "best in class" even though they're partial.
Full per-system analysis and the attack→defense mapping are in docs/COMPARISON.md.
phantommark/
├── __init__.py public API (PhantomMarkV7, V6, VideoWatermark)
├── core.py primitives: ECC, payload, pilot, 4 signal layers
├── detection.py geometric sync: folded-NCC + angle/scale search
├── attacks.py attack simulation + image I/O
├── v6.py PhantomMarkV6 engine
├── v7.py PhantomMarkV7 engine (+ perceptual masking)
└── video.py VideoWatermark (per-frame + temporal binding)
legacy/ historical engines (v5/v6) kept for benchmarking
scripts/ benchmarks, cross-key tests, asset generators
tests/ pytest suite (16 tests)
docs/ ARCHITECTURE · BENCHMARK · COMPARISON · THREAT_MODEL
assets/ README figures
demo/ sample images
PhantomMark raises the cost of removing or forging a mark, but no image watermark survives a determined, adaptive regeneration (see docs/THREAT_MODEL.md). For high-value provenance, pair it with C2PA/Content Credentials or a signed ledger, and treat detection as a signal to escalate — not proof in isolation. Read SECURITY.md for the full honest statement.
| Doc | Contents |
|---|---|
| docs/ARCHITECTURE.md | layers, perceptual masking, detection pipeline, multi-tenancy |
| docs/BENCHMARK.md | reproducible numbers, attack catalog |
| docs/COMPARISON.md | deep per-system analysis with sources |
| docs/THREAT_MODEL.md | assets, adversaries, defenses, fundamental limits |
MIT © 2026 AnnenkovLabs.


