Spaces:
Sleeping
Sleeping
Add Bounding Box vs Segment Overlay output style option in Gradio UI
Browse files- app.py +9 -3
- diff_ai.py +28 -17
app.py
CHANGED
|
@@ -18,7 +18,7 @@ from describe import describe_change
|
|
| 18 |
|
| 19 |
import gradio as gr
|
| 20 |
|
| 21 |
-
def gradio_compare(img1, img2):
|
| 22 |
if img1 is None or img2 is None:
|
| 23 |
return None, None, "Please upload both images.", {}
|
| 24 |
|
|
@@ -39,7 +39,8 @@ def gradio_compare(img1, img2):
|
|
| 39 |
# Run comparison pipeline
|
| 40 |
pipeline_used = "AI Pipeline"
|
| 41 |
try:
|
| 42 |
-
|
|
|
|
| 43 |
except Exception as e:
|
| 44 |
print(f"[Gradio] AI pipeline failed ({e}); falling back to classical")
|
| 45 |
result_data = compare_images(path1, path2, output_path, heatmap_path)
|
|
@@ -109,6 +110,11 @@ with gr.Blocks() as demo:
|
|
| 109 |
gr.Markdown("### Input Images")
|
| 110 |
img1_input = gr.Image(label="Before Image", type="numpy")
|
| 111 |
img2_input = gr.Image(label="After Image", type="numpy")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
submit_btn = gr.Button("Compare & Analyze", variant="primary", size="lg")
|
| 113 |
|
| 114 |
with gr.Column(scale=1):
|
|
@@ -123,7 +129,7 @@ with gr.Blocks() as demo:
|
|
| 123 |
|
| 124 |
submit_btn.click(
|
| 125 |
fn=gradio_compare,
|
| 126 |
-
inputs=[img1_input, img2_input],
|
| 127 |
outputs=[result_img_output, heatmap_img_output, desc_output, metrics_output]
|
| 128 |
)
|
| 129 |
|
|
|
|
| 18 |
|
| 19 |
import gradio as gr
|
| 20 |
|
| 21 |
+
def gradio_compare(img1, img2, style_option="Segment Overlay"):
|
| 22 |
if img1 is None or img2 is None:
|
| 23 |
return None, None, "Please upload both images.", {}
|
| 24 |
|
|
|
|
| 39 |
# Run comparison pipeline
|
| 40 |
pipeline_used = "AI Pipeline"
|
| 41 |
try:
|
| 42 |
+
draw_style = "box" if style_option == "Bounding Boxes Only" else "overlay"
|
| 43 |
+
result_data = compare_images_ai(path1, path2, output_path, heatmap_path, draw_style=draw_style)
|
| 44 |
except Exception as e:
|
| 45 |
print(f"[Gradio] AI pipeline failed ({e}); falling back to classical")
|
| 46 |
result_data = compare_images(path1, path2, output_path, heatmap_path)
|
|
|
|
| 110 |
gr.Markdown("### Input Images")
|
| 111 |
img1_input = gr.Image(label="Before Image", type="numpy")
|
| 112 |
img2_input = gr.Image(label="After Image", type="numpy")
|
| 113 |
+
style_input = gr.Radio(
|
| 114 |
+
choices=["Segment Overlay", "Bounding Boxes Only"],
|
| 115 |
+
value="Segment Overlay",
|
| 116 |
+
label="Visualization Output Style"
|
| 117 |
+
)
|
| 118 |
submit_btn = gr.Button("Compare & Analyze", variant="primary", size="lg")
|
| 119 |
|
| 120 |
with gr.Column(scale=1):
|
|
|
|
| 129 |
|
| 130 |
submit_btn.click(
|
| 131 |
fn=gradio_compare,
|
| 132 |
+
inputs=[img1_input, img2_input, style_input],
|
| 133 |
outputs=[result_img_output, heatmap_img_output, desc_output, metrics_output]
|
| 134 |
)
|
| 135 |
|
diff_ai.py
CHANGED
|
@@ -458,7 +458,7 @@ def _composite_object(base, object_img, mask, bbox, color):
|
|
| 458 |
# MAIN ENTRY
|
| 459 |
# =====================================================================
|
| 460 |
|
| 461 |
-
def _compare_images_ai_impl(img1_path, img2_path, output_path, heatmap_path):
|
| 462 |
"""End-to-end change-region-driven AI pipeline. Raises RuntimeError
|
| 463 |
if any required model is unavailable."""
|
| 464 |
if not _get_loftr() or not _get_sam() or not _get_dinov2():
|
|
@@ -611,18 +611,29 @@ def _compare_images_ai_impl(img1_path, img2_path, output_path, heatmap_path):
|
|
| 611 |
n_total = n_added + n_removed + n_moved
|
| 612 |
severity = "HIGH" if n_total > 0 else "NONE"
|
| 613 |
|
| 614 |
-
# 5) Render
|
| 615 |
-
|
| 616 |
-
|
| 617 |
-
|
| 618 |
-
|
| 619 |
-
|
| 620 |
-
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 626 |
|
| 627 |
# Draw severity label in top-left
|
| 628 |
label = f"{severity} +{n_added} -{n_removed} ~{n_moved}"
|
|
@@ -647,8 +658,8 @@ def _compare_images_ai_impl(img1_path, img2_path, output_path, heatmap_path):
|
|
| 647 |
|
| 648 |
if HAS_SPACES:
|
| 649 |
@spaces.GPU
|
| 650 |
-
def compare_images_ai(img1_path, img2_path, output_path, heatmap_path):
|
| 651 |
-
return _compare_images_ai_impl(img1_path, img2_path, output_path, heatmap_path)
|
| 652 |
else:
|
| 653 |
-
def compare_images_ai(img1_path, img2_path, output_path, heatmap_path):
|
| 654 |
-
return _compare_images_ai_impl(img1_path, img2_path, output_path, heatmap_path)
|
|
|
|
| 458 |
# MAIN ENTRY
|
| 459 |
# =====================================================================
|
| 460 |
|
| 461 |
+
def _compare_images_ai_impl(img1_path, img2_path, output_path, heatmap_path, draw_style="overlay"):
|
| 462 |
"""End-to-end change-region-driven AI pipeline. Raises RuntimeError
|
| 463 |
if any required model is unavailable."""
|
| 464 |
if not _get_loftr() or not _get_sam() or not _get_dinov2():
|
|
|
|
| 611 |
n_total = n_added + n_removed + n_moved
|
| 612 |
severity = "HIGH" if n_total > 0 else "NONE"
|
| 613 |
|
| 614 |
+
# 5) Render output image
|
| 615 |
+
if draw_style == "box":
|
| 616 |
+
result_img = aligned.copy()
|
| 617 |
+
for a in added_objects:
|
| 618 |
+
_draw_box(result_img, a["bbox"], COLOR_ADDED, "ADDED")
|
| 619 |
+
for r in removed_objects:
|
| 620 |
+
_draw_box(result_img, r["bbox"], COLOR_REMOVED, "REMOVED")
|
| 621 |
+
for m in moved_objects:
|
| 622 |
+
_draw_box(result_img, m["from"]["bbox"], COLOR_MOVED, "MOVED")
|
| 623 |
+
_draw_box(result_img, m["to"]["bbox"], COLOR_MOVED, "MOVED")
|
| 624 |
+
else:
|
| 625 |
+
# Dark-tint background + highlight changed objects (overlay)
|
| 626 |
+
DARK_FACTOR = 0.3
|
| 627 |
+
result_img = cv2.multiply(aligned, np.array([DARK_FACTOR] * 3, dtype=np.float64))
|
| 628 |
+
result_img = np.clip(result_img, 0, 255).astype(np.uint8)
|
| 629 |
+
|
| 630 |
+
for a in added_objects:
|
| 631 |
+
_composite_object(result_img, aligned, a["mask"], a["bbox"], COLOR_ADDED)
|
| 632 |
+
for r in removed_objects:
|
| 633 |
+
_composite_object(result_img, r["source"], r["mask"], r["bbox"], COLOR_REMOVED)
|
| 634 |
+
for m in moved_objects:
|
| 635 |
+
_composite_object(result_img, m["from"]["source"], m["from"]["mask"], m["from"]["bbox"], COLOR_MOVED)
|
| 636 |
+
_composite_object(result_img, aligned, m["to"]["mask"], m["to"]["bbox"], COLOR_MOVED)
|
| 637 |
|
| 638 |
# Draw severity label in top-left
|
| 639 |
label = f"{severity} +{n_added} -{n_removed} ~{n_moved}"
|
|
|
|
| 658 |
|
| 659 |
if HAS_SPACES:
|
| 660 |
@spaces.GPU
|
| 661 |
+
def compare_images_ai(img1_path, img2_path, output_path, heatmap_path, draw_style="overlay"):
|
| 662 |
+
return _compare_images_ai_impl(img1_path, img2_path, output_path, heatmap_path, draw_style=draw_style)
|
| 663 |
else:
|
| 664 |
+
def compare_images_ai(img1_path, img2_path, output_path, heatmap_path, draw_style="overlay"):
|
| 665 |
+
return _compare_images_ai_impl(img1_path, img2_path, output_path, heatmap_path, draw_style=draw_style)
|