COCO 數據集 - Ultralytics YOLO 文檔
比如我只想從數據集中取手機的圖像,來用于我的訓練,懶得自己一張一張標注,方法如下
# -*- coding: utf-8 -*-
import json
import os
import shutil
from pathlib import Path
from tqdm import tqdm
import cv2
from collections import defaultdictDEBUG = True # 調試階段先開著# cap
kind = "val"
if kind == "val":ann_file = r"F:\coco_pictures\annotations_trainval2017\annotations\instances_val2017.json"img_dir = r"F:\coco_pictures\cocoval2017\val2017"out_dir = r"E:\picture\coco\cellphone_val2017"out_dir_result = r"E:\picture\coco\cellphone_val2017_box"out_dir_result_txt = r"E:\picture\coco\cellphone_val2017_box_txt"
elif kind == "train":# ===== 按需修改 =====ann_file = r"F:\coco_pictures\annotations_trainval2017\annotations\instances_train2017.json"img_dir = r"F:\coco_pictures\coco_train2017\train2017"out_dir = r"E:\picture\coco\cellphone_train2017" # 原圖復制到這里out_dir_result = r"E:\picture\coco\cellphone_train2017_box" # 畫框后的結果圖out_dir_result_txt = r"E:\picture\coco\cellphone_train2017_box_txt" # <- 修正為 train# ===================Path(out_dir).mkdir(parents=True, exist_ok=True)
Path(out_dir_result).mkdir(parents=True, exist_ok=True)
Path(out_dir_result_txt).mkdir(parents=True, exist_ok=True)# 1) 讀取標注文件
with open(ann_file, "r", encoding="utf-8") as f:coco = json.load(f)# 2) 找到 cell phone 類別 id
cellphone_id = None
for cat in coco["categories"]:if cat["name"].lower() == "cell phone":cellphone_id = int(cat["id"])break
if cellphone_id is None:raise RuntimeError("未在 categories 中找到 'cell phone'")print("cell phone category_id =", cellphone_id)# 3) 建立 image_id -> 元信息
id2img = {int(img["id"]): img for img in coco["images"]}# 4) 收集每張圖的所有手機標注
imgid_to_bboxes = defaultdict(list)
for ann in coco["annotations"]:if int(ann.get("category_id", -1)) == cellphone_id:imgid_to_bboxes[int(ann["image_id"])].append(ann["bbox"]) # COCO [x,y,w,h] (float)# 5) 遍歷含手機的圖像:復制原圖 + 畫框另存 + 寫坐標txt
cellphone_img_ids = list(imgid_to_bboxes.keys())
print(f"共 {len(cellphone_img_ids)} 張圖含有手機標注。")for img_id in tqdm(cellphone_img_ids):meta = id2img.get(img_id)if not meta:continuefile_name = meta["file_name"]src = os.path.join(img_dir, file_name)dst_img_copy = os.path.join(out_dir, file_name)dst_boxed = os.path.join(out_dir_result, file_name)dst_txt = os.path.join(out_dir_result_txt, Path(file_name).stem + ".txt")# 復制原圖if not os.path.exists(src):continueif not os.path.exists(dst_img_copy):Path(os.path.dirname(dst_img_copy)).mkdir(parents=True, exist_ok=True)shutil.copy(src, dst_img_copy)# 讀圖并繪制所有 bbox,同時收集裁邊后的框用于寫txtim = cv2.imread(src)if im is None:continueH, W = im.shape[:2]clipped_boxes_xyxy = [] # 用于寫 txt:x1 y1 x2 y2(int)for bbox in imgid_to_bboxes[img_id]:x, y, w, h = bbox # COCO: [x,y,w,h]# 裁剪到圖像邊界并轉為 intx1 = max(0, min(int(round(x)), W - 1))y1 = max(0, min(int(round(y)), H - 1))x2 = max(0, min(int(round(x + w)), W - 1))y2 = max(0, min(int(round(y + h)), H - 1))if x2 <= x1 or y2 <= y1:continueclipped_boxes_xyxy.append((x1, y1, x2, y2))# 畫矩形框 & 標簽cv2.rectangle(im, (x1, y1), (x2, y2), (0, 255, 0), thickness=2)label = "cell phone"(tw, th), baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)ty1 = max(0, y1 - th - 6)cv2.rectangle(im, (x1, ty1), (x1 + tw + 6, ty1 + th + 4), (0, 255, 0), thickness=-1)cv2.putText(im, label, (x1 + 3, ty1 + th + 1),cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), thickness=2, lineType=cv2.LINE_AA)# 保存帶框圖Path(os.path.dirname(dst_boxed)).mkdir(parents=True, exist_ok=True)cv2.imwrite(dst_boxed, im, [cv2.IMWRITE_JPEG_QUALITY, 95])# 保存坐標 txt:每行一個框:x1 y1 x2 y2# 若沒有有效框,寫空文件或跳過均可;這里選擇寫空文件便于對齊清單with open(dst_txt, "w", encoding="utf-8") as ftxt:for (x1, y1, x2, y2) in clipped_boxes_xyxy:ftxt.write(f"{x1} {y1} {x2} {y2}\n")print(f"完成!原圖復制到:{out_dir}")
print(f"完成!帶框結果圖輸出到:{out_dir_result}")
print(f"完成!坐標TXT輸出到:{out_dir_result_txt}(每行:x1 y1 x2 y2)")
如何降低誤報(提升精確率)的實操建議
-
門限分級
-
提高 cell phone 類的專屬
conf_thr
(類特異閾值);或對小目標額外提高閾值(面積/長寬<閾值時+Δ)。
-
-
后處理約束
-
最小/最大面積過濾(相對圖像面積),去除遠處噪點或過大異常框。
-
縱橫比過濾:手機通常縱橫比在一定范圍(含殼/角度會變化,可設寬松區間)。
-
類別共現/上下文:要求與手、人或桌面/鍵盤/屏幕等場景共現;否則降權或拒絕(用多任務檢測或語義分割、場景分類輔助)。
-
-
兩段式判別(Cascade)
-
檢測器先召回,再用一個輕量分類器或 Patch 質量判別器二篩(比如 MobileNet/RepVGG 小模型),對候選框裁剪后復判,顯著減少FP。
-
-
困難負樣本挖掘(Hard Negative Mining)
-
用本腳本導出的誤報圖集做“負樣本再訓練”:將誤報區域打負標簽或加“非手機”對比樣本,繼續微調。
-
-
數據增強針對性
-
加入反手機相似物(遙控器、移動電源、充電器、書本邊角、黑色矩形圖案、廣告牌等)的負樣本;
-
光照/模糊/噪聲/尺度/角度增強,降低模型將“黑色高對比矩形”錯當手機的概率。
-
-
NMS與多尺度
-
合理調
iou
(NMS)與conf
;對于密集小目標,試diou-nms
/soft-nms
; -
多尺度測試(或訓練)以穩住不同距離下的外觀差異。
-
-
模型層面
-
選擇更合適的輸入分辨率(手機通常小目標,略提分辨率會降FP/漏檢);
-
若部署在 OpenVINO/RKNN 等,注意量化誤差:用代表性數據做校準,并檢查感興趣類上的 mAP 變化。
-