carlosriverat's picture
updated magenta images
1601fa5
import gradio as gr
import cv2
import numpy as np
from skimage.metrics import structural_similarity as ssim
def preprocess_image(image, blur_value):
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Apply Gaussian blur to reduce noise
blurred = cv2.GaussianBlur(gray, (blur_value, blur_value), 0)
return blurred
def create_dramatic_magenta(image1, diff):
"""Create a more dramatic magenta overlay to highlight differences"""
# Create a more intense magenta by boosting the red and blue channels
diff_colored = cv2.absdiff(image1, diff)
# Normalize to enhance contrast
diff_normalized = cv2.normalize(diff_colored, None, 0, 255, cv2.NORM_MINMAX)
# Amplify the red channel for more dramatic magenta
diff_normalized[:, :, 0] = 0 # Remove blue
diff_normalized[:, :, 1] = 0 # Remove green
diff_normalized[:, :, 2] = np.clip(diff_normalized[:, :, 2] * 2, 0, 255) # Boost red
# Create more dramatic overlay with higher contrast
overlay = cv2.addWeighted(image1, 0.5, diff_normalized, 0.8, 0)
return overlay
def background_subtraction(image1, image2):
subtractor = cv2.createBackgroundSubtractorMOG2()
fgmask1 = subtractor.apply(image1)
fgmask2 = subtractor.apply(image2)
diff = cv2.absdiff(fgmask1, fgmask2)
# Create a binary mask
_, mask = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)
# Create highlighted differences
highlighted = cv2.bitwise_and(image2, image2, mask=mask)
# Create raw difference overlay with dramatic magenta
raw_overlay = create_dramatic_magenta(image1, image2)
# Create a blended image
blended = cv2.addWeighted(image1, 0.5, image2, 0.5, 0)
# Create a composite using the mask
composite = image1.copy()
composite[mask > 0] = image2[mask > 0]
# Create final difference overlay with dramatic magenta
final_overlay = create_dramatic_magenta(image1, composite)
return blended, raw_overlay, highlighted, mask, composite, final_overlay
def optical_flow(image1, image2):
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(gray1, gray2, None, 0.5, 3, 15, 3, 5, 1.2, 0)
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
hsv = np.zeros_like(image1)
hsv[..., 1] = 255
hsv[..., 0] = ang * 180 / np.pi / 2
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
# Create mask from magnitude
mask = cv2.threshold(hsv[..., 2], 30, 255, cv2.THRESH_BINARY)[1].astype(np.uint8)
# Create highlighted differences
highlighted = cv2.bitwise_and(image2, image2, mask=mask)
# Create raw difference overlay with dramatic magenta
raw_overlay = create_dramatic_magenta(image1, image2)
# Create a blended image
blended = cv2.addWeighted(image1, 0.5, image2, 0.5, 0)
# Create a composite using the mask
composite = image1.copy()
composite[mask > 0] = image2[mask > 0]
# Create final difference overlay with dramatic magenta
final_overlay = create_dramatic_magenta(image1, composite)
return blended, raw_overlay, highlighted, mask, composite, final_overlay
def feature_matching(image1, image2):
# Use SSIM as a fallback for feature matching since the original implementation doesn't give us a good mask
return compare_ssim(image1, image2, 5, "Adaptive Threshold", 30)
def compare_ssim(image1, image2, blur_value, technique, threshold_value):
gray1 = preprocess_image(image1, blur_value)
gray2 = preprocess_image(image2, blur_value)
score, diff = ssim(gray1, gray2, full=True)
diff = (diff * 255).astype("uint8")
if technique == "Adaptive Threshold":
_, thresh = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY_INV)
elif technique == "Otsu's Threshold":
_, thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
else:
_, thresh = cv2.threshold(diff, threshold_value, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 500]
mask = np.zeros_like(gray1, dtype=np.uint8)
cv2.drawContours(mask, filtered_contours, -1, 255, thickness=cv2.FILLED)
# Create highlighted differences
highlighted = cv2.bitwise_and(image2, image2, mask=mask)
# Create raw difference overlay with dramatic magenta
raw_overlay = create_dramatic_magenta(image1, image2)
# Create a blended image
blended = cv2.addWeighted(image1, 0.5, image2, 0.5, 0)
# Create a composite using the mask
composite = image1.copy()
mask_3channel = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
masked_obj = cv2.bitwise_and(image2, mask_3channel)
masked_bg = cv2.bitwise_and(image1, cv2.bitwise_not(mask_3channel))
composite = cv2.add(masked_bg, masked_obj)
# Create final difference overlay with dramatic magenta
final_overlay = create_dramatic_magenta(image1, composite)
return blended, raw_overlay, highlighted, mask, composite, final_overlay
def compare_images(image1, image2, blur_value, technique, threshold_value, method):
if method == "Background Subtraction":
return background_subtraction(image1, image2)
elif method == "Optical Flow":
return optical_flow(image1, image2)
elif method == "Feature Matching":
return feature_matching(image1, image2)
else: # SSIM
return compare_ssim(image1, image2, blur_value, technique, threshold_value)
def update_threshold_visibility(technique):
return gr.update(visible=(technique == "Simple Binary"))
with gr.Blocks() as demo:
gr.Markdown("# Object Difference Highlighter\nUpload two images: one without an object and one with an object. The app will highlight only the newly added object and show the real differences in magenta overlayed on the original image.")
with gr.Row():
img1 = gr.Image(type="numpy", label="Image Without Object (Scene)")
img2 = gr.Image(type="numpy", label="Image With Object")
blur_slider = gr.Slider(minimum=1, maximum=15, step=2, value=5, label="Gaussian Blur")
technique_dropdown = gr.Dropdown(["Adaptive Threshold", "Otsu's Threshold", "Simple Binary"], label="Thresholding Technique", value="Adaptive Threshold", interactive=True)
threshold_slider = gr.Slider(minimum=0, maximum=255, step=1, value=50, label="Threshold Value", visible=False)
method_dropdown = gr.Dropdown(["SSIM", "Background Subtraction", "Optical Flow", "Feature Matching"], label="Comparison Method", value="SSIM", interactive=True)
technique_dropdown.change(update_threshold_visibility, inputs=[technique_dropdown], outputs=[threshold_slider])
# Row 1 - Blend and Raw Difference
with gr.Row():
output1 = gr.Image(type="numpy", label="Blended Image")
output2 = gr.Image(type="numpy", label="Raw Difference Overlay (Magenta)")
# Row 2 - Algorithmic Differences and Mask
with gr.Row():
output3 = gr.Image(type="numpy", label="Highlighted Differences")
output4 = gr.Image(type="numpy", label="Black & White Mask")
# Row 3 - Composite and Final Difference
with gr.Row():
output5 = gr.Image(type="numpy", label="Composite (Scene + Masked Object)")
output6 = gr.Image(type="numpy", label="Final Difference Overlay (Magenta)")
btn = gr.Button("Process")
btn.click(compare_images, inputs=[img1, img2, blur_slider, technique_dropdown, threshold_slider, method_dropdown], outputs=[output1, output2, output3, output4, output5, output6])
demo.launch()