"""Kling (可灵, Kuaishou) visible watermark detector/localizer. Kling stamps its generations with a thin, light-gray "可灵AI 3.0" text strip in the bottom-right corner, preceded by the vendor's spiral logo (not part of the detection silhouette -- logos vary between releases, the text run is what discriminates). Known variants: an "Omni" suffix release, a latin "KlingAI 3.0" release, and a version-less "可灵AI" -- the silhouette targets the common "可灵AI 3.0" core, so the suffix variants are only caught when the core run is bold enough (measured below). Detection matches the bundled glyph silhouette against the corner; removal is the shared **localize -> fill** (the glyph-bbox :meth:`footprint_mask` feeds ``region_eraser``), NOT reverse-alpha. This module supplies only Kling's tuned :class:`TextMarkConfig` (``assets/kling_alpha.png`` -- a font-rendered synthetic silhouette from ``scripts/render_vendor_silhouettes.py``, never cut from an upload). It also feeds ``identify`` as the medium-confidence ``visible_kling`` signal via the registry. EVERY tuned number below was measured on the vendor cohort (30 TC260 carriers whose producer USCC 91110108335469089C names the entity, 2026-07-21; harness ``scripts/vendor_mark_calibrate.py``), NOT inherited from Doubao: * The mark scales with the SHORT side at ~0.12 of it (mark_w/short measured 0.118-0.122 across portrait AND landscape carriers -- unimodal, so the shipped 3-rung ladder covers it) and sits ~0.03 off the right/bottom edges; the locate box fractions below are fitted from the measured absolute mark rects. * ``alpha_height_frac`` comes from the silhouette aspect (0.239) at the fitted width, matching the aspect the fit converged on (0.25). * Gate 0.35, one step above the clean arm's max: on the cohort-vs-clean run (cohort-contamination-guarded, 286 hand-labelled clean frames) the clean arm scored p99 0.304 / max 0.320, and every cohort frame >= 0.35 carries a visible 可灵AI 3.0 mark (9 of ~19 eyeballed visible marks fire = ~47% recall of visible marks; the misses are the faint "Omni"-suffix release, the latin "KlingAI" release and the version-less "可灵AI", which score 0.17-0.25 and cannot be reached without engulfing the clean arm). * STRICT ONLY (``provenance_ncc_factor`` 1.0): the sub-gate band holds real Kling variants AND the clean arm's top (clean p90 0.220 vs variant marks at 0.17-0.25 -- they overlap), so a provenance-relaxed arm cannot separate them. No provenance relaxation exists for this mark. * No rival margin: at the shipped gate the template fires on 1 of 400 Doubao-marked frames (0.2%, a 豆包 frame sitting INSIDE the Kling cohort, still below the gate), 0 of 298 Jimeng-marked frames and 0 of 286 hand-labelled clean frames, and a 0.10 rival margin costs zero genuine Kling detections -- so it is simply unnecessary (same conclusion shape as Qwen). """ # The module-level _alpha_template / _glyph_silhouette / _template_match_score below # are thin test-facing shims (imported by tests/), so pyright's src-only pass sees them # as unused; the use is cross-module. # pyright: reportUnusedFunction=false from __future__ import annotations from typing import TYPE_CHECKING, Any from remove_ai_watermarks import _text_mark_engine from remove_ai_watermarks._text_mark_engine import TextMarkConfig, TextMarkEngine if TYPE_CHECKING: from numpy.typing import NDArray # Locate geometry as a fraction of the image SHORT side (measured basis -- see # scale_base). The box is fitted to the measured mark rects: the mark's right # margin is ~0.034 of the short side and its bottom margin ~0.027; width/height # cover the mark plus NCC slack. WM_WIDTH_FRAC = 0.19 WM_HEIGHT_FRAC = 0.05 MARGIN_RIGHT_FRAC = 0.03 MARGIN_BOTTOM_FRAC = 0.023 # Glyph appearance: a light, low-saturation gray rendered brighter than the local # background (white top-hat), same overlay class as Doubao -- inherited, and # harmless because the tophat front-end turns these gates into weights. MAX_SATURATION = 55 LOGO_MIN_LUMA = 150 TOPHAT_DELTA = 12 DETECT_MIN_COVERAGE = 0.04 # unused by the tophat front-end (kept for config parity) # Calibrated 2026-07-21 on the vendor cohort vs 286 hand-labelled clean frames # (cohort-contamination-guarded): clean p99 0.304 / max 0.320, and every cohort # frame scoring >= 0.35 carries a visible 可灵AI 3.0 mark. 0.35 was picked over # 0.33 (also zero clean fires) for margin against unseen clean content at a cost # of zero measured cohort detections. DETECT_NCC_THRESHOLD = 0.35 # Detection-silhouette geometry (fraction of the short side), fitted on the # cohort: the mark's width (0.12, unimodal) and the silhouette aspect (0.239). _ALPHA_WIDTH_FRAC = 0.12 _ALPHA_HEIGHT_FRAC = 0.0287 _CONFIG = TextMarkConfig( name="Kling", asset_name="kling_alpha.png", corner="br", margin_floor=4, width_frac=WM_WIDTH_FRAC, height_frac=WM_HEIGHT_FRAC, margin_x_frac=MARGIN_RIGHT_FRAC, margin_bottom_frac=MARGIN_BOTTOM_FRAC, max_saturation=MAX_SATURATION, logo_min_luma=LOGO_MIN_LUMA, tophat_delta=TOPHAT_DELTA, morph_open_size=5, detect_min_coverage=DETECT_MIN_COVERAGE, detect_ncc_threshold=DETECT_NCC_THRESHOLD, detect_frontend="tophat", scale_basis="short", # measured: mark_w/short 0.118-0.122 across orientations alpha_width_frac=_ALPHA_WIDTH_FRAC, alpha_height_frac=_ALPHA_HEIGHT_FRAC, min_gw=8, # STRICT ONLY: the sub-gate band (real Kling variants at 0.17-0.25) overlaps # the clean arm's top (p90 0.220), so provenance relaxation is disabled # outright (factor 1.0 = never relaxed). provenance_ncc_factor=1.0, ) def _alpha_template() -> NDArray[Any] | None: """The bundled Kling alpha template (float [0,1]), or None.""" return _text_mark_engine.load_alpha_template(_CONFIG.asset_name) def _glyph_silhouette() -> NDArray[Any] | None: """Binary "可灵AI 3.0" silhouette (255 = glyph) from the alpha map, or None.""" return _text_mark_engine.glyph_silhouette(_CONFIG.asset_name) class KlingEngine(TextMarkEngine): """Detect/localize the visible Kling "可灵AI 3.0" watermark (locate -> mask; mask feeds the fill).""" def __init__(self) -> None: super().__init__(_CONFIG)