Update app.py
Browse files
app.py
CHANGED
|
@@ -119,7 +119,13 @@ def create_match_visualization(img_path1, img_path2, kpts0, kpts1, matches, outp
|
|
| 119 |
return output_path
|
| 120 |
|
| 121 |
def predict(input_path):
|
| 122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
# --- 0. GROUND TRUTH ---
|
| 125 |
true_species, true_id = "Unknown", "Unknown"
|
|
@@ -159,9 +165,11 @@ def predict(input_path):
|
|
| 159 |
# --- 3. FINE SEARCH & VISUALIZATION LOOP ---
|
| 160 |
feats_q = extractor.extract(load_image(input_path).to(DEVICE))
|
| 161 |
|
| 162 |
-
log = "🔍 **Analysis Process:**\n"
|
| 163 |
best_score = -1
|
| 164 |
best_candidate_idx = -1
|
|
|
|
|
|
|
|
|
|
| 165 |
cand_viz_paths = [None, None, None]
|
| 166 |
|
| 167 |
for rank, (idx, arcface_sim) in enumerate(unique_candidates):
|
|
@@ -180,9 +188,10 @@ def predict(input_path):
|
|
| 180 |
geo_matches = len(matches["matches"])
|
| 181 |
sim_percent = arcface_sim * 100
|
| 182 |
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
|
|
|
| 186 |
|
| 187 |
viz_name = f"viz_rank_{rank}"
|
| 188 |
viz_path = create_match_visualization(
|
|
@@ -197,7 +206,7 @@ def predict(input_path):
|
|
| 197 |
best_candidate_idx = idx
|
| 198 |
|
| 199 |
except Exception as e:
|
| 200 |
-
|
| 201 |
|
| 202 |
# --- 4. FINAL DECISION ---
|
| 203 |
CONFIDENCE_THRESHOLD = 15
|
|
@@ -205,61 +214,63 @@ def predict(input_path):
|
|
| 205 |
pred_species = g_species[best_candidate_idx]
|
| 206 |
pred_id = g_labels[best_candidate_idx]
|
| 207 |
is_correct = (pred_id == true_id)
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
header
|
| 212 |
-
|
|
|
|
| 213 |
header += f"*(Confirmed with {best_score} geometric keypoints)*"
|
| 214 |
else:
|
| 215 |
-
header = "# ⚠️ UNKNOWN / NO MATCH\n"
|
| 216 |
header += f"**Ground Truth:** {true_species} / {true_id}\n"
|
| 217 |
-
header += f"**
|
| 218 |
|
| 219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
|
| 221 |
-
# ---
|
| 222 |
examples_list = []
|
| 223 |
if os.path.exists(TEST_QUERIES_DIR):
|
| 224 |
examples_list = [os.path.join(TEST_QUERIES_DIR, f) for f in os.listdir(TEST_QUERIES_DIR) if f.lower().endswith(('.jpg', '.png'))]
|
| 225 |
|
| 226 |
with gr.Blocks(title="Wildlife Re-ID: Coarse-to-Fine Demo") as demo:
|
| 227 |
gr.Markdown("# Wildlife Re-ID: Coarse-to-Fine Demo")
|
| 228 |
-
gr.Markdown("Select a test image
|
| 229 |
|
| 230 |
with gr.Row():
|
| 231 |
-
# --- Left Column: Input
|
| 232 |
with gr.Column(scale=1):
|
| 233 |
input_img = gr.Image(type="filepath", label="Test Image", height=300)
|
| 234 |
-
|
| 235 |
-
# EXAMPLES directly under the input image
|
| 236 |
-
gr.Examples(
|
| 237 |
-
examples=examples_list,
|
| 238 |
-
inputs=input_img,
|
| 239 |
-
label="Test Examples (Click to Select)",
|
| 240 |
-
examples_per_page=5
|
| 241 |
-
)
|
| 242 |
-
|
| 243 |
submit_btn = gr.Button("Run Identification", variant="primary", size="lg")
|
| 244 |
|
| 245 |
-
# --- Right Column:
|
| 246 |
with gr.Column(scale=2):
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
|
| 257 |
-
# connect the button click to the function
|
| 258 |
submit_btn.click(
|
| 259 |
fn=predict,
|
| 260 |
inputs=input_img,
|
| 261 |
-
outputs=[
|
| 262 |
)
|
| 263 |
|
| 264 |
-
# Fix: Move CSS to launch
|
| 265 |
demo.launch(allowed_paths=[TEST_QUERIES_DIR])
|
|
|
|
| 119 |
return output_path
|
| 120 |
|
| 121 |
def predict(input_path):
|
| 122 |
+
# Default return values (empty)
|
| 123 |
+
default_header = "Please upload an image."
|
| 124 |
+
default_logs = ["", "", ""]
|
| 125 |
+
default_imgs = [None, None, None]
|
| 126 |
+
|
| 127 |
+
if input_path is None:
|
| 128 |
+
return default_header, default_logs[0], default_imgs[0], default_logs[1], default_imgs[1], default_logs[2], default_imgs[2]
|
| 129 |
|
| 130 |
# --- 0. GROUND TRUTH ---
|
| 131 |
true_species, true_id = "Unknown", "Unknown"
|
|
|
|
| 165 |
# --- 3. FINE SEARCH & VISUALIZATION LOOP ---
|
| 166 |
feats_q = extractor.extract(load_image(input_path).to(DEVICE))
|
| 167 |
|
|
|
|
| 168 |
best_score = -1
|
| 169 |
best_candidate_idx = -1
|
| 170 |
+
|
| 171 |
+
# Initialize output lists (size 3)
|
| 172 |
+
cand_logs = ["Waiting for data...", "Waiting for data...", "Waiting for data..."]
|
| 173 |
cand_viz_paths = [None, None, None]
|
| 174 |
|
| 175 |
for rank, (idx, arcface_sim) in enumerate(unique_candidates):
|
|
|
|
| 188 |
geo_matches = len(matches["matches"])
|
| 189 |
sim_percent = arcface_sim * 100
|
| 190 |
|
| 191 |
+
# --- CREATE INDIVIDUAL LOG STRING ---
|
| 192 |
+
log_str = f"### Candidate {rank+1}: {species} / {label}\n"
|
| 193 |
+
log_str += f"**🧠 Coarse Confidence:** {sim_percent:.1f}% | **📐 Geometric Matches:** {geo_matches}"
|
| 194 |
+
cand_logs[rank] = log_str
|
| 195 |
|
| 196 |
viz_name = f"viz_rank_{rank}"
|
| 197 |
viz_path = create_match_visualization(
|
|
|
|
| 206 |
best_candidate_idx = idx
|
| 207 |
|
| 208 |
except Exception as e:
|
| 209 |
+
cand_logs[rank] = f"Error processing candidate: {e}"
|
| 210 |
|
| 211 |
# --- 4. FINAL DECISION ---
|
| 212 |
CONFIDENCE_THRESHOLD = 15
|
|
|
|
| 214 |
pred_species = g_species[best_candidate_idx]
|
| 215 |
pred_id = g_labels[best_candidate_idx]
|
| 216 |
is_correct = (pred_id == true_id)
|
| 217 |
+
|
| 218 |
+
if true_id == "Unknown": header = f"### ❓ MATCH FOUND (No Ground Truth)\n"
|
| 219 |
+
elif is_correct: header = f"### ✅ CORRECT MATCH!\n"
|
| 220 |
+
else: header = f"### ❌ INCORRECT MATCH\n"
|
| 221 |
+
|
| 222 |
+
header += f"**Ground Truth:** {true_species} / {true_id} ➡️ **Prediction:** {pred_species} / {pred_id}\n"
|
| 223 |
header += f"*(Confirmed with {best_score} geometric keypoints)*"
|
| 224 |
else:
|
| 225 |
+
header = "### ⚠️ UNKNOWN / NO MATCH\n"
|
| 226 |
header += f"**Ground Truth:** {true_species} / {true_id}\n"
|
| 227 |
+
header += f"**Prediction:** None (Best match only had {best_score} keypoints)\n"
|
| 228 |
|
| 229 |
+
# Return: Header, then (Log, Img) for Cand 1, then (Log, Img) for Cand 2, etc.
|
| 230 |
+
return (header,
|
| 231 |
+
cand_logs[0], cand_viz_paths[0],
|
| 232 |
+
cand_logs[1], cand_viz_paths[1],
|
| 233 |
+
cand_logs[2], cand_viz_paths[2])
|
| 234 |
|
| 235 |
+
# --- UI SETUP ---
|
| 236 |
examples_list = []
|
| 237 |
if os.path.exists(TEST_QUERIES_DIR):
|
| 238 |
examples_list = [os.path.join(TEST_QUERIES_DIR, f) for f in os.listdir(TEST_QUERIES_DIR) if f.lower().endswith(('.jpg', '.png'))]
|
| 239 |
|
| 240 |
with gr.Blocks(title="Wildlife Re-ID: Coarse-to-Fine Demo") as demo:
|
| 241 |
gr.Markdown("# Wildlife Re-ID: Coarse-to-Fine Demo")
|
| 242 |
+
gr.Markdown("Select a test image. The system finds the Top 3 UNIQUE individuals using embeddings, then verifies them using geometry.")
|
| 243 |
|
| 244 |
with gr.Row():
|
| 245 |
+
# --- Left Column: Input ---
|
| 246 |
with gr.Column(scale=1):
|
| 247 |
input_img = gr.Image(type="filepath", label="Test Image", height=300)
|
| 248 |
+
gr.Examples(examples=examples_list, inputs=input_img, label="Test Examples", examples_per_page=4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
submit_btn = gr.Button("Run Identification", variant="primary", size="lg")
|
| 250 |
|
| 251 |
+
# --- Right Column: Vertical Stack of Candidates ---
|
| 252 |
with gr.Column(scale=2):
|
| 253 |
+
header_md = gr.Markdown(label="Final Decision")
|
| 254 |
+
|
| 255 |
+
# Candidate 1 Group
|
| 256 |
+
with gr.Group():
|
| 257 |
+
log1 = gr.Markdown()
|
| 258 |
+
img1 = gr.Image(label="Visualization", height=450, show_download_button=False)
|
| 259 |
+
|
| 260 |
+
# Candidate 2 Group
|
| 261 |
+
with gr.Group():
|
| 262 |
+
log2 = gr.Markdown()
|
| 263 |
+
img2 = gr.Image(label="Visualization", height=450, show_download_button=False)
|
| 264 |
+
|
| 265 |
+
# Candidate 3 Group
|
| 266 |
+
with gr.Group():
|
| 267 |
+
log3 = gr.Markdown()
|
| 268 |
+
img3 = gr.Image(label="Visualization", height=450, show_download_button=False)
|
| 269 |
|
|
|
|
| 270 |
submit_btn.click(
|
| 271 |
fn=predict,
|
| 272 |
inputs=input_img,
|
| 273 |
+
outputs=[header_md, log1, img1, log2, img2, log3, img3]
|
| 274 |
)
|
| 275 |
|
|
|
|
| 276 |
demo.launch(allowed_paths=[TEST_QUERIES_DIR])
|