DawnC commited on
Commit
9d69a6b
1 Parent(s): 606b787

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +165 -331
app.py CHANGED
@@ -165,165 +165,165 @@ def _predict_single_dog(image):
165
  return top1_prob, topk_breeds, topk_probs_percent
166
 
167
 
168
- # async def detect_multiple_dogs(image, conf_threshold=0.25, iou_threshold=0.4):
169
- # results = model_yolo(image, conf=conf_threshold, iou=iou_threshold)[0]
170
- # dogs = []
171
- # for box in results.boxes:
172
- # if box.cls == 16: # COCO 資料集中狗的類別是 16
173
- # xyxy = box.xyxy[0].tolist()
174
- # confidence = box.conf.item()
175
- # cropped_image = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
176
- # dogs.append((cropped_image, confidence, xyxy))
177
- # return dogs
178
 
179
 
180
- # async def predict(image):
181
- # if image is None:
182
- # return "Please upload an image to start.", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), None
183
 
184
- # try:
185
- # if isinstance(image, np.ndarray):
186
- # image = Image.fromarray(image)
187
 
188
- # dogs = await detect_multiple_dogs(image, conf_threshold=0.25, iou_threshold=0.4)
189
 
190
- # if len(dogs) <= 1:
191
- # return await process_single_dog(image)
192
 
193
- # # 多狗情境
194
- # color_list = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF', '#800080', '#FFA500']
195
- # explanations = []
196
- # buttons = []
197
- # annotated_image = image.copy()
198
- # draw = ImageDraw.Draw(annotated_image)
199
- # font = ImageFont.load_default()
200
 
201
- # for i, (cropped_image, _, box) in enumerate(dogs):
202
- # top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(cropped_image)
203
- # color = color_list[i % len(color_list)]
204
- # draw.rectangle(box, outline=color, width=3)
205
- # draw.text((box[0], box[1]), f"Dog {i+1}", fill=color, font=font)
206
 
207
- # breed = topk_breeds[0]
208
- # if top1_prob >= 0.5:
209
- # description = get_dog_description(breed)
210
- # formatted_description = format_description(description, breed)
211
- # explanations.append(f"Dog {i+1}: {formatted_description}")
212
- # elif top1_prob >= 0.2:
213
- # dog_explanation = f"Dog {i+1}: Top 3 possible breeds:\n"
214
- # dog_explanation += "\n".join([f"{j+1}. **{breed}** ({prob} confidence)" for j, (breed, prob) in enumerate(zip(topk_breeds[:3], topk_probs_percent[:3]))])
215
- # explanations.append(dog_explanation)
216
- # buttons.extend([gr.update(visible=True, value=f"Dog {i+1}: More about {breed}") for breed in topk_breeds[:3]])
217
- # else:
218
- # explanations.append(f"Dog {i+1}: The image is unclear or the breed is not in the dataset.")
219
 
220
- # final_explanation = "\n\n".join(explanations)
221
- # if buttons:
222
- # final_explanation += "\n\nClick on a button to view more information about the breed."
223
- # initial_state = {
224
- # "explanation": final_explanation,
225
- # "buttons": buttons,
226
- # "show_back": True
227
- # }
228
- # return (final_explanation, annotated_image,
229
- # buttons[0] if len(buttons) > 0 else gr.update(visible=False),
230
- # buttons[1] if len(buttons) > 1 else gr.update(visible=False),
231
- # buttons[2] if len(buttons) > 2 else gr.update(visible=False),
232
- # gr.update(visible=True),
233
- # initial_state)
234
- # else:
235
- # initial_state = {
236
- # "explanation": final_explanation,
237
- # "buttons": [],
238
- # "show_back": False
239
- # }
240
- # return final_explanation, annotated_image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
241
 
242
- # except Exception as e:
243
- # error_msg = f"An error occurred: {str(e)}"
244
- # print(error_msg) # 添加日誌輸出
245
- # return error_msg, None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), None
246
 
247
 
248
- async def detect_multiple_dogs(image, conf_threshold=0.25, iou_threshold=0.4, merge_threshold=0.5):
249
- results = model_yolo(image, conf=conf_threshold, iou=iou_threshold)[0]
250
- dogs = []
251
 
252
- image_area = image.width * image.height
253
- min_area_ratio = 0.005 # 最小檢測面積佔整個圖像的比例
254
 
255
- for box in results.boxes:
256
- if box.cls == 16: # COCO 數據集中狗的類別是 16
257
- xyxy = box.xyxy[0].tolist()
258
- area = (xyxy[2] - xyxy[0]) * (xyxy[3] - xyxy[1])
259
- if area / image_area >= min_area_ratio:
260
- confidence = box.conf.item()
261
- dogs.append((xyxy, confidence))
262
 
263
- if dogs:
264
- boxes = torch.tensor([dog[0] for dog in dogs])
265
- scores = torch.tensor([dog[1] for dog in dogs])
266
 
267
- # 應用 NMS
268
- keep = nms(boxes, scores, iou_threshold)
269
 
270
- merged_dogs = []
271
- for i in keep:
272
- xyxy = boxes[i].tolist()
273
- confidence = scores[i].item()
274
- merged_dogs.append((xyxy, confidence))
275
 
276
- # 後處��:分離過於接近的檢測框
277
- final_dogs = []
278
- while merged_dogs:
279
- base_dog = merged_dogs.pop(0)
280
- to_merge = [base_dog]
281
 
282
- i = 0
283
- while i < len(merged_dogs):
284
- iou = box_iou(torch.tensor([base_dog[0]]), torch.tensor([merged_dogs[i][0]]))[0][0].item()
285
- if iou > merge_threshold:
286
- to_merge.append(merged_dogs.pop(i))
287
- else:
288
- i += 1
289
 
290
- if len(to_merge) == 1:
291
- final_dogs.append(base_dog)
292
- else:
293
- # 如果檢測到多個重疊框,嘗試分離它們
294
- centers = torch.tensor([[((box[0] + box[2]) / 2, (box[1] + box[3]) / 2)] for box, _ in to_merge])
295
- distances = torch.cdist(centers, centers)
296
 
297
- if torch.any(distances > 0): # 確保不是完全重疊
298
- max_distance = distances.max()
299
- if max_distance > (base_dog[0][2] - base_dog[0][0]) * 0.5: # 如果最大距離大於框寬度的一半
300
- final_dogs.extend(to_merge)
301
- else:
302
- # 合併為一個框
303
- merged_box = torch.tensor([box for box, _ in to_merge]).mean(dim=0)
304
- merged_confidence = max(conf for _, conf in to_merge)
305
- final_dogs.append((merged_box.tolist(), merged_confidence))
306
- else:
307
- # 完全重疊的情況,保留置信度最高的
308
- best_dog = max(to_merge, key=lambda x: x[1])
309
- final_dogs.append(best_dog)
310
 
311
- # 擴展邊界框並創建剪裁的圖像
312
- expanded_dogs = []
313
- for xyxy, confidence in final_dogs:
314
- expanded_xyxy = [
315
- max(0, xyxy[0] - 20),
316
- max(0, xyxy[1] - 20),
317
- min(image.width, xyxy[2] + 20),
318
- min(image.height, xyxy[3] + 20)
319
- ]
320
- cropped_image = image.crop(expanded_xyxy)
321
- expanded_dogs.append((cropped_image, confidence, expanded_xyxy))
322
 
323
- return expanded_dogs
324
 
325
- # 如果沒有檢測到狗狗,返回整張圖片
326
- return [(image, 1.0, [0, 0, image.width, image.height])]
327
 
328
  # async def predict(image):
329
  # if image is None:
@@ -396,166 +396,6 @@ async def detect_multiple_dogs(image, conf_threshold=0.25, iou_threshold=0.4, me
396
  # return error_msg, None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), None
397
 
398
 
399
- # async def process_single_dog(image):
400
- # top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(image)
401
- # if top1_prob < 0.2:
402
- # initial_state = {
403
- # "explanation": "The image is unclear or the breed is not in the dataset. Please upload a clearer image of a dog.",
404
- # "buttons": [],
405
- # "show_back": False
406
- # }
407
- # return initial_state["explanation"], None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
408
-
409
- # breed = topk_breeds[0]
410
- # description = get_dog_description(breed)
411
-
412
- # if top1_prob >= 0.5:
413
- # formatted_description = format_description(description, breed)
414
- # initial_state = {
415
- # "explanation": formatted_description,
416
- # "buttons": [],
417
- # "show_back": False
418
- # }
419
- # return formatted_description, image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
420
- # else:
421
- # explanation = (
422
- # f"The model couldn't confidently identify the breed. Here are the top 3 possible breeds:\n\n"
423
- # f"1. **{topk_breeds[0]}** ({topk_probs_percent[0]} confidence)\n"
424
- # f"2. **{topk_breeds[1]}** ({topk_probs_percent[1]} confidence)\n"
425
- # f"3. **{topk_breeds[2]}** ({topk_probs_percent[2]} confidence)\n\n"
426
- # "Click on a button to view more information about the breed."
427
- # )
428
- # buttons = [
429
- # gr.update(visible=True, value=f"More about {topk_breeds[0]}"),
430
- # gr.update(visible=True, value=f"More about {topk_breeds[1]}"),
431
- # gr.update(visible=True, value=f"More about {topk_breeds[2]}")
432
- # ]
433
- # initial_state = {
434
- # "explanation": explanation,
435
- # "buttons": buttons,
436
- # "show_back": True
437
- # }
438
- # return explanation, image, buttons[0], buttons[1], buttons[2], gr.update(visible=True), initial_state
439
-
440
- # def show_details(choice, previous_output, initial_state):
441
- # if not choice:
442
- # return previous_output, gr.update(visible=True), initial_state
443
-
444
- # try:
445
- # breed = choice.split("More about ")[-1]
446
- # description = get_dog_description(breed)
447
- # formatted_description = format_description(description, breed)
448
- # return formatted_description, gr.update(visible=True), initial_state
449
- # except Exception as e:
450
- # error_msg = f"An error occurred while showing details: {e}"
451
- # print(error_msg) # 添加日誌輸出
452
- # return error_msg, gr.update(visible=True), initial_state
453
-
454
- # # 介面部分
455
- # with gr.Blocks() as iface:
456
- # gr.HTML("<h1 style='text-align: center;'>🐶 Dog Breed Classifier 🔍</h1>")
457
- # gr.HTML("<p style='text-align: center;'>Upload a picture of a dog, and the model will predict its breed, provide detailed information, and include an extra information link!</p>")
458
-
459
- # with gr.Row():
460
- # input_image = gr.Image(label="Upload a dog image", type="pil")
461
- # output_image = gr.Image(label="Annotated Image")
462
-
463
- # output = gr.Markdown(label="Prediction Results")
464
-
465
- # with gr.Row():
466
- # btn1 = gr.Button("View More 1", visible=False)
467
- # btn2 = gr.Button("View More 2", visible=False)
468
- # btn3 = gr.Button("View More 3", visible=False)
469
-
470
- # back_button = gr.Button("Back", visible=False)
471
-
472
- # initial_state = gr.State()
473
-
474
- # input_image.change(
475
- # predict,
476
- # inputs=input_image,
477
- # outputs=[output, output_image, btn1, btn2, btn3, back_button, initial_state]
478
- # )
479
-
480
- # for btn in [btn1, btn2, btn3]:
481
- # btn.click(
482
- # show_details,
483
- # inputs=[btn, output, initial_state],
484
- # outputs=[output, back_button, initial_state]
485
- # )
486
-
487
- # back_button.click(
488
- # lambda state: (state["explanation"],
489
- # state["buttons"][0] if len(state["buttons"]) > 0 else gr.update(visible=False),
490
- # state["buttons"][1] if len(state["buttons"]) > 1 else gr.update(visible=False),
491
- # gr.update(visible=state["show_back"])),
492
- # inputs=[initial_state],
493
- # outputs=[output, btn1, btn2, btn3, back_button]
494
- # )
495
-
496
- # gr.Examples(
497
- # examples=['Border_Collie.jpg', 'Golden_Retriever.jpeg', 'Saint_Bernard.jpeg', 'French_Bulldog.jpeg', 'Samoyed.jpg'],
498
- # inputs=input_image
499
- # )
500
-
501
- # gr.HTML('For more details on this project and other work, feel free to visit my GitHub <a href="https://github.com/Eric-Chung-0511/Learning-Record/tree/main/Data%20Science%20Projects/Dog_Breed_Classifier">Dog Breed Classifier</a>')
502
-
503
- # if __name__ == "__main__":
504
- # iface.launch()
505
-
506
-
507
- async def predict(image):
508
- if image is None:
509
- return "Please upload an image to start.", None, [], gr.update(visible=False), None
510
-
511
- try:
512
- if isinstance(image, np.ndarray):
513
- image = Image.fromarray(image)
514
-
515
- dogs = await detect_multiple_dogs(image)
516
-
517
- if len(dogs) <= 1:
518
- return await process_single_dog(image)
519
-
520
- color_list = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF', '#800080', '#FFA500']
521
- explanations = []
522
- buttons = []
523
- annotated_image = image.copy()
524
- draw = ImageDraw.Draw(annotated_image)
525
- font = ImageFont.load_default()
526
-
527
- for i, (cropped_image, _, box) in enumerate(dogs):
528
- top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(cropped_image)
529
- color = color_list[i % len(color_list)]
530
- draw.rectangle(box, outline=color, width=3)
531
- draw.text((box[0], box[1]), f"Dog {i+1}", fill=color, font=font)
532
-
533
- breed = topk_breeds[0]
534
- if top1_prob >= 0.5:
535
- description = get_dog_description(breed)
536
- formatted_description = format_description(description, breed)
537
- explanations.append(f"Dog {i+1}: {formatted_description}")
538
- else:
539
- dog_explanation = f"Dog {i+1}: Top 3 possible breeds:\n"
540
- dog_explanation += "\n".join([f"{j+1}. **{breed}** ({prob} confidence)" for j, (breed, prob) in enumerate(zip(topk_breeds[:3], topk_probs_percent[:3]))])
541
- explanations.append(dog_explanation)
542
- buttons.extend([f"Dog {i+1}: More about {breed}" for breed in topk_breeds[:3]])
543
-
544
- final_explanation = "\n\n".join(explanations)
545
- if buttons:
546
- final_explanation += "\n\nClick on a button to view more information about the breed."
547
-
548
- initial_state = {
549
- "explanation": final_explanation,
550
- "buttons": buttons,
551
- "show_back": bool(buttons)
552
- }
553
- return final_explanation, annotated_image, buttons, gr.update(visible=bool(buttons)), initial_state
554
-
555
- except Exception as e:
556
- error_msg = f"An error occurred: {str(e)}"
557
- print(error_msg) # 添加日誌輸出
558
- return error_msg, None, [], gr.update(visible=False), None
559
 
560
  async def process_single_dog(image):
561
  top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(image)
@@ -565,7 +405,7 @@ async def process_single_dog(image):
565
  "buttons": [],
566
  "show_back": False
567
  }
568
- return initial_state["explanation"], None, [], gr.update(visible=False), initial_state
569
 
570
  breed = topk_breeds[0]
571
  description = get_dog_description(breed)
@@ -577,7 +417,7 @@ async def process_single_dog(image):
577
  "buttons": [],
578
  "show_back": False
579
  }
580
- return formatted_description, image, [], gr.update(visible=False), initial_state
581
  else:
582
  explanation = (
583
  f"The model couldn't confidently identify the breed. Here are the top 3 possible breeds:\n\n"
@@ -586,13 +426,17 @@ async def process_single_dog(image):
586
  f"3. **{topk_breeds[2]}** ({topk_probs_percent[2]} confidence)\n\n"
587
  "Click on a button to view more information about the breed."
588
  )
589
- buttons = [f"More about {breed}" for breed in topk_breeds[:3]]
 
 
 
 
590
  initial_state = {
591
  "explanation": explanation,
592
  "buttons": buttons,
593
  "show_back": True
594
  }
595
- return explanation, image, buttons, gr.update(visible=True), initial_state
596
 
597
  def show_details(choice, previous_output, initial_state):
598
  if not choice:
@@ -608,6 +452,7 @@ def show_details(choice, previous_output, initial_state):
608
  print(error_msg) # 添加日誌輸出
609
  return error_msg, gr.update(visible=True), initial_state
610
 
 
611
  with gr.Blocks() as iface:
612
  gr.HTML("<h1 style='text-align: center;'>🐶 Dog Breed Classifier 🔍</h1>")
613
  gr.HTML("<p style='text-align: center;'>Upload a picture of a dog, and the model will predict its breed, provide detailed information, and include an extra information link!</p>")
@@ -618,54 +463,43 @@ with gr.Blocks() as iface:
618
 
619
  output = gr.Markdown(label="Prediction Results")
620
 
621
- button_container = gr.Column()
 
 
 
622
 
623
  back_button = gr.Button("Back", visible=False)
624
 
625
  initial_state = gr.State()
626
 
627
- def create_buttons(button_texts):
628
- buttons = []
629
- for text in button_texts:
630
- button = gr.Button(text)
631
- button.click(
632
- show_details,
633
- inputs=[button, output, initial_state],
634
- outputs=[output, back_button, initial_state]
635
- )
636
- buttons.append(button)
637
- return buttons
638
-
639
- def update_ui(explanation, image, button_texts, show_back, state):
640
- button_container.clear()
641
- buttons = create_buttons(button_texts)
642
- return explanation, image, *buttons, gr.update(visible=show_back), state
643
-
644
  input_image.change(
645
  predict,
646
  inputs=input_image,
647
- outputs=[output, output_image, button_container, back_button, initial_state]
648
- ).then(
649
- update_ui,
650
- inputs=[output, output_image, button_container, back_button, initial_state],
651
- outputs=[output, output_image] + [button_container] * 9 + [back_button, initial_state]
652
  )
653
-
654
- def go_back(state):
655
- return update_ui(state["explanation"], None, state["buttons"], state["show_back"], state)
 
 
 
 
656
 
657
  back_button.click(
658
- go_back,
 
 
 
659
  inputs=[initial_state],
660
- outputs=[output, output_image] + [button_container] * 9 + [back_button, initial_state]
661
  )
662
-
663
  gr.Examples(
664
  examples=['Border_Collie.jpg', 'Golden_Retriever.jpeg', 'Saint_Bernard.jpeg', 'French_Bulldog.jpeg', 'Samoyed.jpg'],
665
  inputs=input_image
666
  )
667
-
668
  gr.HTML('For more details on this project and other work, feel free to visit my GitHub <a href="https://github.com/Eric-Chung-0511/Learning-Record/tree/main/Data%20Science%20Projects/Dog_Breed_Classifier">Dog Breed Classifier</a>')
669
 
670
- if __name__ == "__main__":
671
- iface.launch()
 
165
  return top1_prob, topk_breeds, topk_probs_percent
166
 
167
 
168
+ async def detect_multiple_dogs(image, conf_threshold=0.25, iou_threshold=0.4):
169
+ results = model_yolo(image, conf=conf_threshold, iou=iou_threshold)[0]
170
+ dogs = []
171
+ for box in results.boxes:
172
+ if box.cls == 16: # COCO 資料集中狗的類別是 16
173
+ xyxy = box.xyxy[0].tolist()
174
+ confidence = box.conf.item()
175
+ cropped_image = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
176
+ dogs.append((cropped_image, confidence, xyxy))
177
+ return dogs
178
 
179
 
180
+ async def predict(image):
181
+ if image is None:
182
+ return "Please upload an image to start.", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), None
183
 
184
+ try:
185
+ if isinstance(image, np.ndarray):
186
+ image = Image.fromarray(image)
187
 
188
+ dogs = await detect_multiple_dogs(image, conf_threshold=0.25, iou_threshold=0.4)
189
 
190
+ if len(dogs) <= 1:
191
+ return await process_single_dog(image)
192
 
193
+ # 多狗情境
194
+ color_list = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF', '#800080', '#FFA500']
195
+ explanations = []
196
+ buttons = []
197
+ annotated_image = image.copy()
198
+ draw = ImageDraw.Draw(annotated_image)
199
+ font = ImageFont.load_default()
200
 
201
+ for i, (cropped_image, _, box) in enumerate(dogs):
202
+ top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(cropped_image)
203
+ color = color_list[i % len(color_list)]
204
+ draw.rectangle(box, outline=color, width=3)
205
+ draw.text((box[0], box[1]), f"Dog {i+1}", fill=color, font=font)
206
 
207
+ breed = topk_breeds[0]
208
+ if top1_prob >= 0.5:
209
+ description = get_dog_description(breed)
210
+ formatted_description = format_description(description, breed)
211
+ explanations.append(f"Dog {i+1}: {formatted_description}")
212
+ elif top1_prob >= 0.2:
213
+ dog_explanation = f"Dog {i+1}: Top 3 possible breeds:\n"
214
+ dog_explanation += "\n".join([f"{j+1}. **{breed}** ({prob} confidence)" for j, (breed, prob) in enumerate(zip(topk_breeds[:3], topk_probs_percent[:3]))])
215
+ explanations.append(dog_explanation)
216
+ buttons.extend([gr.update(visible=True, value=f"Dog {i+1}: More about {breed}") for breed in topk_breeds[:3]])
217
+ else:
218
+ explanations.append(f"Dog {i+1}: The image is unclear or the breed is not in the dataset.")
219
 
220
+ final_explanation = "\n\n".join(explanations)
221
+ if buttons:
222
+ final_explanation += "\n\nClick on a button to view more information about the breed."
223
+ initial_state = {
224
+ "explanation": final_explanation,
225
+ "buttons": buttons,
226
+ "show_back": True
227
+ }
228
+ return (final_explanation, annotated_image,
229
+ buttons[0] if len(buttons) > 0 else gr.update(visible=False),
230
+ buttons[1] if len(buttons) > 1 else gr.update(visible=False),
231
+ buttons[2] if len(buttons) > 2 else gr.update(visible=False),
232
+ gr.update(visible=True),
233
+ initial_state)
234
+ else:
235
+ initial_state = {
236
+ "explanation": final_explanation,
237
+ "buttons": [],
238
+ "show_back": False
239
+ }
240
+ return final_explanation, annotated_image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
241
 
242
+ except Exception as e:
243
+ error_msg = f"An error occurred: {str(e)}"
244
+ print(error_msg) # 添加日誌輸出
245
+ return error_msg, None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), None
246
 
247
 
248
+ # async def detect_multiple_dogs(image, conf_threshold=0.25, iou_threshold=0.4, merge_threshold=0.5):
249
+ # results = model_yolo(image, conf=conf_threshold, iou=iou_threshold)[0]
250
+ # dogs = []
251
 
252
+ # image_area = image.width * image.height
253
+ # min_area_ratio = 0.005 # 最小檢測面積佔整個圖像的比例
254
 
255
+ # for box in results.boxes:
256
+ # if box.cls == 16: # COCO 數據集中狗的類別是 16
257
+ # xyxy = box.xyxy[0].tolist()
258
+ # area = (xyxy[2] - xyxy[0]) * (xyxy[3] - xyxy[1])
259
+ # if area / image_area >= min_area_ratio:
260
+ # confidence = box.conf.item()
261
+ # dogs.append((xyxy, confidence))
262
 
263
+ # if dogs:
264
+ # boxes = torch.tensor([dog[0] for dog in dogs])
265
+ # scores = torch.tensor([dog[1] for dog in dogs])
266
 
267
+ # # 應用 NMS
268
+ # keep = nms(boxes, scores, iou_threshold)
269
 
270
+ # merged_dogs = []
271
+ # for i in keep:
272
+ # xyxy = boxes[i].tolist()
273
+ # confidence = scores[i].item()
274
+ # merged_dogs.append((xyxy, confidence))
275
 
276
+ # # 後處理:分離過於接近的檢測框
277
+ # final_dogs = []
278
+ # while merged_dogs:
279
+ # base_dog = merged_dogs.pop(0)
280
+ # to_merge = [base_dog]
281
 
282
+ # i = 0
283
+ # while i < len(merged_dogs):
284
+ # iou = box_iou(torch.tensor([base_dog[0]]), torch.tensor([merged_dogs[i][0]]))[0][0].item()
285
+ # if iou > merge_threshold:
286
+ # to_merge.append(merged_dogs.pop(i))
287
+ # else:
288
+ # i += 1
289
 
290
+ # if len(to_merge) == 1:
291
+ # final_dogs.append(base_dog)
292
+ # else:
293
+ # # 如果檢測到多個重疊框,嘗試分離它們
294
+ # centers = torch.tensor([[((box[0] + box[2]) / 2, (box[1] + box[3]) / 2)] for box, _ in to_merge])
295
+ # distances = torch.cdist(centers, centers)
296
 
297
+ # if torch.any(distances > 0): # 確保不是完全重疊
298
+ # max_distance = distances.max()
299
+ # if max_distance > (base_dog[0][2] - base_dog[0][0]) * 0.5: # 如果最大距離大於框寬度的一半
300
+ # final_dogs.extend(to_merge)
301
+ # else:
302
+ # # 合併為一個框
303
+ # merged_box = torch.tensor([box for box, _ in to_merge]).mean(dim=0)
304
+ # merged_confidence = max(conf for _, conf in to_merge)
305
+ # final_dogs.append((merged_box.tolist(), merged_confidence))
306
+ # else:
307
+ # # 完全重疊的情況,保留置信度最高的
308
+ # best_dog = max(to_merge, key=lambda x: x[1])
309
+ # final_dogs.append(best_dog)
310
 
311
+ # # 擴展邊界框並創建剪裁的圖像
312
+ # expanded_dogs = []
313
+ # for xyxy, confidence in final_dogs:
314
+ # expanded_xyxy = [
315
+ # max(0, xyxy[0] - 20),
316
+ # max(0, xyxy[1] - 20),
317
+ # min(image.width, xyxy[2] + 20),
318
+ # min(image.height, xyxy[3] + 20)
319
+ # ]
320
+ # cropped_image = image.crop(expanded_xyxy)
321
+ # expanded_dogs.append((cropped_image, confidence, expanded_xyxy))
322
 
323
+ # return expanded_dogs
324
 
325
+ # # 如果沒有檢測到狗狗,返回整張圖片
326
+ # return [(image, 1.0, [0, 0, image.width, image.height])]
327
 
328
  # async def predict(image):
329
  # if image is None:
 
396
  # return error_msg, None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), None
397
 
398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
 
400
  async def process_single_dog(image):
401
  top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(image)
 
405
  "buttons": [],
406
  "show_back": False
407
  }
408
+ return initial_state["explanation"], None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
409
 
410
  breed = topk_breeds[0]
411
  description = get_dog_description(breed)
 
417
  "buttons": [],
418
  "show_back": False
419
  }
420
+ return formatted_description, image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
421
  else:
422
  explanation = (
423
  f"The model couldn't confidently identify the breed. Here are the top 3 possible breeds:\n\n"
 
426
  f"3. **{topk_breeds[2]}** ({topk_probs_percent[2]} confidence)\n\n"
427
  "Click on a button to view more information about the breed."
428
  )
429
+ buttons = [
430
+ gr.update(visible=True, value=f"More about {topk_breeds[0]}"),
431
+ gr.update(visible=True, value=f"More about {topk_breeds[1]}"),
432
+ gr.update(visible=True, value=f"More about {topk_breeds[2]}")
433
+ ]
434
  initial_state = {
435
  "explanation": explanation,
436
  "buttons": buttons,
437
  "show_back": True
438
  }
439
+ return explanation, image, buttons[0], buttons[1], buttons[2], gr.update(visible=True), initial_state
440
 
441
  def show_details(choice, previous_output, initial_state):
442
  if not choice:
 
452
  print(error_msg) # 添加日誌輸出
453
  return error_msg, gr.update(visible=True), initial_state
454
 
455
+ # 介面部分
456
  with gr.Blocks() as iface:
457
  gr.HTML("<h1 style='text-align: center;'>🐶 Dog Breed Classifier 🔍</h1>")
458
  gr.HTML("<p style='text-align: center;'>Upload a picture of a dog, and the model will predict its breed, provide detailed information, and include an extra information link!</p>")
 
463
 
464
  output = gr.Markdown(label="Prediction Results")
465
 
466
+ with gr.Row():
467
+ btn1 = gr.Button("View More 1", visible=False)
468
+ btn2 = gr.Button("View More 2", visible=False)
469
+ btn3 = gr.Button("View More 3", visible=False)
470
 
471
  back_button = gr.Button("Back", visible=False)
472
 
473
  initial_state = gr.State()
474
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  input_image.change(
476
  predict,
477
  inputs=input_image,
478
+ outputs=[output, output_image, btn1, btn2, btn3, back_button, initial_state]
 
 
 
 
479
  )
480
+
481
+ for btn in [btn1, btn2, btn3]:
482
+ btn.click(
483
+ show_details,
484
+ inputs=[btn, output, initial_state],
485
+ outputs=[output, back_button, initial_state]
486
+ )
487
 
488
  back_button.click(
489
+ lambda state: (state["explanation"],
490
+ state["buttons"][0] if len(state["buttons"]) > 0 else gr.update(visible=False),
491
+ state["buttons"][1] if len(state["buttons"]) > 1 else gr.update(visible=False),
492
+ gr.update(visible=state["show_back"])),
493
  inputs=[initial_state],
494
+ outputs=[output, btn1, btn2, btn3, back_button]
495
  )
496
+
497
  gr.Examples(
498
  examples=['Border_Collie.jpg', 'Golden_Retriever.jpeg', 'Saint_Bernard.jpeg', 'French_Bulldog.jpeg', 'Samoyed.jpg'],
499
  inputs=input_image
500
  )
501
+
502
  gr.HTML('For more details on this project and other work, feel free to visit my GitHub <a href="https://github.com/Eric-Chung-0511/Learning-Record/tree/main/Data%20Science%20Projects/Dog_Breed_Classifier">Dog Breed Classifier</a>')
503
 
504
+ if __name__ == "__main__":
505
+ iface.launch()