LabelMe转YOLO分割数据集:一键转换脚本与避坑指南
发布时间:2026/10/10 21:04:16 锦皓数字建站

简介这份资源面向已使用 LabelMe 完成分割数据集标注、需要将标注结果迁移到 YOLO 训练流程的算法工程师与深度学习学习者核心解决 JSON 标注格式与 YOLO 文本标签格式不兼容的问题。压缩包共 6 个文件以 txt 说明文档、Python 脚本、md 使用说明和 license 许可文件为主整体约 9KB体积轻量、开箱即用。脚本支持通过 --json_dir 指定 LabelMe JSON 文件夹路径用 --val_size 按比例自动划分训练集与验证集默认 0.1也可用 --json_name 转换单个 JSON 文件并可通过 --seg 参数直接生成 YOLOv5 v7.0 实例分割数据集。运行后会在独立目录下输出 YOLO 格式的标签与数据集结构省去手工编写转换代码的重复劳动。目前已有 215 人学习适合希望快速打通 LabelMe 到 YOLO 分割训练链路、减少格式转换踩坑成本的读者参考使用。1. 从 LabelMe 到 YOLO一份能直接跑通的分割数据集转换工具如果你用 LabelMe 标过分割数据集大概率经历过这个场景几十上百张图每张对应一个 JSON里面是多边形点集但 YOLO 训练要的是归一化后的 txt 标签实例分割还要按class x1 y1 x2 y2 ...的格式逐行展开。手动转不现实。写脚本每次都要重新处理坐标归一化、类别映射、训练验证集划分这几件事写一次能用换个项目又得改。这份资源就是干这个的一个labelme2yolo.py脚本把 LabelMe 的 JSON 直接转成 YOLO 检测或 YOLOv5 v7.0 实例分割格式的数据集顺带按--val_size切好训练集和验证集。它适合已经用 LabelMe 完成标注、准备进 YOLO 训练流程的人尤其是做分割任务、不想在格式转换上反复造轮子的从业者。压缩包里除了主脚本还有requirements.txt、README.md、LICENSE和一份资源说明结构很干净没有多余依赖。2. 转换原理与目录结构先搞清楚脚本在做什么2.1 LabelMe JSON 里到底存了什么LabelMe 保存的 JSON 结构不复杂核心是shapes数组每个 shape 包含label、points、shape_type和可选的flags。对于分割标注shape_type通常是polygonpoints是一串[x, y]像素坐标。除此之外还有imagePath、imageWidth、imageHeight这些元信息转换时归一化坐标就靠宽高。YOLO 检测格式每行是class_id cx cy w h全部归一化到 0~1YOLO 分割格式每行是class_id x1 y1 x2 y2 ... xn yn同样是归一化坐标点按顺序排列。两者的关键差异在于检测需要从多边形算出外接矩形分割则直接保留多边形点集。脚本要做的就是读 JSON、提取 shapes、按类别映射成 id、归一化、写 txt。注意LabelMe 的points是像素坐标YOLO 要的是相对坐标除以imageWidth和imageHeight即可。如果图片被旋转过或者 EXIF 方向不对宽高可能和实际不符这是后面避坑章节要说的点。2.2 资源包里的文件各自负责什么解压后能看到这几个文件分工很明确文件作用labelme2yolo.py主转换脚本所有逻辑都在这里requirements.txtPython 依赖清单主要是labelme、numpy、tqdm等README.md用法说明和参数解释LICENSE开源协议商用前确认一下资源内容.txt资源包的补充说明没有多余的配置文件也没有硬编码路径所有输入都通过命令行参数传入。这种设计的好处是你可以把它丢进任何项目目录不用改代码。依赖方面requirements.txt里列的东西不多常见做法是直接pip install -r requirements.txt如果环境里已经有labelme和numpy基本不会冲突。2.3 类别映射与 id 分配逻辑脚本会扫描--json_dir下所有 JSON收集出现过的label然后按某种顺序分配class_id。常见做法是按字母序或者按首次出现顺序。这里有个关键点类别顺序决定了训练时模型输出的类别索引如果你后续要跟其他数据集合并或者用预训练权重类别顺序必须对齐否则模型学出来的东西全是错的。我一般会先跑一次转换看看生成的classes.txt或者控制台输出的类别列表确认顺序符合预期。如果不符合要么改 JSON 里的 label 命名要么在脚本里加一个手动映射表。脚本本身没有提供--class_map参数所以类别顺序完全由扫描结果决定这一点在多人协作标注时尤其要注意——不同人用的 label 拼写不一致会直接导致类别分裂。3. 动手转换从安装依赖到生成数据集3.1 环境准备与依赖安装先确认 Python 版本建议 3.8 以上。然后进到解压目录安装依赖cd labelme2yolo pip install -r requirements.txt如果requirements.txt里没有锁版本而你的环境里已经有较新的numpy或labelme可能会遇到兼容性问题。我一般会先建一个干净的虚拟环境conda create -n labelme2yolo python3.9 conda activate labelme2yolo pip install -r requirements.txt这样做的原因是labelme这个包本身依赖较多跟其他项目的环境混在一起容易出玄学问题。虚拟环境能隔离掉大部分版本冲突。安装完成后可以用python labelme2yolo.py --help看看参数是否正常输出确认脚本能跑起来。3.2 批量转换一条命令切分训练集与验证集把所有 LabelMe JSON 放在一个目录下比如/data/labelme_json/然后执行python labelme2yolo.py --json_dir /data/labelme_json/ --val_size 0.2这条命令做了几件事遍历--json_dir下所有.json文件解析每个文件的 shapes按类别分配 id归一化坐标然后按--val_size的比例把数据切分成训练集和验证集。--val_size 0.2表示 20% 作为验证集80% 作为训练集。默认值是 0.1也就是 10% 验证集。脚本会在--json_dir同级或内部生成labels和images目录结构具体布局取决于脚本实现。常见做法是生成train/和val/两个子目录每个下面各有images/和labels/。转换完成后你会得到一堆.txt文件每行对应一个标注对象。提示--val_size的切分是随机的但没有固定随机种子的话每次运行结果可能不同。如果你需要可复现的实验建议在脚本里加random.seed(42)或者转换后手动固定数据集划分。3.3 单文件转换与分割模式如果只想转一个 JSON 文件用--json_namepython labelme2yolo.py --json_dir /data/labelme_json/ --json_name image_001.json这个参数适合调试阶段比如你怀疑某张图的标注有问题可以单独转出来看看坐标对不对。注意--json_name通常需要配合--json_dir一起用脚本会在该目录下找这个文件。分割模式用--segpython labelme2yolo.py --json_dir /data/labelme_json/ --val_size 0.2 --seg加上--seg后脚本会输出 YOLOv5 v7.0 实例分割格式每行是class_id x1 y1 x2 y2 ...而不是检测格式的class_id cx cy w h。这个模式下多边形的点会全部保留点数取决于你标注时的精细程度。如果标注时点太少分割 mask 会很粗糙点太多txt 文件会很大训练时数据加载会变慢。我一般会在 LabelMe 里标注时控制点数在 20~50 个之间既能保证轮廓质量又不至于让标签文件膨胀。3.4 转换结果验证别急着开始训练转换完成后先别急着丢进 YOLO 训练。花几分钟做几个检查第一看labels目录下的 txt 文件数量是否和 JSON 数量一致。如果少了说明有些 JSON 解析失败可能是格式异常或者图片路径不对。第二随便打开一个 txt确认坐标都在 0~1 之间。如果出现大于 1 的值说明归一化用的宽高和实际图片不匹配。第三确认类别 id 从 0 开始连续。YOLO 要求类别 id 是 0 到num_classes - 1中间不能跳号。第四如果是分割模式确认每行的点数是偶数且至少 3 个点6 个数值。少于 3 个点构不成多边形YOLO 训练时会报错。# 快速检查脚本统计 txt 文件数量和坐标范围 import os import glob label_dir /data/labelme_json/labels txt_files glob.glob(os.path.join(label_dir, *.txt)) print(ftxt 文件数量: {len(txt_files)}) for f in txt_files[:5]: with open(f) as fh: for line in fh: parts line.strip().split() coords [float(x) for x in parts[1:]] if any(c 0 or c 1 for c in coords): print(f坐标越界: {f}) break这段脚本只做最基础的检查但能拦住大部分低级错误。坐标越界通常意味着imageWidth或imageHeight读错了或者图片被裁剪过但 JSON 没更新。4. 避坑与排查转换过程中最容易翻车的几个点4.1 现象转换后类别 id 混乱训练时 loss 不下降原因不同 JSON 里同一个类别的 label 拼写不一致比如person和Person脚本会当成两个类别导致类别数翻倍模型学不明白。解决转换前先统一 label 命名。可以写个脚本扫描所有 JSON统计 label 出现频率把拼写不一致的找出来手动修正。或者用jq批量替换# 统计所有 JSON 中的 label 分布 cat *.json | jq -r .shapes[].label | sort | uniq -c | sort -rn发现不一致后批量替换 JSON 里的 label 字段再重新转换。4.2 现象坐标归一化后超出 0~1 范围原因JSON 里的imageWidth和imageHeight与实际图片尺寸不符。常见于图片被旋转、裁剪或缩放后JSON 没有同步更新。解决转换前用 PIL 或 OpenCV 读一遍图片确认实际宽高和 JSON 里的值对比。如果不一致以实际图片为准修改 JSON 或直接在脚本里用实际宽高做归一化。from PIL import Image import json with open(image_001.json) as f: data json.load(f) img Image.open(data[imagePath]) print(fJSON 宽高: {data[imageWidth]}x{data[imageHeight]}) print(f实际宽高: {img.width}x{img.height})如果两者不一致建议在脚本里加一个校验步骤用实际图片尺寸覆盖 JSON 里的值。4.3 现象分割模式下某些多边形点数为奇数原因LabelMe 保存时可能因为浮点精度或手动编辑导致 points 数组长度异常或者 shape_type 不是 polygon 而是 rectangle、circle 等。解决转换前过滤掉非 polygon 的 shape或者把 rectangle 转成 polygon。脚本本身可能没有处理这些边界情况需要手动加逻辑# 过滤非 polygon 的 shape valid_shapes [s for s in data[shapes] if s[shape_type] polygon]如果确实需要保留 rectangle可以把它转成四个角点的 polygon再走后续流程。4.4 现象训练时提示 label 文件找不到或格式错误原因YOLO 训练时要求images和labels目录结构对应图片文件名和标签文件名一致除了扩展名。如果脚本生成的目录结构不符合 YOLO 预期或者文件名有空格、特殊字符就会报错。解决转换后检查目录结构确保images/train/下的xxx.jpg对应labels/train/xxx.txt。文件名尽量用英文和数字避免空格和中文。如果原始 JSON 文件名有特殊字符转换时重命名。4.5 现象--val_size切分后验证集为空或比例不对原因当 JSON 文件数量很少时按比例切分可能导致验证集为空。比如 5 个文件--val_size 0.1算出来是 0.5取整后可能变成 0。解决小数据集建议手动指定验证集或者把--val_size设大一点比如 0.3。也可以转换后手动移动文件确保训练集和验证集都有足够样本。我一般会在数据量少于 50 张时直接用 0.3 的比例避免验证集太小导致评估指标波动大。5. 进阶技巧让转换后的数据集直接进训练流程5.1 生成 YOLO 训练所需的 data.yaml转换完成后YOLO 训练还需要一个data.yaml里面指定训练集、验证集路径和类别名称。脚本本身可能不生成这个文件需要手动写# data.yaml train: /data/labelme_json/images/train val: /data/labelme_json/images/val nc: 3 names: [person, car, dog]nc是类别数names的顺序必须和转换时分配的 class_id 一致。如果类别顺序不对训练出来的模型会把类别搞混。我一般会从转换脚本的输出里复制类别列表确保一字不差。5.2 用 YOLOv5 或 YOLOv8 直接训练以 YOLOv5 为例把data.yaml放到项目根目录然后python train.py --data data.yaml --img 640 --batch 16 --epochs 100 --weights yolov5s.pt如果是分割任务YOLOv5 v7.0 支持--seg模式训练需要把data.yaml里的路径指向分割标签目录。YOLOv8 的话命令类似yolo segment train datadata.yaml modelyolov8n-seg.pt epochs100 imgsz640训练前建议先用少量数据跑几个 epoch确认 loss 正常下降再上全量数据。如果 loss 一直是 nan 或者不降回头检查标签格式和类别 id。5.3 可视化验证把标签画回图片上转换完不放心的话可以把 YOLO 标签画回图片肉眼确认一遍。用 OpenCV 或 PIL 都行import cv2 import numpy as np img cv2.imread(image_001.jpg) h, w img.shape[:2] with open(image_001.txt) as f: for line in f: parts line.strip().split() cls_id int(parts[0]) coords np.array([float(x) for x in parts[1:]]).reshape(-1, 2) coords[:, 0] * w coords[:, 1] * h coords coords.astype(np.int32) cv2.polylines(img, [coords], True, (0, 255, 0), 2) cv2.imwrite(vis_001.jpg, img)这段代码把归一化坐标还原成像素坐标画多边形轮廓。如果轮廓和原图里的目标对不上说明转换有问题。我每次转换完新数据集都会随机抽 5 张图做这个可视化确认没问题再开始训练。这个习惯帮我省了很多次重新训练的时间。5.4 批量处理多个目录与增量转换如果数据集分了好几个批次标注可以写个循环批量转换for dir in /data/batch1 /data/batch2 /data/batch3; do python labelme2yolo.py --json_dir $dir --val_size 0.2 --seg done转换完成后把各个批次的images和labels合并到一个总目录再统一生成data.yaml。注意合并时文件名不能冲突如果有重名需要加前缀区分。增量转换时已经转过的目录可以跳过只处理新增的 JSON。从那以后我每次拿到新标注的数据都会先跑一遍 label 分布统计确认类别命名统一再执行转换最后抽几张图做可视化验证。这套流程走下来基本没再因为格式问题翻过车。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。