mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-08-05 13:38:36 +02:00
feat(invisible): protect text automatically by default (#21)
Mirror protect_faces: protect_text defaults to True in invisible_engine and watermark_remover, so the SDXL pipeline detects text per image and switches to Differential Diffusion only when glyphs are found. Text-free inputs fall back to plain img2img with no differential-pipeline load, so the autonomy is free. The CLI now exposes a single off-switch --no-protect-text instead of the positive flag, keeping the interface minimal. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
a0bf62e601
commit
0eec3001bb
@@ -461,10 +461,10 @@ def cmd_erase(
|
||||
help="Cap long side (px) before diffusion; 0 = native (best quality, like raiw.cc). Raise only on GPU/MPS OOM.",
|
||||
)
|
||||
@click.option(
|
||||
"--protect-text",
|
||||
"--no-protect-text",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Preserve detected text (incl. CJK) via Differential Diffusion. SDXL default pipeline only.",
|
||||
help="Disable automatic text protection (text/CJK is preserved by default on the SDXL pipeline).",
|
||||
)
|
||||
@click.pass_context
|
||||
def cmd_invisible(
|
||||
@@ -479,7 +479,7 @@ def cmd_invisible(
|
||||
hf_token: str | None,
|
||||
humanize: float,
|
||||
max_resolution: int,
|
||||
protect_text: bool,
|
||||
no_protect_text: bool,
|
||||
) -> None:
|
||||
"""Remove invisible AI watermarks (SynthID, StableSignature, TreeRing).
|
||||
|
||||
@@ -526,7 +526,7 @@ def cmd_invisible(
|
||||
guidance_scale=None,
|
||||
seed=seed,
|
||||
humanize=humanize,
|
||||
protect_text=protect_text,
|
||||
protect_text=not no_protect_text,
|
||||
max_resolution=max_resolution,
|
||||
)
|
||||
elapsed = time.monotonic() - t0
|
||||
@@ -680,10 +680,10 @@ def cmd_identify(ctx: click.Context, source: Path, no_visible: bool, as_json: bo
|
||||
help="Cap long side (px) before diffusion; 0 = native (best quality, like raiw.cc). Raise only on GPU/MPS OOM.",
|
||||
)
|
||||
@click.option(
|
||||
"--protect-text",
|
||||
"--no-protect-text",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Preserve detected text (incl. CJK) via Differential Diffusion. SDXL default pipeline only.",
|
||||
help="Disable automatic text protection (text/CJK is preserved by default on the SDXL pipeline).",
|
||||
)
|
||||
@click.pass_context
|
||||
def cmd_all(
|
||||
@@ -701,7 +701,7 @@ def cmd_all(
|
||||
hf_token: str | None,
|
||||
humanize: float,
|
||||
max_resolution: int,
|
||||
protect_text: bool,
|
||||
no_protect_text: bool,
|
||||
) -> None:
|
||||
"""Remove ALL watermarks: visible + invisible + metadata.
|
||||
|
||||
@@ -793,7 +793,7 @@ def cmd_all(
|
||||
num_inference_steps=steps,
|
||||
seed=seed,
|
||||
humanize=humanize,
|
||||
protect_text=protect_text,
|
||||
protect_text=not no_protect_text,
|
||||
max_resolution=max_resolution,
|
||||
)
|
||||
console.print(" [green]✓[/] Invisible watermark removed")
|
||||
|
||||
@@ -125,7 +125,7 @@ class InvisibleEngine:
|
||||
seed: int | None = None,
|
||||
humanize: float = 0.0,
|
||||
protect_faces: bool = True,
|
||||
protect_text: bool = False,
|
||||
protect_text: bool = True,
|
||||
max_resolution: int = 0,
|
||||
) -> Path:
|
||||
"""Remove invisible watermark from an image.
|
||||
@@ -139,8 +139,9 @@ class InvisibleEngine:
|
||||
seed: Random seed for reproducibility.
|
||||
humanize: Intensity of Analog Humanizer film grain (0 = off).
|
||||
protect_faces: Boolean to extract and restore faces intact.
|
||||
protect_text: Preserve detected text regions via Differential
|
||||
Diffusion so glyphs (incl. CJK) survive the removal pass.
|
||||
protect_text: Detect text regions and preserve them via Differential
|
||||
Diffusion when any are found, so glyphs (incl. CJK) survive the
|
||||
removal pass. On by default; the detector decides per image.
|
||||
max_resolution: Cap the long side (px) before diffusion. 0 (default)
|
||||
= native resolution, no pre-downscale -- matches the hosted
|
||||
raiw.cc backend. Set a positive value only to bound GPU/MPS
|
||||
|
||||
@@ -387,7 +387,7 @@ class WatermarkRemover:
|
||||
num_inference_steps: int = 50,
|
||||
guidance_scale: float | None = None,
|
||||
seed: int | None = None,
|
||||
protect_text: bool = False,
|
||||
protect_text: bool = True,
|
||||
) -> Path:
|
||||
"""Remove watermark from an image using regeneration attack.
|
||||
|
||||
@@ -398,8 +398,10 @@ class WatermarkRemover:
|
||||
num_inference_steps: Number of denoising steps.
|
||||
guidance_scale: Classifier-free guidance scale.
|
||||
seed: Random seed for reproducibility.
|
||||
protect_text: Preserve detected text regions via Differential
|
||||
Diffusion (SDXL default profile only). Off by default.
|
||||
protect_text: Detect text regions and preserve them via Differential
|
||||
Diffusion when any are found (SDXL default profile only). On by
|
||||
default; the detector decides per image, and text-free inputs run
|
||||
the standard pass at no extra cost.
|
||||
|
||||
Returns:
|
||||
Path to the cleaned image.
|
||||
@@ -458,8 +460,8 @@ class WatermarkRemover:
|
||||
)
|
||||
else:
|
||||
if protect_text:
|
||||
logger.warning(
|
||||
"protect_text requested but unavailable "
|
||||
logger.debug(
|
||||
"Text protection unavailable "
|
||||
"(needs the SDXL default model and the cv2 text detector); "
|
||||
"running standard img2img."
|
||||
)
|
||||
@@ -611,6 +613,10 @@ class WatermarkRemover:
|
||||
logger.warning("Text detection failed (%s); running standard img2img.", exc)
|
||||
return self._run_img2img(init_image, strength, num_inference_steps, guidance_scale, generator)
|
||||
|
||||
if not boxes:
|
||||
self._set_progress("No text detected; running standard img2img.")
|
||||
return self._run_img2img(init_image, strength, num_inference_steps, guidance_scale, generator)
|
||||
|
||||
width, height = init_image.size
|
||||
change_map = text_protector.build_change_map(boxes, height, width)
|
||||
self._set_progress(f"Protecting {len(boxes)} text region(s) via Differential Diffusion...")
|
||||
|
||||
Reference in New Issue
Block a user