import os import json from pathlib import Path from ultralytics import YOLO import cv2 import numpy as np def get_color_by_class_id(class_id: int): """根据 class_id 生成稳定颜色(BGR)""" np.random.seed(class_id) color = np.random.randint(0, 255, size=3).tolist() return tuple(color) def mask_to_polygons(mask: np.ndarray): """将二值 mask 转换为 COCO 风格多边形列表""" contours, _ = cv2.findContours( mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) polygons = [] for contour in contours: if contour.shape[0] < 3: continue polygon = contour.flatten().tolist() polygons.append(polygon) return polygons IMAGE_DIR = "C:/Users/meta/Desktop/Datamate/yolo/Photos" OUT_IMG_DIR = "outputs_seg/images" OUT_JSON_DIR = "outputs_seg/annotations" MODEL_MAP = { "n": "yolov8n-seg.pt", "s": "yolov8s-seg.pt", "m": "yolov8m-seg.pt", "l": "yolov8l-seg.pt", "x": "yolov8x-seg.pt", } MODEL_KEY = "x" MODEL_PATH = MODEL_MAP[MODEL_KEY] CONF_THRES = 0.7 DRAW_BBOX = True COCO_CLASS_MAP = { 0: "person", 1: "bicycle", 2: "car", 3: "motorcycle", 4: "airplane", 5: "bus", 6: "train", 7: "truck", 8: "boat", 9: "traffic light", 10: "fire hydrant", 11: "stop sign", 12: "parking meter", 13: "bench", 14: "bird", 15: "cat", 16: "dog", 17: "horse", 18: "sheep", 19: "cow", 20: "elephant", 21: "bear", 22: "zebra", 23: "giraffe", 24: "backpack", 25: "umbrella", 26: "handbag", 27: "tie", 28: "suitcase", 29: "frisbee", 30: "skis", 31: "snowboard", 32: "sports ball", 33: "kite", 34: "baseball bat", 35: "baseball glove", 36: "skateboard", 37: "surfboard", 38: "tennis racket", 39: "bottle", 40: "wine glass", 41: "cup", 42: "fork", 43: "knife", 44: "spoon", 45: "bowl", 46: "banana", 47: "apple", 48: "sandwich", 49: "orange", 50: "broccoli", 51: "carrot", 52: "hot dog", 53: "pizza", 54: "donut", 55: "cake", 56: "chair", 57: "couch", 58: "potted plant", 59: "bed", 60: "dining table", 61: "toilet", 62: "tv", 63: "laptop", 64: "mouse", 65: "remote", 66: "keyboard", 67: "cell phone", 68: "microwave", 69: "oven", 70: "toaster", 71: "sink", 72: "refrigerator", 73: "book", 74: "clock", 75: "vase", 76: "scissors", 77: "teddy bear", 78: "hair drier", 79: "toothbrush" } TARGET_CLASS_IDS = [0, 2, 5] os.makedirs(OUT_IMG_DIR, exist_ok=True) os.makedirs(OUT_JSON_DIR, exist_ok=True) if TARGET_CLASS_IDS is not None: for cid in TARGET_CLASS_IDS: if cid not in COCO_CLASS_MAP: raise ValueError(f"Invalid class id: {cid}") model = YOLO(MODEL_PATH) image_paths = list(Path(IMAGE_DIR).glob("*.*")) for img_path in image_paths: img = cv2.imread(str(img_path)) if img is None: print(f"[WARN] Failed to read {img_path}") continue results = model(img, conf=CONF_THRES) r = results[0] h, w = img.shape[:2] annotations = { "image": img_path.name, "width": w, "height": h, "model_key": MODEL_KEY, "conf_threshold": CONF_THRES, "supported_classes": COCO_CLASS_MAP, "selected_class_ids": TARGET_CLASS_IDS, "instances": [] } if r.boxes is not None and r.masks is not None: for i, box in enumerate(r.boxes): cls_id = int(box.cls[0]) if TARGET_CLASS_IDS is not None and cls_id not in TARGET_CLASS_IDS: continue conf = float(box.conf[0]) x1, y1, x2, y2 = map(float, box.xyxy[0]) label = COCO_CLASS_MAP[cls_id] mask = r.masks.data[i].cpu().numpy() mask = (mask > 0.5).astype(np.uint8) mask = cv2.resize(mask, (w, h), interpolation=cv2.INTER_NEAREST) color = get_color_by_class_id(cls_id) img[mask == 1] = ( img[mask == 1] * 0.5 + np.array(color) * 0.5 ).astype(np.uint8) if True: cv2.rectangle( img, (int(x1), int(y1)), (int(x2), int(y2)), color, 2 ) cv2.putText( img, f"{label} {conf:.2f}", (int(x1), max(int(y1) - 5, 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1 ) polygons = mask_to_polygons(mask) annotations["instances"].append({ "label": label, "class_id": cls_id, "confidence": round(conf, 4), "bbox_xyxy": [x1, y1, x2, y2], "segmentation": polygons }) out_img_path = os.path.join(OUT_IMG_DIR, img_path.name) out_json_path = os.path.join(OUT_JSON_DIR, img_path.stem + ".json") cv2.imwrite(out_img_path, img) with open(out_json_path, "w", encoding="utf-8") as f: json.dump(annotations, f, indent=2, ensure_ascii=False) print(f"[OK] {img_path.name}") print("Segmentation batch finished.")