Commit
·
1ab24b1
1
Parent(s):
62974a7
fix: improve pink detection with multiple methods and add debug logging to diagnose removal issues
Browse files- api/main.py +41 -16
api/main.py
CHANGED
|
@@ -394,27 +394,38 @@ def remove_pink_segments(
|
|
| 394 |
# Pink/Magenta → white in mask (remove)
|
| 395 |
# Everything else (natural image colors, including dark areas) → black in mask (keep)
|
| 396 |
|
| 397 |
-
#
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
(img_rgb[:, :,
|
| 401 |
-
(img_rgb[:, :,
|
|
|
|
| 402 |
).astype(np.uint8) * 255
|
| 403 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 404 |
# Clean up the pink mask
|
| 405 |
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
|
| 406 |
-
binmask = cv2.morphologyEx(
|
| 407 |
binmask = cv2.morphologyEx(binmask, cv2.MORPH_OPEN, kernel, iterations=1)
|
| 408 |
|
| 409 |
nonzero = int((binmask > 0).sum())
|
| 410 |
-
|
|
|
|
| 411 |
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
magenta_strict = np.all(img_rgb == [255, 0, 255], axis=2).astype(np.uint8) * 255
|
| 415 |
-
binmask = cv2.morphologyEx(magenta_strict, cv2.MORPH_CLOSE, kernel, iterations=3)
|
| 416 |
-
nonzero = int((binmask > 0).sum())
|
| 417 |
-
log.info(f"Strict detection: {nonzero} pink pixels")
|
| 418 |
|
| 419 |
if nonzero < 50:
|
| 420 |
log.error("No pink segments detected! Returning original image.")
|
|
@@ -428,7 +439,7 @@ def remove_pink_segments(
|
|
| 428 |
}
|
| 429 |
|
| 430 |
# Create binary mask: Pink pixels → white (255), Everything else → black (0)
|
| 431 |
-
#
|
| 432 |
# process_inpaint does: mask = 255 - mask[:,:,3]
|
| 433 |
# So: alpha=0 (transparent/pink) → becomes 255 (white/remove)
|
| 434 |
# alpha=255 (opaque/keep) → becomes 0 (black/keep)
|
|
@@ -441,11 +452,25 @@ def remove_pink_segments(
|
|
| 441 |
# 255 (opaque) everywhere else → will become black after 255-alpha
|
| 442 |
mask_rgba[:, :, 3] = 255 - binmask # Invert: pink areas get alpha=0, rest get alpha=255
|
| 443 |
|
|
|
|
|
|
|
|
|
|
| 444 |
total_pixels = binmask.shape[0] * binmask.shape[1]
|
| 445 |
-
log.info(f"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 446 |
|
| 447 |
# Process with invert_mask=True (default) because process_inpaint expects alpha=0 for removal
|
| 448 |
-
|
|
|
|
|
|
|
| 449 |
result_name = f"output_{uuid.uuid4().hex}.png"
|
| 450 |
result_path = os.path.join(OUTPUT_DIR, result_name)
|
| 451 |
Image.fromarray(result).save(result_path, "PNG", optimize=False, compress_level=1)
|
|
|
|
| 394 |
# Pink/Magenta → white in mask (remove)
|
| 395 |
# Everything else (natural image colors, including dark areas) → black in mask (keep)
|
| 396 |
|
| 397 |
+
# More robust pink/magenta detection - try multiple methods
|
| 398 |
+
# Method 1: Detect bright magenta (RGB: R>200, G<80, B>200) - more lenient
|
| 399 |
+
magenta_detected_loose = (
|
| 400 |
+
(img_rgb[:, :, 0] > 200) & # Red: high
|
| 401 |
+
(img_rgb[:, :, 1] < 80) & # Green: low (allow more tolerance)
|
| 402 |
+
(img_rgb[:, :, 2] > 200) # Blue: high
|
| 403 |
).astype(np.uint8) * 255
|
| 404 |
|
| 405 |
+
# Method 2: Detect exact magenta (255, 0, 255)
|
| 406 |
+
magenta_strict = np.all(img_rgb == [255, 0, 255], axis=2).astype(np.uint8) * 255
|
| 407 |
+
|
| 408 |
+
# Method 3: Detect pink-ish colors (high red+blue, low green)
|
| 409 |
+
pink_detected = (
|
| 410 |
+
(img_rgb[:, :, 0] > 220) & # Red: very high
|
| 411 |
+
(img_rgb[:, :, 1] < 100) & # Green: low
|
| 412 |
+
(img_rgb[:, :, 2] > 220) # Blue: very high
|
| 413 |
+
).astype(np.uint8) * 255
|
| 414 |
+
|
| 415 |
+
# Combine all detection methods
|
| 416 |
+
binmask = np.maximum.reduce([magenta_detected_loose, magenta_strict, pink_detected])
|
| 417 |
+
|
| 418 |
# Clean up the pink mask
|
| 419 |
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
|
| 420 |
+
binmask = cv2.morphologyEx(binmask, cv2.MORPH_CLOSE, kernel, iterations=2)
|
| 421 |
binmask = cv2.morphologyEx(binmask, cv2.MORPH_OPEN, kernel, iterations=1)
|
| 422 |
|
| 423 |
nonzero = int((binmask > 0).sum())
|
| 424 |
+
total_pixels = binmask.shape[0] * binmask.shape[1]
|
| 425 |
+
log.info(f"Detected {nonzero} pink pixels ({100*nonzero/total_pixels:.2f}% of image) to remove")
|
| 426 |
|
| 427 |
+
# Debug: show detection stats
|
| 428 |
+
log.info(f"Detection stats - Loose: {int((magenta_detected_loose > 0).sum())}, Strict: {int((magenta_strict > 0).sum())}, Pink: {int((pink_detected > 0).sum())}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 429 |
|
| 430 |
if nonzero < 50:
|
| 431 |
log.error("No pink segments detected! Returning original image.")
|
|
|
|
| 439 |
}
|
| 440 |
|
| 441 |
# Create binary mask: Pink pixels → white (255), Everything else → black (0)
|
| 442 |
+
# Encode in RGBA format that process_inpaint expects
|
| 443 |
# process_inpaint does: mask = 255 - mask[:,:,3]
|
| 444 |
# So: alpha=0 (transparent/pink) → becomes 255 (white/remove)
|
| 445 |
# alpha=255 (opaque/keep) → becomes 0 (black/keep)
|
|
|
|
| 452 |
# 255 (opaque) everywhere else → will become black after 255-alpha
|
| 453 |
mask_rgba[:, :, 3] = 255 - binmask # Invert: pink areas get alpha=0, rest get alpha=255
|
| 454 |
|
| 455 |
+
# Verify mask encoding
|
| 456 |
+
alpha_zero_count = int((mask_rgba[:,:,3] == 0).sum())
|
| 457 |
+
alpha_255_count = int((mask_rgba[:,:,3] == 255).sum())
|
| 458 |
total_pixels = binmask.shape[0] * binmask.shape[1]
|
| 459 |
+
log.info(f"Mask encoding: {alpha_zero_count} pixels with alpha=0 (pink), {alpha_255_count} pixels with alpha=255 (keep)")
|
| 460 |
+
log.info(f"After 255-alpha conversion: {alpha_zero_count} will become white (255/remove), {alpha_255_count} will become black (0/keep)")
|
| 461 |
+
|
| 462 |
+
# IMPORTANT: We need to use the ORIGINAL image WITHOUT pink paint for inpainting!
|
| 463 |
+
# Remove pink from the original image before processing
|
| 464 |
+
# Create a clean version: where pink was detected, keep original image colors
|
| 465 |
+
img_clean = np.array(img.convert("RGBA"))
|
| 466 |
+
# Where pink is detected, we want to inpaint, so we can leave it (or blend it out)
|
| 467 |
+
# Actually, the model will inpaint over those areas, so we can pass the original
|
| 468 |
+
# But for better results, we might want to remove the pink overlay first
|
| 469 |
|
| 470 |
# Process with invert_mask=True (default) because process_inpaint expects alpha=0 for removal
|
| 471 |
+
log.info(f"Starting inpainting process...")
|
| 472 |
+
result = process_inpaint(img_clean, mask_rgba, invert_mask=True)
|
| 473 |
+
log.info(f"Inpainting complete, result shape: {result.shape}")
|
| 474 |
result_name = f"output_{uuid.uuid4().hex}.png"
|
| 475 |
result_path = os.path.join(OUTPUT_DIR, result_name)
|
| 476 |
Image.fromarray(result).save(result_path, "PNG", optimize=False, compress_level=1)
|