import cv2 import numpy as np import gradio as gr def find_bounding_box(mask): """Find the bounding box around the largest contour in the mask.""" mask = mask.astype(np.uint8) _, binary_mask = cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY) contours, _ = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contours: x, y, w, h = cv2.boundingRect(np.vstack(contours)) return x, y, w, h return None def overlay_logo_on_image(original_img, mask, logo): """Overlay a scaled logo while maintaining aspect ratio and centering it in the bounding box.""" bbox = find_bounding_box(mask) if bbox is None: print("No bounding box found. Returning original image.") return original_img x, y, w, h = bbox print(f"Bounding box found at: x={x}, y={y}, w={w}, h={h}") # Get original logo dimensions logo_h, logo_w = logo.shape[:2] # Compute the scaling factor while maintaining aspect ratio scale = min(w / logo_w, h / logo_h) new_w, new_h = int(logo_w * scale), int(logo_h * scale) # Resize the logo while maintaining aspect ratio logo_resized = cv2.resize(logo, (new_w, new_h), interpolation=cv2.INTER_AREA) # Ensure logo_resized has 4 channels (RGBA) if logo_resized.shape[2] == 3: logo_resized = cv2.cvtColor(logo_resized, cv2.COLOR_RGB2RGBA) # Create a blank transparent canvas (RGBA) logo_canvas = np.zeros((h, w, 4), dtype=np.uint8) # Compute centering offsets x_offset = (w - new_w) // 2 y_offset = (h - new_h) // 2 # Place the resized logo at the center of the bounding box logo_canvas[y_offset:y_offset + new_h, x_offset:x_offset + new_w] = logo_resized # Convert original image to 4-channel if necessary if original_img.shape[2] == 3: original_img = cv2.cvtColor(original_img, cv2.COLOR_RGB2RGBA) # Blend the logo into the image using alpha blending alpha = logo_canvas[:, :, 3] / 255.0 for c in range(3): original_img[y:y+h, x:x+w, c] = ( (1 - alpha) * original_img[y:y+h, x:x+w, c] + alpha * logo_canvas[:, :, c] ) return original_img def process_images(original_img, mask, logo, progress=gr.Progress()): """Process images: overlay logo using uploaded mask.""" original_img = cv2.cvtColor(np.array(original_img), cv2.COLOR_RGB2BGR) mask = np.array(mask) print(f"Logo type before conversion: {type(logo)}, dtype: {getattr(logo, 'dtype', 'N/A')}") logo = np.array(logo) if logo.dtype != np.uint8: logo = logo.astype(np.uint8) logo = cv2.cvtColor(np.array(logo), cv2.COLOR_RGB2BGR) if len(mask.shape) == 3: mask = cv2.cvtColor(mask, cv2.COLOR_RGB2GRAY) mask = (mask > 0).astype(np.uint8) * 255 print(f"Mask shape: {mask.shape}, unique values: {np.unique(mask)}") result_img = overlay_logo_on_image(original_img, mask, logo) result_img = cv2.cvtColor(result_img, cv2.COLOR_BGRA2RGBA) if result_img.shape[2] == 4 else cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB) return result_img with gr.Blocks() as demo : gr.Markdown("## Inpaint Logo on Uploaded Mask") with gr.Row() : with gr.Column() : with gr.Row(): original_img = gr.Image(label="Upload Original Image", type="numpy") with gr.Row(): mask = gr.Image(label="Upload Mask (Binary)", type="numpy") logo = gr.Image(label="Upload Logo", type="numpy") btn = gr.Button("Submit") with gr.Column() : output = gr.Image(label="Output Image", format="png") btn.click(fn=process_images, inputs=[original_img, mask, logo], outputs=output) demo.launch(share=True, debug=True, show_error=True)