LatentSeal
Fast, secure & high‑capacity semantic image watermarking with text‑autoencoded messages.
Hide full sentences in images, survive heavy JPEG/crop/noise, decode in real time.
Installation
pip install latseal # use `pip install -e .` when developing locally
The first call to latseal.embed(...) or latseal.encode(...) will download
the required TorchScript models and autoencoder checkpoint into
~/.cache/latseal (override with LATSEAL_CACHE_DIR). The download is ~1.5 GB
and only happens once per machine. Set LATSEAL_LOCAL_ONLY=1 to disable
network access and rely on locally provided weights via the LATSEAL_*
environment overrides documented in latseal._resources. By default the assets
are pulled from the Hugging Face repository Gevennou/lseal.
Watermarking and autoencoding can be used independently or chained, depending on your workflow.
Quickstart Demo
Watermarking and text autoencoding demonstrated separately (requires the
requests package):
from pathlib import Path
import requests
import torch
from PIL import Image
import latseal
img_url = "https://images.dog.ceo/breeds/frise-bichon/3.jpg" # 640x640 image
img_path = Path("latseal_demo_input.jpg")
secret_key = "demo-secret"
text_payload = (
"Close-up photograph of a gourmet grilled cheese sandwich that has been artistically sliced in half. Each half reveals a gooey, white cheese center ith an enticing stringy, melted cheese bridge connecting them. The sandwich features double"
)
response = requests.get(img_url, timeout=30)
response.raise_for_status()
img_path.write_bytes(response.content)
image = Image.open(img_path).convert("RGB")
# --- Watermark round-trip ---
message = latseal.random_message()
secret_message = latseal.secret_rotation(message, secret_key=secret_key)
wm_image = latseal.embed(secret_message, image, secret_key=None)
wm_image.save("latseal_demo_watermarked.jpg")
recovered = latseal.detect(wm_image, secret_key=None)
recovered = latseal.secret_rotation(recovered, secret_key=secret_key, inverse=True)
cos_sim = torch.dot(message, recovered) / (message.norm() * recovered.norm())
print(f"Cosine similarity between original and recovered message: {float(cos_sim):.4f}")
# --- Text autoencoder round-trip ---
latent = latseal.encode(text_payload)
decoded = latseal.decode(latent)
score = latseal.confidence(latent)
print(f"Original text: {text_payload}")
print(f"Decoded text : {decoded}")
print(f"Confidence : {score:.3f}")
All-in-One Text Latent Demo
Prefer to hide a specific sentence directly? Encode it, embed the latent, and
report fidelity metrics (requires the requests and numpy packages):
from pathlib import Path
import requests
import torch
from PIL import Image
import latseal
import numpy as np
def psnr(img_a, img_b, max_val=255.0):
"""PSNR in dB for 8-bit RGB PIL images."""
a = np.asarray(img_a, dtype=np.float32)
b = np.asarray(img_b, dtype=np.float32)
mse = np.mean((a - b) ** 2)
if mse == 0:
return float("inf")
return 20 * np.log10(max_val) - 10 * np.log10(mse)
img_url = "https://images.dog.ceo/breeds/frise-bichon/3.jpg" # 640x640 image
img_path = Path("latseal_demo_psnr_input.jpg")
secret_key = "demo-secret"
text_payload = (
"Close-up photograph of a gourmet grilled cheese sandwich that has been artistically sliced in half. Each half reveals a gooey, white cheese center with an enticing stringy, melted cheese bridge connecting them. The sandwich features double"
)
response = requests.get(img_url, timeout=30)
response.raise_for_status()
img_path.write_bytes(response.content)
image = Image.open(img_path).convert("RGB")
latent_message = latseal.encode(text_payload).squeeze(0)
secret_message = latseal.secret_rotation(latent_message, secret_key=secret_key)
wm_image = latseal.embed(secret_message, image, secret_key=None)
wm_image.save("latseal_text_latent_watermarked.jpg")
detected = latseal.detect(wm_image, secret_key=None)
detected = latseal.secret_rotation(detected, secret_key=secret_key, inverse=True).squeeze(0)
print(f"PSNR: {psnr(image, wm_image):.2f} dB")
cos_sim = torch.dot(latent_message, detected) / (latent_message.norm() * detected.norm())
print(f"Cosine similarity: {float(cos_sim):.4f}")
print(f"Decoded text: {latseal.decode(detected)}")
print(f"Confidence: {latseal.confidence(detected)}")
Features
- Content‑aware payload – 256‑D unit‑norm latent vectors from a lightweight text autoencoder (TAE).
- Robust embedding – finetuned watermark model plus a secret invertible rotation (“spin”) boosts security.
- High capacity – > 256 bits (full sentences) per image.
- Confidence score – flags unreliable extractions via the confidence metric.
Citation
@misc{evennou2025fastsecurehighcapacityimage,
title={Fast, Secure, and High-Capacity Image Watermarking with Autoencoded Text Vectors},
author={Gautier Evennou and Vivien Chappelier and Ewa Kijak},
year={2025},
eprint={2510.00799},
archivePrefix={arXiv},
primaryClass={cs.CR},
url={https://arxiv.org/abs/2510.00799},
}
License
BSD-3-Clause-Attribution — see LICENSE.
Model tree for Gevennou/lseal
Base model
answerdotai/ModernBERT-base