DawnC commited on
Commit
86d9dde
1 Parent(s): 1044c24

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -111
app.py CHANGED
@@ -312,7 +312,7 @@ def _predict_single_dog(image):
312
  # return dogs
313
  # 此為如果後面調不好 使用的版本
314
 
315
- async def detect_multiple_dogs(image, conf_threshold=0.1, iou_threshold=0.3):
316
  results = model_yolo(image, conf=conf_threshold, iou=iou_threshold)[0]
317
  dogs = []
318
  for box in results.boxes:
@@ -320,33 +320,45 @@ async def detect_multiple_dogs(image, conf_threshold=0.1, iou_threshold=0.3):
320
  xyxy = box.xyxy[0].tolist()
321
  confidence = box.conf.item()
322
  area = (xyxy[2] - xyxy[0]) * (xyxy[3] - xyxy[1])
323
- image_area = image.width * image.height
324
- if area > 0.005 * image_area: # 降低面積閾值以檢測更多狗
325
  cropped_image = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
326
  dogs.append((cropped_image, confidence, xyxy))
327
 
328
- # 如果檢測到的狗太少,嘗試降低閾值再次檢測
329
- if len(dogs) < 2:
330
- results = model_yolo(image, conf=conf_threshold/2, iou=iou_threshold)[0]
331
- for box in results.boxes:
332
- if box.cls == 16:
333
- xyxy = box.xyxy[0].tolist()
334
- confidence = box.conf.item()
335
- area = (xyxy[2] - xyxy[0]) * (xyxy[3] - xyxy[1])
336
- image_area = image.width * image.height
337
- if area > 0.005 * image_area and not is_box_duplicate(xyxy, [d[2] for d in dogs]):
338
- cropped_image = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
339
- dogs.append((cropped_image, confidence, xyxy))
340
 
341
  return dogs
342
 
343
- def is_box_duplicate(new_box, existing_boxes, iou_threshold=0.5):
344
- for box in existing_boxes:
345
- if calculate_iou(new_box, box) > iou_threshold:
346
- return True
347
- return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
 
349
  def calculate_iou(box1, box2):
 
350
  x1 = max(box1[0], box2[0])
351
  y1 = max(box1[1], box2[1])
352
  x2 = min(box1[2], box2[2])
@@ -474,48 +486,72 @@ def calculate_iou(box1, box2):
474
 
475
  async def predict(image):
476
  if image is None:
477
- 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
478
 
479
  try:
480
  if isinstance(image, np.ndarray):
481
  image = Image.fromarray(image)
482
 
483
- # 首先使用YOLO檢測是否有多隻狗
484
- dogs = await detect_multiple_dogs(image)
485
 
486
  if len(dogs) <= 1:
487
- # 單狗情境或沒有檢測到狗,使用整張圖片進行預測
488
  return await process_single_dog(image)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  else:
490
- # 多狗情境
491
- return await process_multiple_dogs(image, dogs)
492
 
493
  except Exception as e:
494
- error_msg = f"An error occurred: {str(e)}"
495
- print(error_msg) # 添加日誌輸出
496
- return error_msg, None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), None
497
-
498
- def has_multiple_dogs(image):
499
- gray = image.convert('L')
500
- edges = gray.filter(ImageFilter.FIND_EDGES)
501
- edge_pixels = np.array(edges)
502
- return np.sum(edge_pixels > 128) > image.width * image.height * 0.1
503
 
504
  async def process_single_dog(image):
505
  top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(image)
506
-
 
 
507
  breed = topk_breeds[0]
508
  description = get_dog_description(breed)
509
 
510
  if top1_prob >= 0.5:
511
  formatted_description = format_description(description, breed)
512
- initial_state = {
513
- "explanation": formatted_description,
514
- "buttons": [],
515
- "show_back": False
516
- }
517
- return formatted_description, image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
518
- elif top1_prob >= 0.2:
519
  explanation = (
520
  f"The model couldn't confidently identify the breed. Here are the top 3 possible breeds:\n\n"
521
  f"1. **{topk_breeds[0]}** ({topk_probs_percent[0]} confidence)\n"
@@ -523,80 +559,18 @@ async def process_single_dog(image):
523
  f"3. **{topk_breeds[2]}** ({topk_probs_percent[2]} confidence)\n\n"
524
  "Click on a button to view more information about the breed."
525
  )
526
- buttons = [
527
- gr.update(visible=True, value=f"More about {topk_breeds[0]}"),
528
- gr.update(visible=True, value=f"More about {topk_breeds[1]}"),
529
- gr.update(visible=True, value=f"More about {topk_breeds[2]}")
530
- ]
531
- initial_state = {
532
- "explanation": explanation,
533
- "buttons": buttons,
534
- "show_back": True
535
- }
536
- return explanation, image, buttons[0], buttons[1], buttons[2], gr.update(visible=True), initial_state
537
- else:
538
- initial_state = {
539
- "explanation": "The image is unclear or the breed is not in the dataset. Please upload a clearer image of a dog.",
540
- "buttons": [],
541
- "show_back": False
542
- }
543
- return initial_state["explanation"], None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
544
-
545
- async def process_multiple_dogs(image, dogs):
546
- color_list = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF', '#800080', '#FFA500']
547
- explanations = []
548
- buttons = []
549
- annotated_image = image.copy()
550
- draw = ImageDraw.Draw(annotated_image)
551
- font = ImageFont.load_default()
552
-
553
- for i, (cropped_image, _, box) in enumerate(dogs):
554
- top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(cropped_image)
555
- color = color_list[i % len(color_list)]
556
- draw.rectangle(box, outline=color, width=3)
557
- draw.text((box[0], box[1]), f"Dog {i+1}", fill=color, font=font)
558
-
559
- breed = topk_breeds[0]
560
- if top1_prob >= 0.5:
561
- description = get_dog_description(breed)
562
- formatted_description = format_description(description, breed)
563
- explanations.append(f"Dog {i+1}: {formatted_description}")
564
- elif top1_prob >= 0.2:
565
- dog_explanation = f"Dog {i+1}: Top 3 possible breeds:\n"
566
- dog_explanation += "\n".join([f"{j+1}. **{breed}** ({prob} confidence)" for j, (breed, prob) in enumerate(zip(topk_breeds[:3], topk_probs_percent[:3]))])
567
- explanations.append(dog_explanation)
568
- buttons.extend([gr.update(visible=True, value=f"Dog {i+1}: More about {breed}") for breed in topk_breeds[:3]])
569
- else:
570
- explanations.append(f"Dog {i+1}: The image is unclear or the breed is not in the dataset.")
571
-
572
- final_explanation = "\n\n".join(explanations)
573
- if buttons:
574
- final_explanation += "\n\nClick on a button to view more information about the breed."
575
- initial_state = {
576
- "explanation": final_explanation,
577
- "buttons": buttons,
578
- "show_back": True
579
- }
580
- return (final_explanation, annotated_image,
581
- buttons[0] if len(buttons) > 0 else gr.update(visible=False),
582
- buttons[1] if len(buttons) > 1 else gr.update(visible=False),
583
- buttons[2] if len(buttons) > 2 else gr.update(visible=False),
584
- gr.update(visible=True),
585
- initial_state)
586
- else:
587
- initial_state = {
588
- "explanation": final_explanation,
589
- "buttons": [],
590
- "show_back": False
591
- }
592
- return final_explanation, annotated_image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), initial_state
593
 
594
  def show_details(choice, previous_output):
595
  if not choice:
596
  return previous_output, gr.update(visible=True)
597
 
598
  try:
599
- breed = choice.split("More about ")[-1].split(": ")[-1]
600
  description = get_dog_description(breed)
601
  return format_description(description, breed), gr.update(visible=True)
602
  except Exception as e:
 
312
  # return dogs
313
  # 此為如果後面調不好 使用的版本
314
 
315
+ async def detect_multiple_dogs(image, conf_threshold=0.3, iou_threshold=0.5):
316
  results = model_yolo(image, conf=conf_threshold, iou=iou_threshold)[0]
317
  dogs = []
318
  for box in results.boxes:
 
320
  xyxy = box.xyxy[0].tolist()
321
  confidence = box.conf.item()
322
  area = (xyxy[2] - xyxy[0]) * (xyxy[3] - xyxy[1])
323
+ if area > 1000: # 過濾掉太小的檢測框
 
324
  cropped_image = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
325
  dogs.append((cropped_image, confidence, xyxy))
326
 
327
+ # 合併重疊的檢測框
328
+ dogs = merge_overlapping_boxes(dogs, iou_threshold=0.6)
 
 
 
 
 
 
 
 
 
 
329
 
330
  return dogs
331
 
332
+ def merge_overlapping_boxes(dogs, iou_threshold=0.6):
333
+ merged_dogs = []
334
+ while dogs:
335
+ base = dogs.pop(0)
336
+ i = 0
337
+ while i < len(dogs):
338
+ if calculate_iou(base[2], dogs[i][2]) > iou_threshold:
339
+ # 合併重疊的框
340
+ base = merge_boxes(base, dogs.pop(i))
341
+ else:
342
+ i += 1
343
+ merged_dogs.append(base)
344
+ return merged_dogs
345
+
346
+ def merge_boxes(box1, box2):
347
+ xyxy1, conf1, _ = box1
348
+ xyxy2, conf2, _ = box2
349
+ merged_xyxy = [
350
+ min(xyxy1[0], xyxy2[0]),
351
+ min(xyxy1[1], xyxy2[1]),
352
+ max(xyxy1[2], xyxy2[2]),
353
+ max(xyxy1[3], xyxy2[3])
354
+ ]
355
+ merged_conf = max(conf1, conf2)
356
+ merged_image = Image.new('RGB', (int(merged_xyxy[2] - merged_xyxy[0]), int(merged_xyxy[3] - merged_xyxy[1])))
357
+ merged_image.paste(box1[0], (0, 0))
358
+ return (merged_image, merged_conf, merged_xyxy)
359
 
360
  def calculate_iou(box1, box2):
361
+ # 計算兩個邊界框的交集面積
362
  x1 = max(box1[0], box2[0])
363
  y1 = max(box1[1], box2[1])
364
  x2 = min(box1[2], box2[2])
 
486
 
487
  async def predict(image):
488
  if image is None:
489
+ return "Please upload an image to start.", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
490
 
491
  try:
492
  if isinstance(image, np.ndarray):
493
  image = Image.fromarray(image)
494
 
495
+ # 嘗試檢測多隻狗,進一步降低閾值以提高檢測率
496
+ dogs = await detect_multiple_dogs(image, conf_threshold=0.05) # 降低閾值以檢測更多狗
497
 
498
  if len(dogs) <= 1:
499
+ # 單狗情境
500
  return await process_single_dog(image)
501
+
502
+ # 多狗情境
503
+ color_list = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF', '#800080', '#FFA500']
504
+ explanations = []
505
+ buttons = []
506
+ annotated_image = image.copy()
507
+ draw = ImageDraw.Draw(annotated_image)
508
+ font = ImageFont.load_default()
509
+
510
+ for i, (cropped_image, _, box) in enumerate(dogs):
511
+ top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(cropped_image)
512
+ color = color_list[i % len(color_list)]
513
+ draw.rectangle(box, outline=color, width=3)
514
+ draw.text((box[0], box[1]), f"Dog {i+1}", fill=color, font=font)
515
+
516
+ breed = topk_breeds[0]
517
+ if top1_prob >= 0.5:
518
+ description = get_dog_description(breed)
519
+ formatted_description = format_description(description, breed)
520
+ explanations.append(f"Dog {i+1}: {formatted_description}")
521
+ elif top1_prob >= 0.2:
522
+ dog_explanation = f"Dog {i+1}: Top 3 possible breeds:\n"
523
+ dog_explanation += "\n".join([f"{j+1}. **{breed}** ({prob} confidence)" for j, (breed, prob) in enumerate(zip(topk_breeds[:3], topk_probs_percent[:3]))])
524
+ explanations.append(dog_explanation)
525
+ buttons.extend([gr.update(visible=True, value=f"Dog {i+1}: More about {breed}") for breed in topk_breeds[:3]])
526
+ else:
527
+ explanations.append(f"Dog {i+1}: The image is unclear or the breed is not in the dataset.")
528
+
529
+ final_explanation = "\n\n".join(explanations)
530
+ if buttons:
531
+ final_explanation += "\n\nClick on a button to view more information about the breed."
532
+ return (final_explanation, annotated_image,
533
+ buttons[0] if len(buttons) > 0 else gr.update(visible=False),
534
+ buttons[1] if len(buttons) > 1 else gr.update(visible=False),
535
+ buttons[2] if len(buttons) > 2 else gr.update(visible=False),
536
+ gr.update(visible=True)) # 顯示 back 按鈕
537
  else:
538
+ return final_explanation, annotated_image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
 
539
 
540
  except Exception as e:
541
+ return f"An error occurred: {str(e)}", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
 
 
 
 
 
 
 
 
542
 
543
  async def process_single_dog(image):
544
  top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(image)
545
+ if top1_prob < 0.2:
546
+ return "The image is unclear or the breed is not in the dataset. Please upload a clearer image of a dog.", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
547
+
548
  breed = topk_breeds[0]
549
  description = get_dog_description(breed)
550
 
551
  if top1_prob >= 0.5:
552
  formatted_description = format_description(description, breed)
553
+ return formatted_description, image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
554
+ else:
 
 
 
 
 
555
  explanation = (
556
  f"The model couldn't confidently identify the breed. Here are the top 3 possible breeds:\n\n"
557
  f"1. **{topk_breeds[0]}** ({topk_probs_percent[0]} confidence)\n"
 
559
  f"3. **{topk_breeds[2]}** ({topk_probs_percent[2]} confidence)\n\n"
560
  "Click on a button to view more information about the breed."
561
  )
562
+ return (explanation, image,
563
+ gr.update(visible=True, value=f"More about {topk_breeds[0]}"),
564
+ gr.update(visible=True, value=f"More about {topk_breeds[1]}"),
565
+ gr.update(visible=True, value=f"More about {topk_breeds[2]}"),
566
+ gr.update(visible=True)) # 顯示 back 按鈕
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
 
568
  def show_details(choice, previous_output):
569
  if not choice:
570
  return previous_output, gr.update(visible=True)
571
 
572
  try:
573
+ breed = choice.split("More about ")[-1]
574
  description = get_dog_description(breed)
575
  return format_description(description, breed), gr.update(visible=True)
576
  except Exception as e: