mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-07-07 17:07:50 +02:00
- Add the Jimeng-basic top-left "AI生成" pill as a CAPTURE-LESS mark (pill_engine.py): synthetic-silhouette edge-NCC detect + inpaint-only removal. Gated in remove_auto_marks: kept only when Jimeng is confirmed (TC260 metadata OR the bottom-right "★ 即梦AI" wordmark fired -- the wordmark keeps recall on metadata-STRIPPED uploads) AND Doubao did not fire. - Add an inpaint-fallback removal path + MI-GAN ONNX backend (migan extra, MIT, ~28 MB / ~1 GB peak -- droplet-friendly) alongside big-LaMa. New --method auto|reverse-alpha|inpaint (shared across visible/all/batch) and erase --backend migan; footprint_mask on each engine. - auto is deterministic: reverse-alpha for capture marks (recovers exact pixels, lighter -- measured cleaner than MI-GAN on structured backgrounds) and inpaint only for the capture-less pill. - --mark auto now removes EVERY detected mark in one pass (remove_auto_marks), so a Jimeng-basic image's top-left pill AND bottom-right wordmark both clear. - Bump 0.12.1 -> 0.13.0. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
"""Render the SYNTHETIC 'AI生成' pill silhouette asset (data-safe, font-rendered).
|
||||
|
||||
The Jimeng-basic TC260 visible label is a rounded pill with 'AI生成' in the TOP-LEFT
|
||||
corner (issue #54). Unlike the reverse-alpha marks, this is a CAPTURE-LESS mark:
|
||||
the committed asset is a font-rendered binary SILHOUETTE (mark shape only, zero photo
|
||||
content), used ONLY to (a) detect the pill by edge-NCC in the top-left corner and
|
||||
(b) build the inpaint mask. It is NOT an alpha map -- removal quality comes from the
|
||||
inpaint backend (MI-GAN/cv2), so the silhouette need not be pixel-accurate, and the
|
||||
synthetic render keeps corpus/user content out of the tracked repo (data-safety).
|
||||
|
||||
Detection was calibrated on the retained local corpus (61 real positives + jimeng
|
||||
negatives): edge-NCC threshold ~0.22 in the top-left ROI. Re-run to regenerate the
|
||||
asset: uv run python scripts/render_pill_silhouette.py
|
||||
|
||||
Requires a CJK font (macOS STHeiti by default); the asset itself is committed, so this
|
||||
script only runs when regenerating it (never in CI).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
_ASSET = Path(__file__).resolve().parents[1] / "src" / "remove_ai_watermarks" / "assets" / "jimeng_pill.png"
|
||||
_FONT = "/System/Library/Fonts/STHeiti Medium.ttc"
|
||||
|
||||
|
||||
def render_silhouette(w: int = 320) -> np.ndarray:
|
||||
"""Rounded-pill outline + 'AI生成' text as a binary silhouette (255 = mark)."""
|
||||
h = int(w * 0.5)
|
||||
im = Image.new("L", (w, h), 0)
|
||||
d = ImageDraw.Draw(im)
|
||||
pad = int(w * 0.03)
|
||||
r = (h - 2 * pad) // 3
|
||||
d.rounded_rectangle([pad, pad, w - pad, h - pad], radius=r, outline=255, width=max(2, w // 90))
|
||||
fsz = int(h * 0.42)
|
||||
font = ImageFont.truetype(_FONT, fsz)
|
||||
txt = "AI生成"
|
||||
tb = d.textbbox((0, 0), txt, font=font)
|
||||
tw, th = tb[2] - tb[0], tb[3] - tb[1]
|
||||
d.text(((w - tw) // 2 - tb[0], (h - th) // 2 - tb[1]), txt, font=font, fill=255)
|
||||
return np.array(im)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
try:
|
||||
sil = render_silhouette()
|
||||
except OSError as e:
|
||||
print(f"Font not found ({e}); install a CJK font or edit _FONT.", file=sys.stderr)
|
||||
raise SystemExit(1) from e
|
||||
_ASSET.parent.mkdir(parents=True, exist_ok=True)
|
||||
Image.fromarray(sil).save(_ASSET)
|
||||
print(f"wrote {_ASSET} ({sil.shape[1]}x{sil.shape[0]})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user