Spaces:
Sleeping
Sleeping
File size: 7,803 Bytes
0e27905 d6888a9 0e27905 176f783 9e601d1 176f783 9e601d1 1601fa5 0b7c7f6 9e2fa2e 1601fa5 9e2fa2e 1601fa5 9e2fa2e 1601fa5 0b7c7f6 9e2fa2e 1601fa5 9e2fa2e 1601fa5 9e2fa2e 1601fa5 0b7c7f6 9e2fa2e 0b7c7f6 9e2fa2e 176f783 d6888a9 176f783 0b7c7f6 24647ae d6888a9 9e601d1 9e2fa2e d6888a9 1601fa5 08cc004 9e2fa2e 176f783 9e2fa2e ef88f4b 1601fa5 9e2fa2e 1601fa5 9e2fa2e 24647ae d6888a9 b883a76 9e2fa2e b883a76 1601fa5 b883a76 0b7c7f6 b883a76 9e2fa2e 0b7c7f6 9e2fa2e 0b7c7f6 b883a76 9e2fa2e df8b5d4 9e2fa2e df8b5d4 b883a76 9e2fa2e 24647ae 08cc004 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
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()
|