File size: 15,240 Bytes
6779b1a 4d6feed ef4e074 4d6feed ef4e074 1c5a214 ef4e074 e653994 ef4e074 1c5a214 e653994 4d6feed ef4e074 e653994 ef4e074 2cff2f8 ef4e074 2cff2f8 e653994 2cff2f8 ef4e074 2cff2f8 e653994 2cff2f8 ef4e074 e653994 2cff2f8 e653994 2cff2f8 e653994 2cff2f8 e653994 ef4e074 e653994 2cff2f8 e653994 2cff2f8 e653994 2cff2f8 e653994 ef4e074 e653994 ef4e074 e653994 2cff2f8 e653994 1c5a214 e653994 1c5a214 e653994 1c5a214 e653994 ef4e074 619aadd bc4a6f3 619aadd bc4a6f3 619aadd bc4a6f3 619aadd 4d6feed e653994 619aadd e653994 ef4e074 e653994 ef4e074 612fcaf 619aadd bc4a6f3 619aadd e653994 619aadd e653994 a128b36 619aadd e653994 717ded7 2cff2f8 e653994 717ded7 e653994 717ded7 e653994 717ded7 e653994 717ded7 e653994 717ded7 e653994 717ded7 e653994 717ded7 1c5a214 e653994 717ded7 7ebecdb 717ded7 bc4a6f3 e653994 717ded7 e653994 717ded7 e653994 717ded7 a128b36 7ebecdb 4d6feed 6779b1a ef4e074 1c5a214 e653994 1c5a214 6779b1a 612fcaf |
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 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
import gradio as gr
import numpy as np
import cv2
import os
import tempfile
############################################
# 1. SINGLE-IMAGE GOIS INFERENCE (Imported)
############################################
from gois_core import run_inference
"""
Assumed signature of run_inference:
run_inference(
image: np.ndarray (RGB),
model_name: str,
coarse_size: int,
fine_size: int,
c_overlap: float,
f_overlap: float,
nms_thresh: float
) -> Tuple[
np.ndarray, # FI image
np.ndarray, # GOIS image
str, # FI HTML table
str, # GOIS HTML table
np.ndarray, # bar_chart image
np.ndarray, # fi_pie image
np.ndarray, # gois_pie image
str # metrics table HTML
]
"""
############################################
# 2. BATCH INFERENCE FOR MULTIPLE IMAGES
############################################
def run_inference_batch(
file_paths: list,
model_name: str,
coarse_size: int,
fine_size: int,
c_overlap: float,
f_overlap: float,
nms_thresh: float
):
"""
1. `file_paths` is a list of string file paths.
2. For each path:
- Load the image
- Run single-image GOIS inference
- Collect FI & GOIS outputs plus minimal metrics
3. Return:
- A gallery of pairs [(FI_1, "Name FI"), (GOIS_1, "Name GOIS"), ..., (FI_N, "Name FI"), (GOIS_N, "Name GOIS")]
- An HTML table summarizing metrics for each image
"""
if not file_paths:
return None, "<p style='color:red;'>No images uploaded.</p>"
# This will store pairs of images for a gallery
combined_images = []
# This will collect rows (HTML) for a metrics summary table
metrics_rows = []
for path in file_paths:
img_name = os.path.basename(path)
img = cv2.imread(path) # BGR
if img is None:
continue
# Convert to RGB if your model expects that
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 1) Run the single-image inference
(
fi_img,
gois_img,
fi_table_html,
gois_table_html,
bar_chart,
fi_pie,
gois_pie,
metrics_html
) = run_inference(
img_rgb, model_name, coarse_size, fine_size, c_overlap, f_overlap, nms_thresh
)
# 2) Add to gallery: (image, label)
combined_images.append((fi_img, f"{img_name} - FI"))
combined_images.append((gois_img, f"{img_name} - GOIS"))
# 3) Collect metrics in a single row
metrics_rows.append(
f"<tr><td>{img_name}</td><td>{metrics_html or '(No metrics)'} </td></tr>"
)
# 4) Build a single HTML table for the entire batch
table_html = f"""
<table border="1" style="border-collapse: collapse; width:100%;">
<thead>
<tr><th>Image Name</th><th>Metrics</th></tr>
</thead>
<tbody>
{''.join(metrics_rows)}
</tbody>
</table>
"""
return combined_images, table_html
############################################
# 3. EXTENDED MODEL REGISTRY (Placeholder)
############################################
from models_loader import EXTENDED_MODELS
############################################
# 4. OPTIONAL CUSTOM CSS
############################################
CUSTOM_CSS = """
body {
background-color: #fafafa;
font-family: 'Inter', sans-serif;
}
#custom-header {
background: linear-gradient(135deg, #8EC5FC, #E0C3FC);
border-radius: 10px;
padding: 1rem;
text-align: center;
color: #fff;
}
#custom-header h1 { font-size: 2.0rem; margin-bottom: 0.3rem; }
#custom-header h3 { font-size: 1.2rem; margin-top: 0.2rem; }
.tabitem {
background-color: #ffffff;
border: 1px solid #ddd;
border-radius: 8px;
margin: 0.5rem 0;
padding: 1rem;
}
.gradio-tab .gradio-tabitem label {
background: linear-gradient(135deg, #ffc3a0, #ffafbd);
color: #3c3c3c !important;
border-radius: 5px 5px 0 0;
margin-right: 3px;
font-weight: 600 !important;
font-size: 0.95rem;
}
.gradio-tab .gradio-tabitem input:checked + label {
background: linear-gradient(135deg, #D3CCE3, #E9E4F0);
color: #000 !important;
}
"""
############################################
# 5. BUILD GRADIO INTERFACE
############################################
import gradio as gr
def build_app():
theme = gr.themes.Soft(
primary_hue="indigo",
secondary_hue="pink",
neutral_hue="blue"
)
with gr.Blocks(css=CUSTOM_CSS, theme=theme) as demo:
# 5.1 HEADER
gr.HTML("""
<div id="custom-header">
<h1>GOIS vs. Full-Image Detection</h1>
<h3>Single & Multiple Images Comparison</h3>
</div>
""")
####################################
# 5.2. OVERVIEW TAB
####################################
with gr.Tab("Overview", elem_classes="tabitem"):
gr.Markdown("""
### GOIS: Granular Object Inspection Strategy
**Granular Object Inspection Strategy (GOIS)** slices images (coarse → fine) to detect objects that might be missed in a single pass:
- Better handling of **occlusion** or partially visible objects.
- Fewer **boundary artifacts** when patch edges overlap.
- Can reduce **false positives** by skipping large uniform regions.
**Why This App?**
- **Single Image**: See side-by-side Full-Image (FI) detection vs. GOIS detection for one image.
- **Multiple Images**: Upload a batch of images and get a combined gallery + metrics table.
**Extended Models**:
- YOLOv8
- RT-DETR-l
- YOLOv8s-Worldv2
...and more from our custom registry.
**Speed vs. Accuracy**:
- GOIS is more thorough but can be slower due to multi-slicing.
- Adjust slice sizes and overlaps to balance performance.
---
""")
####################################
# 5.3. SINGLE IMAGE TAB
####################################
with gr.Tab("Single Image", elem_classes="tabitem"):
gr.Markdown("#### Upload one image and view FI vs. GOIS outputs in the same tab")
# Input row
with gr.Row():
inp_image = gr.Image(label="Upload Image", type="numpy")
model_dd_img = gr.Dropdown(
label="Select Model",
choices=list(EXTENDED_MODELS.keys()),
value="YOLOv8"
)
# Parameter sliders
with gr.Row():
coarse_size_img = gr.Slider(512, 768, value=640, step=1, label="Coarse Slice Size")
fine_size_img = gr.Slider(128, 384, value=256, step=1, label="Fine Slice Size")
c_overlap_img = gr.Slider(0.1, 0.4, value=0.2, step=0.1, label="Coarse Overlap")
f_overlap_img = gr.Slider(0.1, 0.4, value=0.2, step=0.1, label="Fine Overlap")
nms_thresh_img = gr.Slider(0.3, 0.5, value=0.4, step=0.1, label="NMS Threshold")
run_btn_img = gr.Button("Run Inference (Single Image)", variant="primary")
# Output section in the same tab
gr.Markdown("#### Results (FI vs. GOIS) + Metrics")
with gr.Row():
fi_out = gr.Image(label="FI-Det (Baseline)")
gois_out = gr.Image(label="GOIS-Det")
with gr.Row():
fi_table_html = gr.HTML(label="FI Classes/Distribution")
gois_table_html = gr.HTML(label="GOIS Classes/Distribution")
with gr.Row():
bar_chart = gr.Image(label="Bar Chart (FI vs. GOIS)")
fi_pie_img = gr.Image(label="FI Pie Chart")
gois_pie_img= gr.Image(label="GOIS Pie Chart")
metrics_html = gr.HTML(label="Metrics Table (Single Image)")
# Button binding
run_btn_img.click(
fn=run_inference,
inputs=[
inp_image,
model_dd_img,
coarse_size_img,
fine_size_img,
c_overlap_img,
f_overlap_img,
nms_thresh_img
],
outputs=[
fi_out,
gois_out,
fi_table_html,
gois_table_html,
bar_chart,
fi_pie_img,
gois_pie_img,
metrics_html
]
)
####################################
# 5.4. MULTIPLE IMAGES TAB
####################################
with gr.Tab("Multiple Images", elem_classes="tabitem"):
gr.Markdown("#### Upload multiple images and compare FI vs. GOIS on each")
# Input row
with gr.Row():
batch_imgs = gr.Files(
label="Upload Multiple Images (JPG/PNG)",
file_count="multiple",
type="filepath"
)
model_dd_multi = gr.Dropdown(
label="Select Model",
choices=list(EXTENDED_MODELS.keys()),
value="YOLOv8"
)
# Parameter sliders
with gr.Row():
coarse_size_multi = gr.Slider(512, 768, value=640, step=1, label="Coarse Slice Size")
fine_size_multi = gr.Slider(128, 384, value=256, step=1, label="Fine Slice Size")
c_overlap_multi = gr.Slider(0.1, 0.4, value=0.2, step=0.1, label="Coarse Overlap")
f_overlap_multi = gr.Slider(0.1, 0.4, value=0.2, step=0.1, label="Fine Overlap")
nms_thresh_multi = gr.Slider(0.3, 0.5, value=0.4, step=0.1, label="NMS Threshold")
run_btn_multi = gr.Button("Run Inference (Batch)", variant="primary")
# Outputs in the same tab
gr.Markdown("#### Batch Results & Metrics")
batch_gallery = gr.Gallery(label="FI-Det vs GOIS-Det (All Images)")
batch_metrics_html = gr.HTML(label="Batch Metrics Table")
# Button binding
run_btn_multi.click(
fn=run_inference_batch,
inputs=[
batch_imgs,
model_dd_multi,
coarse_size_multi,
fine_size_multi,
c_overlap_multi,
f_overlap_multi,
nms_thresh_multi
],
outputs=[
batch_gallery,
batch_metrics_html
]
)
####################################
# 5.5. RECOMMENDED CONFIGURATIONS TAB
####################################
with gr.Tab("Recommended Configs"):
gr.Markdown("""
### Suggested Parameter Settings (for GOIS)
| Config | Coarse Size | Fine Size | Coarse Overlap | Fine Overlap | NMS Thresh |
|---------|------------:|----------:|---------------:|-------------:|-----------:|
| **C1** | 512 px | 128 px | 0.1 | 0.1 | 0.3 |
| **C2** | 640 px | 256 px | 0.2 | 0.2 | 0.4 |
| **C3** | 768 px | 384 px | 0.3 | 0.3 | 0.5 |
**Tips**:
- **Coarse Size**: Larger slices → fewer patches → faster, but might miss tiny objects.
- **Fine Size**: Smaller slices → more detailed detection → slower.
- **Overlap**: Higher overlap → fewer boundary misses → more computations.
- **NMS Threshold**: Lower → more aggressive overlap removal → might drop some true positives.
""")
gr.Markdown("""
### More Suggestions and Advanced Parameter Settings (for GOIS)
| Parameter | Recommended Values | Expanded Ranges | Effect on Performance | Handling Errors |
|-------------------------|---------------------|-----------------|-------------------------------------------------------------------|---------------------------------------------------------------|
| **Coarse Slice Size** | 512 - 768 | 256 - 1024 | Larger slices improve speed but may miss small objects | If small objects are missed, reduce slice size |
| **Fine Slice Size** | 128 - 384 | 64 - 512 | Smaller slices detect tiny objects better but increase computation| If too many duplicate detections occur, increase NMS |
| **Coarse Overlap** | 0.2 - 0.4 | 0.1 - 0.5 | Higher overlap reduces boundary artifacts but increases processing time | Increase overlap if objects near boundaries are missing |
| **Fine Overlap** | 0.4 - 0.6 | 0.3 - 0.7 | Higher overlap helps detect occluded objects but increases computation | Increase overlap to detect occluded objects but monitor speed |
| **NMS Threshold** | 0.3 - 0.5 | 0.2 - 0.6 | Lower values remove overlapping boxes but may discard true positives | If detections overlap, lower NMS; if detections disappear, increase NMS |
| **IoU Threshold** | 0.4 - 0.6 | 0.3 - 0.7 | Defines the box-overlap level for merging detections | Lower values reduce false positives; higher values may merge distinct objects |
| **Confidence Threshold**| 0.2 - 0.5 | 0.1 - 0.6 | Minimum confidence score required to keep detections | If too many false positives, increase the confidence threshold |
| **✅ Adaptive Slicing** | **Enabled** | Auto-Tuned | **Dynamically adjusts slice sizes based on object density** | **Helps avoid redundant computations and adapts to object distribution** |
| **✅ Multi-Scale Fusion** | **Enabled** | Auto-Tuned | **Merges detections from different scales for improved accuracy** | **Reduces false negatives for small or occluded objects** |
| **✅ Context Integration** | **Enabled** | Auto-Tuned | **Incorporates adjacent slice info to handle occlusions** | **Reduces missing objects near slice boundaries** |
| **✅ Class-Aware NMS** | **Enabled** | Auto-Tuned | Applies NMS per object class to preserve small-object diversity | Helps maintain multiple overlapping objects of different classes |
""")
return demo
############################################
# 6. MAIN
############################################
if __name__ == "__main__":
demo_app = build_app()
demo_app.launch()
|