COCO 格式数据集制作实战:从 LabelMe JSON 到 MMDetection 可用的 3 步转换
COCO 格式数据集制作实战从 LabelMe JSON 到 MMDetection 可用的 3 步转换当我们需要使用 MMDetection、YOLO 等主流目标检测框架进行模型训练时COCO 格式数据集是最常见的选择之一。本文将详细介绍如何将 LabelMe 标注工具生成的 JSON 格式标注文件转换为标准的 COCO 格式数据集并确保其完全兼容 MMDetection 框架。1. 理解 COCO 数据集格式COCOCommon Objects in Context数据集格式是目前计算机视觉领域最流行的标注格式之一。它采用 JSON 文件存储所有标注信息具有以下核心结构{ info: {...}, licenses: [...], images: [ { id: int, width: int, height: int, file_name: str, license: int, flickr_url: str, coco_url: str, date_captured: datetime } ], annotations: [ { id: int, image_id: int, category_id: int, segmentation: RLE or [polygon], area: float, bbox: [x,y,width,height], iscrowd: 0 or 1 } ], categories: [ { id: int, name: str, supercategory: str } ] }关键字段说明images记录所有图像的基本信息annotations存储所有标注框的详细信息categories定义数据集的类别体系提示对于自定义数据集info 和 licenses 字段可以省略但 images、annotations 和 categories 三个部分是必须的。2. 从 LabelMe 到 COCO 的转换流程2.1 准备工作目录结构与数据整理首先需要建立符合 COCO 标准的目录结构COCO_ROOT/ ├── annotations/ # 存放标注文件 │ ├── instances_train2017.json │ └── instances_val2017.json ├── train2017/ # 训练集图片 └── val2017/ # 验证集图片建议的数据处理流程将所有原始图片放入images/文件夹将所有 LabelMe 生成的 JSON 标注文件放入labels/文件夹确保图片和标注文件一一对应同名不同扩展名2.2 核心转换代码实现以下是一个完整的 Python 转换脚本可将 LabelMe 标注转换为 COCO 格式import json import os import cv2 from glob import glob from tqdm import tqdm class Labelme2Coco: def __init__(self, labelme_json_dir, output_json_path): self.labelme_json_dir labelme_json_dir self.output_json_path output_json_path self.images [] self.annotations [] self.categories [] self.ann_id 1 # 定义你的类别列表 self.classes [cat, dog, person] # 替换为你的实际类别 def convert(self): # 创建类别信息 for i, cls in enumerate(self.classes, 1): self.categories.append({ id: i, name: cls, supercategory: object }) # 处理所有LabelMe JSON文件 json_files glob(os.path.join(self.labelme_json_dir, *.json)) for img_id, json_file in enumerate(tqdm(json_files), 1): with open(json_file, r) as f: data json.load(f) # 添加图片信息 img_path os.path.join(os.path.dirname(json_file), data[imagePath]) img cv2.imread(img_path) height, width img.shape[:2] self.images.append({ id: img_id, file_name: data[imagePath], width: width, height: height }) # 处理每个标注 for shape in data[shapes]: label shape[label] points shape[points] # 计算边界框[x,y,width,height] x_min min(p[0] for p in points) x_max max(p[0] for p in points) y_min min(p[1] for p in points) y_max max(p[1] for p in points) width x_max - x_min height y_max - y_min # 添加标注信息 self.annotations.append({ id: self.ann_id, image_id: img_id, category_id: self.classes.index(label) 1, bbox: [x_min, y_min, width, height], area: width * height, iscrowd: 0, segmentation: [[]] # 空分割标注 }) self.ann_id 1 # 保存为COCO格式 coco_data { images: self.images, annotations: self.annotations, categories: self.categories } with open(self.output_json_path, w) as f: json.dump(coco_data, f, indent2) # 使用示例 converter Labelme2Coco( labelme_json_dirpath/to/labelme_jsons, output_json_pathannotations/instances_train2017.json ) converter.convert()2.3 数据集划分与验证通常我们需要将数据集划分为训练集和验证集推荐比例为 7:3 或 8:2。可以使用以下代码实现随机划分import random import shutil from sklearn.model_selection import train_test_split def split_dataset(image_dir, label_dir, output_dir, test_size0.3): # 获取所有图片文件名不带扩展名 image_files [f.split(.)[0] for f in os.listdir(image_dir) if f.endswith(.jpg)] # 随机划分 train_files, val_files train_test_split(image_files, test_sizetest_size, random_state42) # 创建输出目录 os.makedirs(os.path.join(output_dir, train2017), exist_okTrue) os.makedirs(os.path.join(output_dir, val2017), exist_okTrue) # 移动图片文件 for file in train_files: shutil.copy( os.path.join(image_dir, file .jpg), os.path.join(output_dir, train2017, file .jpg) ) for file in val_files: shutil.copy( os.path.join(image_dir, file .jpg), os.path.join(output_dir, val2017, file .jpg) ) return train_files, val_files3. 验证与 MMDetection 集成3.1 验证 COCO 格式正确性转换完成后可以使用 COCO API 验证格式是否正确from pycocotools.coco import COCO import matplotlib.pyplot as plt # 加载验证 coco COCO(annotations/instances_train2017.json) # 获取所有类别 cats coco.loadCats(coco.getCatIds()) print(COCO categories: \n, [cat[name] for cat in cats]) # 随机显示一张图片及其标注 img_ids coco.getImgIds() img_id random.choice(img_ids) img coco.loadImgs(img_id)[0] ann_ids coco.getAnnIds(imgIdsimg[id]) anns coco.loadAnns(ann_ids) # 可视化 I plt.imread(os.path.join(train2017, img[file_name])) plt.imshow(I) coco.showAnns(anns) plt.show()3.2 配置 MMDetection 数据集在 MMDetection 中使用转换后的数据集需要创建或修改配置文件# configs/my_config.py dataset_type CocoDataset data_root path/to/COCO_ROOT/ train_pipeline [ dict(typeLoadImageFromFile), dict(typeLoadAnnotations, with_bboxTrue), dict(typeResize, img_scale(1333, 800), keep_ratioTrue), dict(typeRandomFlip, flip_ratio0.5), dict(typeNormalize, mean[123.675, 116.28, 103.53], std[58.395, 57.12, 57.375]), dict(typePad, size_divisor32), dict(typeDefaultFormatBundle), dict(typeCollect, keys[img, gt_bboxes, gt_labels]) ] data dict( samples_per_gpu2, workers_per_gpu2, traindict( typedataset_type, ann_filedata_root annotations/instances_train2017.json, img_prefixdata_root train2017/, pipelinetrain_pipeline), valdict( typedataset_type, ann_filedata_root annotations/instances_val2017.json, img_prefixdata_root val2017/, pipelinetest_pipeline), testdict( typedataset_type, ann_filedata_root annotations/instances_val2017.json, img_prefixdata_root val2017/, pipelinetest_pipeline))3.3 常见问题排查在实际转换过程中可能会遇到以下问题坐标系统不一致LabelMe 使用多边形点坐标而 COCO 使用 [x,y,width,height]确保转换时正确计算边界框类别 ID 不连续COCO 要求 category_id 从 1 开始连续编号0 通常保留为背景类图像尺寸不匹配某些框架要求所有图像尺寸相同可以在数据加载时统一调整尺寸标注质量检查使用可视化工具检查转换后的标注是否正确特别注意边界框是否包含完整目标注意对于小目标检测任务建议检查 area 字段是否正确计算某些框架会基于此过滤过小的目标。通过以上三个关键步骤我们就能将 LabelMe 标注的数据集转换为 MMDetection 可直接使用的 COCO 格式。这种转换不仅适用于目标检测任务经过适当调整后也可用于实例分割等更复杂的视觉任务。