mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-07-15 12:17:19 +02:00
fix(gemini): no-op remove_watermark when nothing detected
Reverse alpha blending applied at the assumed default position painted a visible inverse-sparkle artifact onto clean or edited images. The function now returns an unmodified copy when detection fails, instead of falling back to the hardcoded Gemini corner. Bump to 0.3.5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "remove-ai-watermarks"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
description = "Remove visible and invisible AI watermarks from images (Gemini / Nano Banana, ChatGPT, Stable Diffusion)"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@@ -309,12 +309,19 @@ class GeminiEngine:
|
||||
) -> NDArray:
|
||||
"""Remove Gemini visible watermark from an image using reverse alpha blending.
|
||||
|
||||
No-op when the detector does not find a watermark: returns an unmodified
|
||||
copy. Reverse alpha blending applied where no sparkle exists creates a
|
||||
visible inverse artifact, so we refuse to touch pixels without a positive
|
||||
detection. To bypass detection (e.g. you know the exact region), use
|
||||
``remove_watermark_custom``.
|
||||
|
||||
Args:
|
||||
image: BGR image as numpy array (will NOT be modified in-place).
|
||||
force_size: Force a specific watermark size (auto-detect if None).
|
||||
|
||||
Returns:
|
||||
Cleaned BGR image as numpy array.
|
||||
Cleaned BGR image as numpy array, or an unmodified copy when no
|
||||
watermark is detected.
|
||||
"""
|
||||
result = image.copy()
|
||||
|
||||
@@ -324,35 +331,28 @@ class GeminiEngine:
|
||||
elif result.shape[2] == 1:
|
||||
result = cv2.cvtColor(result, cv2.COLOR_GRAY2BGR)
|
||||
|
||||
h, w = result.shape[:2]
|
||||
size = force_size or get_watermark_size(w, h)
|
||||
size = force_size or get_watermark_size(result.shape[1], result.shape[0])
|
||||
|
||||
# Detect dynamic position & size
|
||||
detection = self.detect_watermark(image, force_size=size)
|
||||
|
||||
# If the confidence is really high (>0.15), use the dynamically detected position and size.
|
||||
if detection.confidence > 0.15:
|
||||
pos = (detection.region[0], detection.region[1])
|
||||
alpha_map = self.get_interpolated_alpha(detection.region[2])
|
||||
if not detection.detected:
|
||||
logger.debug(
|
||||
"Using dynamic watermark position (%d, %d) at size %dx%d [conf=%.3f]",
|
||||
pos[0],
|
||||
pos[1],
|
||||
detection.region[2],
|
||||
detection.region[3],
|
||||
"No watermark detected (conf=%.3f); returning image unchanged.",
|
||||
detection.confidence,
|
||||
)
|
||||
else:
|
||||
config = get_watermark_config(w, h)
|
||||
pos = config.get_position(w, h)
|
||||
alpha_map = self.get_alpha_map(size)
|
||||
logger.debug(
|
||||
"Dynamic search failed. Using fallback default position (%d, %d) with %dx%d alpha map.",
|
||||
pos[0],
|
||||
pos[1],
|
||||
alpha_map.shape[1],
|
||||
alpha_map.shape[0],
|
||||
)
|
||||
return result
|
||||
|
||||
pos = (detection.region[0], detection.region[1])
|
||||
alpha_map = self.get_interpolated_alpha(detection.region[2])
|
||||
logger.debug(
|
||||
"Removing watermark at (%d, %d) size %dx%d [conf=%.3f]",
|
||||
pos[0],
|
||||
pos[1],
|
||||
detection.region[2],
|
||||
detection.region[3],
|
||||
detection.confidence,
|
||||
)
|
||||
|
||||
self._reverse_alpha_blend(result, alpha_map, pos)
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user