mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-08-07 06:28:36 +02:00
feat(auto): adaptive detail-targeting polish + --adaptive-polish flag
The fixed mild auto polish (unsharp 0.5 / grain 2.0) under-corrected soft photo/face output (gemini_3 stayed at lap-var 84 vs its 592 original) and its grain speckled small text. Replace it with humanizer.adaptive_polish: target the input's Laplacian variance with a capped unsharp scaled to the deficit + edge- masked grain (smooth regions only), calibrated by a short sigma search. Self- limiting on text/graphics -- already high-frequency, so almost no polish lands and text edges are masked out. Validated on the spaces corpus (gemini_3 84 -> 334 end-to-end; openai_1 text near-untouched). Interface: every --auto decision is now independently overridable -- add --adaptive-polish/--no-adaptive-polish (matching --restore-faces; works without --auto too) so the polish can be disabled or used manually. _apply_auto overrides exactly the three content-adaptive modes (pipeline, restore-faces, adaptive- polish); --unsharp/--humanize stay independent fixed filters. cv2-only, no new deps. Threaded through invisible/all (not batch). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9bd2c17cc4
commit
b686dbdd79
@@ -141,6 +141,7 @@ class InvisibleEngine:
|
||||
restore_faces: bool = False,
|
||||
restore_faces_weight: float = 0.5,
|
||||
unsharp: float = 0.0,
|
||||
adaptive_polish: bool = False,
|
||||
) -> Path:
|
||||
"""Remove invisible watermark from an image.
|
||||
|
||||
@@ -163,6 +164,12 @@ class InvisibleEngine:
|
||||
Applied last (after face restoration) to counter the soft,
|
||||
over-smoothed look of the diffusion/GFPGAN passes; ~0.5-0.8 is a
|
||||
safe range, higher risks edge halos.
|
||||
adaptive_polish: When True (the --auto mode default), restore the input's
|
||||
detail level in the softened output instead of fixed unsharp/humanize:
|
||||
a capped unsharp + edge-masked grain targeting the input's Laplacian
|
||||
variance (self-limiting on text/graphics). Runs LAST, after face
|
||||
restoration. The fixed ``humanize``/``unsharp`` knobs are normally 0
|
||||
when this is on.
|
||||
max_resolution: Cap the long side (px) before diffusion. 0 (default)
|
||||
= no cap. Set a positive value only to bound GPU/MPS memory on
|
||||
very large inputs (it reintroduces a lossy downscale->upscale
|
||||
@@ -189,6 +196,9 @@ class InvisibleEngine:
|
||||
image = Image.open(image_path)
|
||||
image = ImageOps.exif_transpose(image)
|
||||
orig_size = image.size # (width, height)
|
||||
# Full-res original, kept for the adaptive-polish detail target (image is
|
||||
# reassigned to the resized copy below; PIL resize returns a new object).
|
||||
reference_pil = image
|
||||
|
||||
target = _target_size(image.width, image.height, max_resolution, min_resolution)
|
||||
if target is not None:
|
||||
@@ -287,6 +297,23 @@ class InvisibleEngine:
|
||||
self._progress_callback(f"Sharpening (unsharp mask: {unsharp})...")
|
||||
image_io.imwrite(out_path, unsharp_mask(out_cv, amount=unsharp))
|
||||
|
||||
# Adaptive polish (--auto): restore the input's detail level in the softened
|
||||
# output, sparing text/edges. Replaces the fixed unsharp/humanize knobs.
|
||||
if adaptive_polish:
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from remove_ai_watermarks import humanizer, image_io
|
||||
|
||||
out_cv = image_io.imread(out_path, cv2.IMREAD_COLOR)
|
||||
if out_cv is not None:
|
||||
ref = cv2.cvtColor(np.array(reference_pil.convert("RGB")), cv2.COLOR_RGB2BGR)
|
||||
if (ref.shape[1], ref.shape[0]) != (out_cv.shape[1], out_cv.shape[0]):
|
||||
ref = cv2.resize(ref, (out_cv.shape[1], out_cv.shape[0]), interpolation=cv2.INTER_LANCZOS4)
|
||||
if self._progress_callback:
|
||||
self._progress_callback("Adaptive polish (sharpen + grain to the input's detail level)...")
|
||||
image_io.imwrite(out_path, humanizer.adaptive_polish(out_cv, ref, seed=seed))
|
||||
|
||||
return out_path
|
||||
finally:
|
||||
# _tmp_path is always set above (we persist the image unconditionally).
|
||||
|
||||
Reference in New Issue
Block a user