LabelMe标注的JSON文件转换实战从标注到YOLO/MMDetection训练全流程解析当你完成LabelMe标注工作看着满文件夹的.json文件可能会陷入迷茫——这些文件如何变成YOLO或MMDetection能识别的训练数据本文将带你深入理解LabelMe JSON结构并手把手完成格式转换全流程。1. LabelMe JSON文件结构深度解析LabelMe生成的JSON文件实际上是一个包含完整标注信息的结构化数据。打开任意一个.json文件你会看到类似这样的结构{ version: 5.3.1, flags: {}, shapes: [ { label: orange, points: [[100, 150], [200, 250], ...], group_id: null, shape_type: polygon, flags: {} } ], imagePath: orange_001.jpg, imageData: null, imageHeight: 800, imageWidth: 600 }关键字段解析shapes包含所有标注对象的数组label标注类别名称points标注点坐标多边形时为顶点矩形时为对角两点shape_type标注类型polygon/rectangle等imagePath原始图片路径imageHeight/Width图片尺寸注意LabelMe默认使用绝对坐标系统而YOLO需要归一化后的相对坐标这是转换时需要特别注意的点。2. 转换前的准备工作在开始转换前建议按以下步骤整理你的数据集目录结构调整dataset/ ├── images/ # 存放所有原始图片 │ ├── train/ │ └── val/ ├── annotations/ # 存放LabelMe生成的.json文件 │ ├── train/ │ └── val/ └── labels/ # 转换后的标签文件将放在这里 ├── train/ └── val/类别映射文件 创建一个classes.txt文件列出所有类别每行一个类别名。例如orange apple banana安装必要工具pip install labelme numpy opencv-python tqdm3. 转换为YOLO格式实战YOLO格式要求每个图片对应一个.txt文件内容格式为class_id x_center y_center width height其中坐标值都是相对于图片宽高的归一化值0-1之间。以下是完整的转换脚本import json import os import numpy as np from pathlib import Path def convert_labelme_to_yolo(json_dir, output_dir, classes): json_files list(Path(json_dir).glob(*.json)) for json_file in json_files: with open(json_file, r) as f: data json.load(f) img_width data[imageWidth] img_height data[imageHeight] txt_path Path(output_dir) / (json_file.stem .txt) with open(txt_path, w) as f: for shape in data[shapes]: label shape[label] class_id classes.index(label) points np.array(shape[points]) if shape[shape_type] rectangle: x_min, y_min points[0] x_max, y_max points[1] elif shape[shape_type] polygon: x_min, y_min np.min(points, axis0) x_max, y_max np.max(points, axis0) # 计算归一化中心坐标和宽高 x_center ((x_min x_max) / 2) / img_width y_center ((y_min y_max) / 2) / img_height width (x_max - x_min) / img_width height (y_max - y_min) / img_height f.write(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n) # 使用示例 classes [orange, apple, banana] # 应与classes.txt一致 convert_labelme_to_yolo(dataset/annotations/train, dataset/labels/train, classes)常见问题处理坐标越界确保转换后的值在[0,1]范围内必要时进行clip操作类别映射错误检查classes.txt与标注文件中的类别名称是否完全一致图片路径问题如果图片找不到检查json文件中的imagePath是否正确4. 转换为COCO格式MMDetection适用MMDetection通常使用COCO格式其结构更为复杂包含以下主要部分images图片信息列表annotations标注信息列表categories类别信息列表完整转换脚本import json import os from datetime import datetime from pathlib import Path def create_coco_structure(): return { info: { description: My Dataset, url: , version: 1.0, year: datetime.now().year, contributor: , date_created: datetime.now().strftime(%Y/%m/%d) }, licenses: [{id: 1, name: Unknown, url: }], images: [], annotations: [], categories: [] } def convert_labelme_to_coco(json_dir, output_path, classes): coco create_coco_structure() # 添加类别 for i, class_name in enumerate(classes): coco[categories].append({ id: i 1, name: class_name, supercategory: object }) annotation_id 1 json_files list(Path(json_dir).glob(*.json)) for image_id, json_file in enumerate(json_files, 1): with open(json_file, r) as f: data json.load(f) # 添加图片信息 image_info { id: image_id, file_name: Path(data[imagePath]).name, width: data[imageWidth], height: data[imageHeight], license: 1, date_captured: } coco[images].append(image_info) # 添加标注信息 for shape in data[shapes]: label shape[label] category_id classes.index(label) 1 points shape[points] if shape[shape_type] rectangle: x_min min(points[0][0], points[1][0]) y_min min(points[0][1], points[1][1]) x_max max(points[0][0], points[1][0]) y_max max(points[0][1], points[1][1]) width x_max - x_min height y_max - y_min area width * height segmentation [ x_min, y_min, x_max, y_min, x_max, y_max, x_min, y_max ] elif shape[shape_type] polygon: segmentation [coord for point in points for coord in point] x_coords points[:, 0] y_coords points[:, 1] x_min, y_min min(x_coords), min(y_coords) x_max, y_max max(x_coords), max(y_coords) width x_max - x_min height y_max - y_min area width * height annotation { id: annotation_id, image_id: image_id, category_id: category_id, segmentation: [segmentation], area: area, bbox: [x_min, y_min, width, height], iscrowd: 0 } coco[annotations].append(annotation) annotation_id 1 with open(output_path, w) as f: json.dump(coco, f, indent2) # 使用示例 classes [orange, apple, banana] convert_labelme_to_coco(dataset/annotations/train, dataset/annotations/train.json, classes)5. 数据验证与常见问题解决转换完成后强烈建议进行数据验证可视化检查import cv2 import random def visualize_yolo_label(image_path, label_path, classes): image cv2.imread(image_path) img_h, img_w image.shape[:2] with open(label_path, r) as f: lines f.readlines() for line in lines: class_id, x_center, y_center, width, height map(float, line.split()) x_center * img_w y_center * img_h width * img_w height * img_h x_min int(x_center - width/2) y_min int(y_center - height/2) x_max int(x_center width/2) y_max int(y_center height/2) color (random.randint(0,255), random.randint(0,255), random.randint(0,255)) cv2.rectangle(image, (x_min, y_min), (x_max, y_max), color, 2) cv2.putText(image, classes[int(class_id)], (x_min, y_min-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2) cv2.imshow(Preview, image) cv2.waitKey(0) cv2.destroyAllWindows()常见问题解决方案问题现象可能原因解决方案训练时报类别错误类别ID不连续或超出范围检查classes.txt是否包含所有类别且无重复标注框位置异常坐标归一化错误验证转换脚本中的坐标计算逻辑大量标注丢失JSON文件解析错误检查JSON文件是否完整特别是shapes数组图片找不到路径问题确保imagePath相对路径正确或使用绝对路径批量验证脚本# 检查所有标注文件是否有效 find dataset/labels/ -name *.txt -exec grep -q [0-9] {} \; -print | wc -l # 检查图片与标注文件是否匹配 ls dataset/images/train/ | wc -l ls dataset/labels/train/ | wc -l6. 与训练框架集成对于YOLOv5/v8创建数据集配置文件data.yamlpath: ../dataset train: images/train val: images/val names: 0: orange 1: apple 2: banana启动训练python train.py --img 640 --batch 16 --epochs 100 --data data.yaml --weights yolov5s.pt对于MMDetection修改配置文件如configs/_base_/datasets/coco_detection.pydata dict( traindict( ann_filedata/dataset/annotations/train.json, img_prefixdata/dataset/images/train/), valdict( ann_filedata/dataset/annotations/val.json, img_prefixdata/dataset/images/val/), testdict( ann_filedata/dataset/annotations/val.json, img_prefixdata/dataset/images/val/))启动训练python tools/train.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py在实际项目中我发现将LabelMe标注转换为YOLO格式时最容易出错的是坐标归一化步骤。特别是在处理不规则多边形时需要特别注意边界条件的处理。而转换为COCO格式时segmentation字段的生成逻辑需要与后续任务需求保持一致。