恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

labelme与YOLO标注格式互转:从JSON到TXT的完整指南与避坑实践

  • 首页
  • 资讯中心
  • /
  • labelme与YOLO标注格式互转:从JSON到TXT的完整指南与避坑实践

相关资讯

Seata AT模式原理与实战:分布式事务全局锁与回滚机制详解 2026/10/21 12:18:46
表格+AI识图:破解工业场景图文协同难题的落地实践 2026/10/21 12:18:46
基于WSL2搭建低延迟直播:RTMP推流与HTTP-FLV播放实践 2026/10/21 12:13:46

最新资讯

提示工程架构师:用提示词模板驱动敏捷转型
技能体系构建指南:从知识到能力的刻意练习与复用方法
Windows SendMessage死锁原理与四级防护实战
知识工作插件系统架构设计与开发实践指南
litellm:统一大模型调用接口,告别多模型适配碎片化
免费GPU额度如何为AI Bot续命?个人开发者成本优化实战

今日推荐

SAP 屏幕上的金额未必存在数据库表里,从 WB2R_SV 的 Net Amount 看懂运行时计算
具身智能中‘指哪打哪’的视觉语言动作联合建模
AI时代人工翻译技术博客的价值与实践指南

本周热门

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

labelme与YOLO标注格式互转:从JSON到TXT的完整指南与避坑实践

发布时间:2026/10/21 12:18:47
labelme与YOLO标注格式互转:从JSON到TXT的完整指南与避坑实践 目标检测的数据标注是每个做视觉项目的人都绕不开的一道坎。我见过太多团队在标注工具上反复横跳有人习惯用 labelme 那种点几下就能画多边形、改点、加标签的交互觉得顺手也有人认准 YOLO 训练时那套一行一个框、归一化坐标的 txt 格式觉得喂给模型最省心。结果就是标注阶段用一套格式训练阶段要另一套格式中间全靠人肉转换转一次错一次错一次查半天。这篇就专门聊 labelme 和 YOLO 两种标注格式之间的互转把 JSON 和 TXT 之间那点事彻底讲透包括坐标怎么算、类别怎么映射、图片尺寸从哪来、批量脚本怎么写、以及我踩过的那些坑。不管你是刚接触目标检测的新手还是已经跑过几个项目的老手只要你的流程里同时出现过 labelme 和 YOLO这篇内容都能直接拿去用。1. 先搞清楚两种格式到底在存什么很多人转换出错根本原因不是脚本写错了而是压根没弄明白这两种格式各自在表达什么。labelme 存的是几何形状 语义标签YOLO 存的是归一化后的框 类别索引两者的坐标系、精度、组织方式都不一样。不把这一层想清楚后面全是玄学 bug。1.1 labelme 的 JSON 结构一个文件装一张图的所有标注labelme 是典型的一图一 JSON。你标注完一张图它会生成一个和图片同名的.json文件里面记录了图片路径、尺寸、以及一个shapes数组。每个 shape 代表一个标注对象核心字段有这么几个label类别名称是字符串比如 cat、person、defect。points构成这个形状的点坐标数组单位是像素原点在图片左上角。shape_type形状类型常见的有polygon多边形、rectangle矩形、circle、line、point。imageWidth/imageHeight图片的宽高这个字段非常关键YOLO 归一化就靠它。一个典型的矩形标注长这样{ version: 5.1.1, shapes: [ { label: person, points: [[102.5, 88.0], [340.2, 415.7]], shape_type: rectangle, flags: {} } ], imagePath: 0001.jpg, imageWidth: 1280, imageHeight: 720 }注意points里只有两个点分别是矩形的左上角和右下角。但 labelme 并不强制你按左上、右下的顺序点有人习惯从右下往左上拉那points就是反的。这一点在转换时必须处理否则算出来的宽高会是负数。1.2 YOLO 的 TXT 结构一行一个框全部归一化YOLO 的标注是一图一 TXT文件名和图片同名内容每一行代表一个目标格式固定为五个值class_id x_center y_center width height这里有几个硬性约定新手最容易搞错所有坐标都是归一化的也就是除以图片宽高之后的值范围在 0 到 1 之间。x_center、y_center是框中心点不是左上角。width、height是框的宽高也是归一化后的。class_id是从 0 开始的整数索引不是类别名字符串。比如上面那个 person 框假设它是第 0 类转换后大概是这样0 0.17285 0.34979 0.18570 0.455141.3 两种格式的核心差异对照把差异列成表转换时对着看能省很多事维度labelme JSONYOLO TXT文件粒度一图一 JSON一图一 TXT坐标单位像素绝对值归一化 0~1框表示左上右下两点中心点宽高类别表示字符串 label整数 class_id形状支持多边形/矩形/圆/线/点仅矩形框尺寸来源JSON 内自带需外部提供或读图这张表里最要命的是最后一行YOLO 的 TXT 本身不存图片尺寸所以从 YOLO 转回 labelme 时你必须知道每张图的宽高否则没法还原成像素坐标。这是双向转换里最容易翻车的地方后面会专门讲。2. labelme 转 YOLO从 JSON 到归一化 TXT 的完整链路labelme 转 YOLO 是更常见的需求因为大家通常先用 labelme 标再拿去训练 YOLO。这个方向的转换逻辑相对清晰但细节坑不少尤其是多边形和类别映射。2.1 矩形框的坐标换算中心点公式别记反矩形框的转换是基础公式必须记牢。假设 labelme 的两个点是(x1, y1)和(x2, y2)图片宽W、高Hx_min min(x1, x2) y_min min(y1, y2) x_max max(x1, x2) y_max max(y1, y2) x_center (x_min x_max) / 2 / W y_center (y_min y_max) / 2 / H width (x_max - x_min) / W height (y_max - y_min) / H这里用min/max就是为了兼容从右下往左上拉的情况。我见过有人直接拿points[0]当左上角结果一半的框位置全错排查了半天才发现是标注顺序问题。所以别偷懒老老实实取 min/max。2.2 多边形怎么变成矩形框取外接矩形labelme 支持多边形标注但 YOLO 检测只认矩形框。这时候通常的做法是取多边形的外接矩形bounding box也就是所有点里最小的 x、y 和最大的 x、yxs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys)需要提醒的是外接矩形会引入背景冗余。如果你的目标本身是细长或倾斜的外接框里会混进大量无关像素可能影响检测精度。这种情况要么改用分割任务YOLO 也支持 seg 格式存多边形归一化点要么在标注阶段就尽量用矩形框。我个人的经验是检测任务就老老实实标矩形别用多边形再转转出来的框质量不稳定。2.3 类别名到 class_id 的映射顺序必须固定YOLO 训练时class_id和类别名的对应关系由data.yaml里的names列表决定。所以转换脚本里必须维护一份固定的映射表比如class_map { person: 0, car: 1, dog: 2, }这里有个大坑映射表的顺序必须和训练时names的顺序完全一致。我见过一个项目转换脚本里 person 是 0但data.yaml里 person 写在第 2 位结果模型把人和狗认反了训练 loss 看着正常推理结果一塌糊涂。所以建议把映射表单独抽成一个配置文件转换和训练共用同一份从源头杜绝不一致。2.4 批量转换脚本遍历目录 跳过空标注单张转换没意义实际都是批量。下面是一个可直接用的脚本骨架import json import os from pathlib import Path class_map {person: 0, car: 1, dog: 2} def convert_one(json_path, out_dir): with open(json_path, r, encodingutf-8) as f: data json.load(f) W data[imageWidth] H data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue pts shape[points] xs [p[0] for p in pts] ys [p[1] for p in pts] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) xc (x_min x_max) / 2 / W yc (y_min y_max) / 2 / H w (x_max - x_min) / W h (y_max - y_min) / H lines.append(f{class_map[label]} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}) out_path Path(out_dir) / (Path(json_path).stem .txt) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines)) def batch_convert(json_dir, out_dir): os.makedirs(out_dir, exist_okTrue) for name in os.listdir(json_dir): if name.endswith(.json): convert_one(os.path.join(json_dir, name), out_dir)几个实操要点空标注要生成空文件。如果一张图没有任何目标YOLO 期望有一个空的 txt或者干脆没有这个文件取决于训练框架。我建议生成空文件避免训练时找不到标签报错。坐标保留 6 位小数足够再多没意义还占空间。编码统一用 utf-8否则中文路径或中文标签会炸。2.5 转换后的自检别等训练报错才发现转完不要直接开训先做几项检查随机抽几张图用可视化脚本把 YOLO 框画回原图肉眼确认位置对不对。检查所有坐标是否都在 0~1 之间出现负数或大于 1 的说明尺寸或公式有问题。统计每个类别的框数量和 labelme 里的标注数量对一下防止漏转。我一般会写一个简单的可视化函数把归一化坐标乘回宽高再画框这一步能拦下 90% 的低级错误。3. yolo2labelme反向转换里那些容易忽略的细节从 YOLO 转回 labelme 的需求相对少但也不是没有。比如你想用 labelme 的可视化工具检查 YOLO 标注质量或者想把已有的 YOLO 数据集导入 labelme 做二次修正。这个方向的难点在于TXT 里没有图片尺寸也没有类别名。3.1 图片尺寸从哪来必须读图或查表YOLO 的 TXT 只有归一化坐标要还原成像素必须知道每张图的W和H。有两种做法直接读图用 PIL 或 OpenCV 打开对应图片取img.size。简单可靠但要求图片和 TXT 在同一目录或能对应上。查尺寸表如果图片不在手边就得提前准备一份文件名 - (W, H)的映射表。我推荐直接读图因为最不容易出错。用 PIL 的话from PIL import Image img Image.open(img_path) W, H img.size注意 OpenCV 读出来是(H, W)顺序PIL 是(W, H)别搞混这个坑我踩过不止一次。3.2 类别名从哪来反向查映射表YOLO 的class_id是整数labelme 需要字符串 label。所以你得有一份id - name的反向映射。如果训练时用的是data.yaml直接读它的names列表就行id2name {i: name for i, name in enumerate(names)}这里同样强调一致性反向映射必须和当初正向转换用的是同一份类别定义否则转出来的标签名对不上白忙活。3.3 中心点宽高还原成左上右下反向公式是正向的逆运算x_min (x_center - width / 2) * W y_min (y_center - height / 2) * H x_max (x_center width / 2) * W y_max (y_center height / 2) * H还原出来的点是浮点数labelme 能接受浮点坐标但如果你想要整数可以四舍五入。我一般保留一位小数既精确又不至于太啰嗦。3.4 生成符合 labelme 规范的 JSONlabelme 的 JSON 有一些字段是它读取时依赖的不能省。一个最小可用的结构import json labelme_data { version: 5.1.1, flags: {}, shapes: [], imagePath: img_name, imageData: None, imageWidth: W, imageHeight: H, } for line in lines: cid, xc, yc, w, h line.split() cid int(cid) xc, yc, w, h map(float, (xc, yc, w, h)) x_min (xc - w / 2) * W y_min (yc - h / 2) * H x_max (xc w / 2) * W y_max (yc h / 2) * H labelme_data[shapes].append({ label: id2name[cid], points: [[x_min, y_min], [x_max, y_max]], group_id: None, shape_type: rectangle, flags: {}, }) with open(out_json, w, encodingutf-8) as f: json.dump(labelme_data, f, ensure_asciiFalse, indent2)几个关键点imageData设为None就行labelme 会自己去读图片不用把 base64 塞进去否则 JSON 会巨大。shape_type必须是rectangle否则 labelme 打开时可能不认。points顺序是左上、右下这个顺序 labelme 是认的不用纠结。3.5 反向转换的验证用 labelme 打开看一眼转完直接拿 labelme 打开生成的 JSON看框的位置和标签对不对。这一步最直观比写任何断言都管用。如果框整体偏移或缩放八成是 W/H 搞反了或者归一化坐标没乘对。4. 双向转换里我踩过的坑和对应的解法前面讲了流程这一节专门讲坑。这些坑都是我在实际项目里真金白银踩出来的写出来能帮你省下大量排查时间。4.1 坐标越界归一化后出现负数或大于 1现象转换后某些框的坐标是负数或者大于 1训练时直接报错或框跑到图外。原因通常是标注时框超出了图片边界。labelme 允许你把框拉到图片外面但 YOLO 的归一化坐标理论上应该在 0~1 之间。解法转换时做一次裁剪clip把坐标限制在 0~1xc min(max(xc, 0), 1) yc min(max(yc, 0), 1) w min(max(w, 0), 1) h min(max(h, 0), 1)但更根本的做法是标注阶段就别让框出界出界的框本身质量就有问题。4.2 图片尺寸不一致JSON 里的尺寸和实际图片对不上现象转换后框的位置整体偏移或缩放。原因labelme 的 JSON 里存了imageWidth和imageHeight但如果图片后来被裁剪、缩放、替换过JSON 里的尺寸就和实际图片不一致了。转换时如果信了 JSON 里的尺寸算出来的归一化坐标就是错的。解法转换时以实际图片的尺寸为准而不是 JSON 里的。用 PIL 读一下真实尺寸覆盖 JSON 里的值。这个坑很隐蔽因为 JSON 里的尺寸看起来很合理你不会怀疑它。4.3 类别名大小写和空格看不见的杀手现象某些类别的框全部丢失或者映射到错误的 id。原因类别名里有看不见的空格或者大小写不一致。比如person和person 末尾空格在字典里是两个不同的 key。解法转换前对 label 做一次清洗label shape[label].strip()同时建议在标注规范里明确要求类别名统一小写、无空格。我见过一个团队两个人分别标了Car和car结果训练时被当成两个类模型直接懵了。4.4 多边形点顺序混乱外接矩形算错现象多边形转矩形后框的位置或大小明显不对。原因多边形的点顺序不固定有人顺时针点有人逆时针点甚至有人乱序点。如果你假设点是有序的算外接矩形就会出错。解法永远用min/max遍历所有点不要假设点的顺序。这是最稳妥的做法。4.5 空标注和缺失文件训练时的隐形炸弹现象训练时报找不到标签文件或者某些图被静默跳过。原因有些图没有目标labelme 可能没生成 JSON或者转换时没生成对应的空 TXT。解法转换脚本里显式处理空标注生成空文件。同时训练前做一次完整性检查确保每张图都有对应的标签文件哪怕是空的。5. 把转换做成可复用的工具工程化的一点思考单次转换用脚本就够了但如果你的项目要反复迭代标注会不断更新每次都手动跑脚本很容易出错。我的做法是把转换逻辑封装成一个命令行工具支持配置文件和参数。5.1 用配置文件管理类别映射把类别映射、输入输出目录、是否裁剪等参数写进一个 YAMLclass_map: person: 0 car: 1 dog: 2 input_dir: ./labels_json output_dir: ./labels_txt clip: true脚本读这个配置转换和训练共用同一份类别定义彻底消除不一致。5.2 加日志和统计方便排查转换时打印统计信息比如处理了多少文件、跳过了多少、每个类别多少个框。这些信息在排查问题时非常有用。我一般会在转换结束后输出一个汇总处理文件数: 1200 跳过文件数: 3 person: 3400 个框 car: 2100 个框 dog: 800 个框5.3 支持增量转换如果只新增了几十张标注没必要全量重转。可以记录已转换的文件列表只处理新增或修改过的。这个优化在数据集大的时候能省不少时间。6. 转换之外一些关于标注流程的经验格式转换只是标注流程里的一环真正影响效率的是整个流程的设计。分享几点我的经验。6.1 标注规范要提前定死类别名、框的松紧程度、是否允许出界、多边形还是矩形这些都要在标注开始前定好写成文档发给所有标注人员。我见过太多项目标到一半发现规范不统一返工的成本远高于一开始多花半小时定规范。6.2 转换脚本要版本化转换脚本本身也是代码要纳入版本管理。因为类别映射、坐标处理逻辑可能会变出问题时能回溯到具体版本。别把脚本随手丢在桌面过两个月自己都找不到。6.3 转换后一定要可视化抽检不管脚本写得多自信转完都要抽几张图可视化确认。这一步花不了几分钟但能拦住绝大多数低级错误。我习惯抽 10 张覆盖不同类别和不同尺寸的图。6.4 保留原始标注转换是单向的但原始标注要保留。万一转换逻辑有问题还能从原始 JSON 重新转。别转完就把 JSON 删了这个教训我吃过一次重标了一整天。7. 常见问题速查把高频问题整理成表遇到时直接对号入座问题现象可能原因排查方向框位置整体偏移图片尺寸不一致用实际图片尺寸覆盖 JSON 尺寸框大小不对归一化公式用错检查是否除以了 W 和 H部分类别丢失类别名不匹配检查大小写、空格、映射表坐标为负或大于 1框超出图片边界加 clip 或修正标注多边形转框不准点顺序假设错误用 min/max 遍历所有点训练找不到标签空标注未生成文件显式生成空 TXT反向转换框错位W/H 顺序搞反PIL 是 (W,H)OpenCV 是 (H,W)这张表基本覆盖了 90% 的转换问题遇到时先对照排查能省下大量瞎试的时间。8. 写在最后的一点个人体会labelme 和 YOLO 的格式互转技术上并不复杂无非是坐标换算和类别映射。但真正让人头疼的从来不是公式而是数据本身的不规范尺寸对不上、类别名不统一、框出界、点顺序乱。这些问题在单个文件上看不出来一旦批量处理就集中爆发。我的建议是把转换脚本当成项目基础设施来对待而不是临时用的一次性代码。类别映射抽成配置、加日志统计、转换后可视化抽检、保留原始标注这几件事做下来转换环节基本就不会再出问题了。另外标注规范一定要在动手标之前定死这比任何脚本优化都管用。格式转换只是手段干净、一致的数据才是目标检测项目真正的地基。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号