Labelme生成的JSON文件别乱扔!手把手教你用Python脚本批量转成YOLO格式 Labelme标注数据工程化Python脚本实现YOLO格式批量转换实战在计算机视觉项目的实际开发流程中数据标注往往只完成了整个工作流的20%而剩下的80%精力都消耗在数据清洗、格式转换和验证环节。当你用Labelme精心标注了数百张图像后那些生成的JSON文件就像未经雕琢的玉石——价值连城但需要专业加工才能发挥真正作用。1. 理解Labelme与YOLO的数据格式差异Labelme生成的JSON文件采用绝对坐标记录多边形顶点而YOLO需要的却是归一化后的中心点坐标和宽高比例。这种本质差异导致直接使用原始标注会面临三个核心挑战坐标系转换从图像像素坐标系到YOLO的归一化坐标系0-1范围形状描述转换从多边形顶点序列到边界框的数学表达标签映射从文本标签到YOLO要求的类别索引典型的Labelme JSON结构关键字段如下{ version: 5.1.1, flags: {}, shapes: [ { label: cat, points: [[302,240],[402,240],[402,340],[302,340]], shape_type: polygon } ], imagePath: example.jpg, imageWidth: 800, imageHeight: 600 }对应的YOLO格式要求每张图片一个txt文件每行表示一个对象class_id x_center y_center width height2. 构建Python转换脚本的核心逻辑2.1 基础转换函数实现创建一个labelme2yolo.py文件首先实现核心几何计算函数import json import os import numpy as np def polygon_to_yolo(polygon_points, img_width, img_height): 将多边形顶点转换为YOLO格式的边界框 points np.array(polygon_points) 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 return x_center, y_center, width, height2.2 批量处理与文件输出添加目录遍历和文件输出逻辑def process_labelme_json(json_path, class_mapping, output_dir): with open(json_path, r) as f: data json.load(f) txt_lines [] for shape in data[shapes]: if shape[shape_type] ! polygon: continue class_name shape[label].lower() if class_name not in class_mapping: continue # 转换坐标 x_center, y_center, width, height polygon_to_yolo( shape[points], data[imageWidth], data[imageHeight] ) txt_lines.append(f{class_mapping[class_name]} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) # 写入YOLO格式文件 base_name os.path.splitext(os.path.basename(json_path))[0] txt_path os.path.join(output_dir, f{base_name}.txt) with open(txt_path, w) as f: f.write(\n.join(txt_lines))3. 工程化实践中的关键问题处理3.1 复杂多边形的优化策略当遇到复杂多边形时直接取最小外接矩形可能导致标注质量下降。我们可以在转换前对多边形进行凸包处理from scipy.spatial import ConvexHull def optimize_polygon(points): 对复杂多边形进行凸包优化 hull ConvexHull(points) return [points[i] for i in hull.vertices]3.2 多线程批量处理对于大型数据集添加多线程支持可以显著提升处理速度from concurrent.futures import ThreadPoolExecutor def batch_convert(input_dir, output_dir, class_mapping, workers4): os.makedirs(output_dir, exist_okTrue) json_files [f for f in os.listdir(input_dir) if f.endswith(.json)] with ThreadPoolExecutor(max_workersworkers) as executor: for json_file in json_files: executor.submit( process_labelme_json, os.path.join(input_dir, json_file), class_mapping, output_dir )4. 数据验证与质量检查转换完成后必须验证结果准确性这里提供一个可视化检查脚本import cv2 def visualize_yolo_annotation(image_path, txt_path, class_names): image cv2.imread(image_path) height, width image.shape[:2] with open(txt_path, r) as f: for line in f: class_id, xc, yc, w, h map(float, line.strip().split()) # 转换回像素坐标 x int((xc - w/2) * width) y int((yc - h/2) * height) box_w int(w * width) box_h int(h * height) # 绘制边界框 cv2.rectangle(image, (x,y), (xbox_w,ybox_h), (0,255,0), 2) cv2.putText(image, class_names[int(class_id)], (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0,255,0), 2) cv2.imshow(Validation, image) cv2.waitKey(0) cv2.destroyAllWindows()5. 完整项目结构与管理建议采用以下目录结构组织转换项目labelme2yolo/ ├── src/ │ ├── converter.py # 主转换脚本 │ ├── validator.py # 验证脚本 │ └── utils.py # 工具函数 ├── configs/ │ └── classes.yaml # 类别映射配置 ├── input_data/ # 原始Labelme数据 │ ├── images/ # 原图目录 │ └── annotations/ # JSON标注目录 └── output_data/ # 转换输出 ├── images/ # 图片可符号链接 └── labels/ # YOLO格式标签示例classes.yaml配置文件class_mapping: cat: 0 dog: 1 person: 26. 高级技巧与性能优化6.1 内存映射加速大文件处理对于超大JSON文件100MB可以使用ijson库进行流式处理import ijson def process_large_json(json_path): with open(json_path, rb) as f: objects ijson.items(f, shapes.item) for shape in objects: # 处理每个shape对象 pass6.2 增量处理与断点续传添加检查点机制避免重复处理def batch_convert_with_checkpoint(input_dir, output_dir, checkpoint_file): processed set() if os.path.exists(checkpoint_file): with open(checkpoint_file, r) as f: processed.update(f.read().splitlines()) with open(checkpoint_file, a) as checkpoint: for json_file in os.listdir(input_dir): if json_file in processed: continue # 处理文件... checkpoint.write(f{json_file}\n)6.3 并行GPU加速计算对于超大规模数据集可以使用CUDA加速几何计算import cupy as cp def gpu_polygon_to_yolo(polygon_points, img_width, img_height): points cp.array(polygon_points) x_min, y_min cp.min(points, axis0) x_max, y_max cp.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 return x_center.get(), y_center.get(), width.get(), height.get()