| from functools import lru_cache |
| import os |
| from pathlib import Path |
| from urllib.request import urlretrieve |
|
|
| YOLO_CONFIG_DIR = Path("/tmp/Ultralytics") |
| os.environ.setdefault("YOLO_CONFIG_DIR", str(YOLO_CONFIG_DIR)) |
|
|
| import gradio as gr |
| import pandas as pd |
| from PIL import Image |
| from ultralytics import YOLO |
|
|
|
|
| MODEL_NAME = "yolo11n.pt" |
| MODEL_PATH = Path(MODEL_NAME) |
| MODEL_URL = ( |
| "https://github.com/ultralytics/assets/releases/download/v8.3.0/yolo11n.pt" |
| ) |
|
|
|
|
| def download_model_if_needed(): |
| """モデルファイルがない場合は、初回だけダウンロードします。""" |
| if MODEL_PATH.exists(): |
| return |
|
|
| print(f"{MODEL_NAME} が見つからないため、モデルをダウンロードします...") |
| urlretrieve(MODEL_URL, MODEL_PATH) |
| print("モデルのダウンロードが完了しました。") |
|
|
|
|
| @lru_cache(maxsize=1) |
| def load_model(): |
| """YOLOモデルを一度だけ読み込みます。""" |
| download_model_if_needed() |
| return YOLO(str(MODEL_PATH)) |
|
|
|
|
| def create_empty_table(): |
| """検出結果がない場合にも、表の列をわかりやすく表示します。""" |
| return pd.DataFrame( |
| columns=[ |
| "class_name", |
| "confidence", |
| "x_min", |
| "y_min", |
| "x_max", |
| "y_max", |
| ] |
| ) |
|
|
|
|
| def detect_objects(input_image, confidence_threshold, iou_threshold): |
| """アップロード画像に対してYOLO11で物体検出を実行します。""" |
| if input_image is None: |
| return ( |
| None, |
| create_empty_table(), |
| "画像が未入力です。左側のアップロード欄から画像を選択してください。", |
| ) |
|
|
| try: |
| |
| image = Image.fromarray(input_image).convert("RGB") |
|
|
| model = load_model() |
| results = model.predict( |
| source=image, |
| conf=confidence_threshold, |
| iou=iou_threshold, |
| verbose=False, |
| ) |
|
|
| result = results[0] |
|
|
| |
| annotated_image = result.plot() |
|
|
| detection_rows = [] |
| boxes = result.boxes |
|
|
| if boxes is not None and len(boxes) > 0: |
| for box in boxes: |
| class_id = int(box.cls[0].item()) |
| class_name = result.names[class_id] |
| confidence = float(box.conf[0].item()) |
| x_min, y_min, x_max, y_max = box.xyxy[0].tolist() |
|
|
| detection_rows.append( |
| { |
| "class_name": class_name, |
| "confidence": round(confidence, 4), |
| "x_min": round(x_min, 2), |
| "y_min": round(y_min, 2), |
| "x_max": round(x_max, 2), |
| "y_max": round(y_max, 2), |
| } |
| ) |
|
|
| detections_df = ( |
| pd.DataFrame(detection_rows) |
| if detection_rows |
| else create_empty_table() |
| ) |
|
|
| message = ( |
| f"{len(detection_rows)}件の物体を検出しました。" |
| if detection_rows |
| else "指定されたしきい値では物体を検出できませんでした。" |
| ) |
|
|
| return annotated_image, detections_df, message |
|
|
| except Exception as error: |
| |
| return ( |
| None, |
| create_empty_table(), |
| f"推論中にエラーが発生しました: {error}", |
| ) |
|
|
|
|
| with gr.Blocks(title="YOLO11 Object Detection Demo") as demo: |
| gr.Markdown( |
| """ |
| # YOLO11 物体検出デモ |
| |
| 画像をアップロードすると、事前学習済みのYOLO11モデルが物体を検出します。 |
| confidence threshold と IoU threshold を調整して、検出結果の変化を確認できます。 |
| """ |
| ) |
|
|
| with gr.Row(): |
| with gr.Column(): |
| input_image = gr.Image( |
| label="検出したい画像", |
| type="numpy", |
| ) |
| confidence_slider = gr.Slider( |
| minimum=0.05, |
| maximum=1.0, |
| value=0.25, |
| step=0.05, |
| label="Confidence threshold", |
| ) |
| iou_slider = gr.Slider( |
| minimum=0.1, |
| maximum=1.0, |
| value=0.45, |
| step=0.05, |
| label="IoU threshold", |
| ) |
| detect_button = gr.Button("物体検出を実行", variant="primary") |
|
|
| with gr.Column(): |
| output_image = gr.Image(label="検出結果画像") |
| status_message = gr.Textbox( |
| label="メッセージ", |
| value="画像をアップロードして、物体検出を実行してください。", |
| interactive=False, |
| ) |
|
|
| detections_table = gr.Dataframe( |
| headers=["class_name", "confidence", "x_min", "y_min", "x_max", "y_max"], |
| label="検出結果テーブル", |
| interactive=False, |
| ) |
|
|
| detect_button.click( |
| fn=detect_objects, |
| inputs=[input_image, confidence_slider, iou_slider], |
| outputs=[output_image, detections_table, status_message], |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| demo.launch(server_name="0.0.0.0", server_port=7860) |
|
|