DawnC commited on
Commit
4290652
1 Parent(s): 5702af8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -19
app.py CHANGED
@@ -250,8 +250,9 @@ def get_akc_breeds_link():
250
  # iface.launch()
251
 
252
 
 
 
253
  def format_description(description, breed):
254
- # 分別將不同的屬性分開來顯示,保持結果的可讀性
255
  if isinstance(description, dict):
256
  formatted_description = "\n".join([f"**{key}**: {value}" for key, value in description.items()])
257
  else:
@@ -259,12 +260,9 @@ def format_description(description, breed):
259
 
260
  formatted_description = f"""
261
  **Breed**: {breed}
262
-
263
  {formatted_description}
264
-
265
  **Want to learn more about dog breeds?**
266
  [Visit the AKC dog breeds page]({get_akc_breeds_link()}) and search for {breed} to find detailed information.
267
-
268
  *Disclaimer: The external link provided leads to the American Kennel Club (AKC) dog breeds page.
269
  You may need to search for the specific breed on that page.
270
  I am not responsible for the content on external sites.
@@ -274,9 +272,9 @@ Please refer to the AKC's terms of use and privacy policy.*
274
 
275
 
276
  async def predict_single_dog(image):
277
- # 單一品種直接預測,避免 YOLO
278
  return await asyncio.to_thread(_predict_single_dog, image)
279
 
 
280
  def _predict_single_dog(image):
281
  image_tensor = preprocess_image(image)
282
  with torch.no_grad():
@@ -289,22 +287,26 @@ def _predict_single_dog(image):
289
  topk_probs_percent = [f"{prob.item() * 100:.2f}%" for prob in topk_probs[0]]
290
  return top1_prob, topk_breeds, topk_probs_percent
291
 
 
292
  async def detect_multiple_dogs(image):
293
- # 檢測多隻狗時使用 YOLO
294
  return await asyncio.to_thread(_detect_multiple_dogs, image)
295
 
296
- def _detect_multiple_dogs(image):
297
- results = model_yolo(image)
 
 
298
  dogs = []
299
  for result in results:
300
  for box in result.boxes:
301
  if box.cls == 16: # COCO 資料集中狗的類別是 16
302
  xyxy = box.xyxy[0].tolist()
303
  confidence = box.conf.item()
304
- cropped_image = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
305
- dogs.append((cropped_image, confidence, xyxy))
 
306
  return dogs
307
 
 
308
  async def predict(image):
309
  if image is None:
310
  return "Please upload an image to start.", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
@@ -313,11 +315,9 @@ async def predict(image):
313
  if isinstance(image, np.ndarray):
314
  image = Image.fromarray(image)
315
 
316
- # 首先檢查圖片中是否有多隻狗
317
  dogs = await detect_multiple_dogs(image)
318
 
319
  if len(dogs) == 0:
320
- # 單狗直接分類
321
  top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(image)
322
  if top1_prob < 0.2:
323
  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)
@@ -326,19 +326,28 @@ async def predict(image):
326
  formatted_description = format_description(description, breed)
327
  return formatted_description, image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
328
 
 
 
 
 
 
 
 
 
 
329
  explanations = []
330
  visible_buttons = []
331
  annotated_image = image.copy()
332
  draw = ImageDraw.Draw(annotated_image)
 
333
 
334
- # 多狗情況
335
  for i, (cropped_image, _, box) in enumerate(dogs):
336
  top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(cropped_image)
337
 
338
- # 更改框的顏色以增加辨識度
339
- color = ["red", "blue", "green", "yellow"][i % 4]
340
  draw.rectangle(box, outline=color, width=3)
341
- draw.text((box[0], box[1]), f"Dog {i+1}", fill=color)
342
 
343
  if top1_prob >= 0.5:
344
  breed = topk_breeds[0]
@@ -352,21 +361,21 @@ Dog {i+1}: Detected with moderate confidence. Here are the top 3 possible breeds
352
  3. **{topk_breeds[2]}** ({topk_probs_percent[2]})
353
  """
354
  explanations.append(explanation)
355
- # 將 Top3 選項顯示在該狗的下方
356
  visible_buttons.extend([f"More about Dog {i+1}: {topk_breeds[0]}", f"More about Dog {i+1}: {topk_breeds[1]}", f"More about Dog {i+1}: {topk_breeds[2]}"])
357
  else:
358
  explanations.append(f"Dog {i+1}: The image is unclear or the breed is not in the dataset.")
359
 
360
  final_explanation = "\n\n".join(explanations)
361
- return final_explanation, annotated_image, gr.update(visible=len(visible_buttons) >= 1, value=visible_buttons[0] if visible_buttons else ""), gr.update(visible=len(visible_buttons) >= 2, value=visible_buttons[1] if len(visible_buttons) >= 2 else ""), gr.update(visible=len(visible_buttons) >= 3, value=visible_buttons[2] if len(visible_buttons) >= 3 else "")
362
 
363
  except Exception as e:
364
  return f"An error occurred: {e}", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
365
 
 
366
  async def show_details(choice):
367
  if not choice:
368
  return "Please select a breed to view details."
369
-
370
  try:
371
  if "Dog" in choice:
372
  _, breed = choice.split(": ", 1)
@@ -378,6 +387,7 @@ async def show_details(choice):
378
  return f"An error occurred while showing details: {e}"
379
 
380
 
 
381
  with gr.Blocks(css="""
382
  .container { max-width: 900px; margin: auto; padding: 20px; }
383
  .gr-box { border-radius: 15px; }
 
250
  # iface.launch()
251
 
252
 
253
+
254
+ # Update the format_description to handle descriptions more cleanly
255
  def format_description(description, breed):
 
256
  if isinstance(description, dict):
257
  formatted_description = "\n".join([f"**{key}**: {value}" for key, value in description.items()])
258
  else:
 
260
 
261
  formatted_description = f"""
262
  **Breed**: {breed}
 
263
  {formatted_description}
 
264
  **Want to learn more about dog breeds?**
265
  [Visit the AKC dog breeds page]({get_akc_breeds_link()}) and search for {breed} to find detailed information.
 
266
  *Disclaimer: The external link provided leads to the American Kennel Club (AKC) dog breeds page.
267
  You may need to search for the specific breed on that page.
268
  I am not responsible for the content on external sites.
 
272
 
273
 
274
  async def predict_single_dog(image):
 
275
  return await asyncio.to_thread(_predict_single_dog, image)
276
 
277
+
278
  def _predict_single_dog(image):
279
  image_tensor = preprocess_image(image)
280
  with torch.no_grad():
 
287
  topk_probs_percent = [f"{prob.item() * 100:.2f}%" for prob in topk_probs[0]]
288
  return top1_prob, topk_breeds, topk_probs_percent
289
 
290
+
291
  async def detect_multiple_dogs(image):
 
292
  return await asyncio.to_thread(_detect_multiple_dogs, image)
293
 
294
+
295
+ def _detect_multiple_dogs(image, conf_threshold=0.3):
296
+ # 調整 YOLO 模型的置信度閾值
297
+ results = model_yolo(image, conf=conf_threshold)
298
  dogs = []
299
  for result in results:
300
  for box in result.boxes:
301
  if box.cls == 16: # COCO 資料集中狗的類別是 16
302
  xyxy = box.xyxy[0].tolist()
303
  confidence = box.conf.item()
304
+ if confidence >= conf_threshold: # 只保留置信度高於閾值的框
305
+ cropped_image = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
306
+ dogs.append((cropped_image, confidence, xyxy))
307
  return dogs
308
 
309
+
310
  async def predict(image):
311
  if image is None:
312
  return "Please upload an image to start.", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
 
315
  if isinstance(image, np.ndarray):
316
  image = Image.fromarray(image)
317
 
 
318
  dogs = await detect_multiple_dogs(image)
319
 
320
  if len(dogs) == 0:
 
321
  top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(image)
322
  if top1_prob < 0.2:
323
  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)
 
326
  formatted_description = format_description(description, breed)
327
  return formatted_description, image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
328
 
329
+ if len(dogs) == 1:
330
+ top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(image)
331
+ breed = topk_breeds[0]
332
+ description = get_dog_description(breed)
333
+ formatted_description = format_description(description, breed)
334
+ return formatted_description, image, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
335
+
336
+ # Colors and fonts for multiple dogs
337
+ color_list = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF', '#800080', '#FFA500']
338
  explanations = []
339
  visible_buttons = []
340
  annotated_image = image.copy()
341
  draw = ImageDraw.Draw(annotated_image)
342
+ font = ImageFont.load_default()
343
 
344
+ # Process each dog detected by YOLO
345
  for i, (cropped_image, _, box) in enumerate(dogs):
346
  top1_prob, topk_breeds, topk_probs_percent = await predict_single_dog(cropped_image)
347
 
348
+ color = color_list[i % len(color_list)] # Cycle through colors
 
349
  draw.rectangle(box, outline=color, width=3)
350
+ draw.text((box[0], box[1]), f"Dog {i+1}", fill=color, font=font)
351
 
352
  if top1_prob >= 0.5:
353
  breed = topk_breeds[0]
 
361
  3. **{topk_breeds[2]}** ({topk_probs_percent[2]})
362
  """
363
  explanations.append(explanation)
 
364
  visible_buttons.extend([f"More about Dog {i+1}: {topk_breeds[0]}", f"More about Dog {i+1}: {topk_breeds[1]}", f"More about Dog {i+1}: {topk_breeds[2]}"])
365
  else:
366
  explanations.append(f"Dog {i+1}: The image is unclear or the breed is not in the dataset.")
367
 
368
  final_explanation = "\n\n".join(explanations)
369
+ return final_explanation, annotated_image, gr.update(visible=True, choices=visible_buttons), gr.update(visible=False), gr.update(visible=False)
370
 
371
  except Exception as e:
372
  return f"An error occurred: {e}", None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
373
 
374
+
375
  async def show_details(choice):
376
  if not choice:
377
  return "Please select a breed to view details."
378
+
379
  try:
380
  if "Dog" in choice:
381
  _, breed = choice.split(": ", 1)
 
387
  return f"An error occurred while showing details: {e}"
388
 
389
 
390
+
391
  with gr.Blocks(css="""
392
  .container { max-width: 900px; margin: auto; padding: 20px; }
393
  .gr-box { border-radius: 15px; }