import argparse import json import math from pathlib import Path import requests from ultralytics import YOLO # 방법 A) 가장 최신 트렌드인 NMS-Free 임베디드 특화 모델 로드 model = YOLO("./weights/yolo26m.pt") # 방법 B) 복잡한 구도나 정밀 식별에 강한 어텐션 기반 모델 로드 # model = YOLO("./weights/yolo12m.pt") def xyxy_to_xywh(box: dict) -> dict: x1 = math.floor(box["x1"]) y1 = math.floor(box["y1"]) x2 = math.ceil(box["x2"]) y2 = math.ceil(box["y2"]) return {"x": x1, "y": y1, "w": x2 - x1, "h": y2 - y1} def run(image_path: str) -> dict: """이미지 경로를 받아 추론하고 결과 dict를 반환한다.""" results = model(image_path) result = results[0] image_path_obj = Path(result.path) marked_path = image_path_obj.with_name( f"{image_path_obj.stem}_marked{image_path_obj.suffix}" ) result.save(filename=str(marked_path)) detections = [] for det in result.summary(): detections.append({**det, "box": xyxy_to_xywh(det["box"])}) output = { "path": result.path, "marked_path": str(marked_path), "shape": {"height": result.orig_shape[0], "width": result.orig_shape[1]}, "speed_ms": result.speed, "detections": detections, "image_url": str(image_path_obj), } return output def download_image(image_url: str, save_path: str = "image.jpg") -> str: """원격 이미지 URL을 로컬 파일로 저장하고 경로를 반환한다.""" # 이미지 URL 체크 if not image_url.startswith("http"): raise ValueError("Invalid image URL") response = requests.get(image_url) response.raise_for_status() with open(save_path, "wb") as f: f.write(response.content) return save_path def main(image_url: str) -> dict: image_path = download_image(image_url) return run(image_path) if __name__ == "__main__": # 추론 결과를 출력하기 위한 테스트 코드 # uv run start.py --image_url "https://acai.ketidev.kr:20443/detect/image/202606/20260619_145116_image.jpg" parser = argparse.ArgumentParser() parser.add_argument("--image_url", type=str, required=True) args = parser.parse_args() output = main(args.image_url) print(json.dumps(output, indent=2, ensure_ascii=False))