labelImg图像标注实战:从解压到YOLO格式转换与质检
简介LabelImg 是一款可视化图像标注工具面向从事目标检测任务的数据标注人员、算法工程师与深度学习初学者用于为 Faster R-CNN、YOLO、SSD 等网络构建训练数据集标注结果以遵循 PASCAL VOC 格式的 XML 文件输出。该压缩包为工具源码方便无法访问 GitHub 的用户直接获取运行前需配置 Python 与 lxml 环境。包内共 127 个文件以 44 个 py 源码文件为核心辅以 38 个 png 界面图标、6 个 sh 脚本、6 个 svg 矢量图及若干 txt、rst、md 说明文档另有 cfg、yml 等配置文件整体约 6.39MB体积轻量、结构完整。已有 357 人学习下载读者可据此获得可本地运行的标注工具源码理解其界面与标注逻辑并直接产出符合 VOC 规范的数据集为后续检测模型训练打好数据基础。1. 拿到 labelImg-master.rar 先别急着解压它到底解决哪类标注活上周有个做质检的朋友甩过来一个压缩包说产线上攒了两千多张缺陷图想先框出划痕和凹坑再谈训练问我有没有轻量点的工具。我看了眼文件名——labelImg-master.rar这玩意儿在图像标注圈子里算是老熟人了。它解决的就是最朴素的那类需求给图片画矩形框、打类别标签、导出成训练框架能直接吃的格式。适合谁适合手头有一批图、要快速产出检测数据集、又不想被在线平台账号和网络环境卡住的人。它不适合做分割、关键点、旋转框也不适合多人协同标注这点先摆明。下面按我实际拆包、跑通、踩坑的顺序讲新手能照着走熟手能直接跳到参数和排错那几节。2. 解压与跑起来从 rar 到第一个框的完整链路2.1 先看清包里的东西别把源码当成品labelImg-master.rar 解压出来是一个源码目录不是双击就能用的 exe。目录里通常能看到labelImg.py这个入口、libs/放界面和标注逻辑、data/放预定义类别文件、resources.py是 Qt 资源编译产物。很多人第一次翻车就翻在这以为解压完找 exe结果找不到转头去搜“labelImg 安装包”下到一堆来路不明的封装版。我的建议是老老实实走源码这条路依赖清楚、出问题能定位。先确认 Python 环境。我一般用 3.8 到 3.10 之间的版本太新的 Python 配老版本 PyQt5 偶尔会闹脾气。建个独立环境再装依赖别往系统 Python 里怼# 建独立环境避免污染系统 Python python -m venv labelenv # Windows 激活 labelenv\Scripts\activate # macOS / Linux 激活 source labelenv/bin/activate # 装核心依赖PyQt5 是界面lxml 用于解析 XML 标注文件 pip install pyqt5 lxml装完进到解压目录直接跑入口脚本# 进入源码目录路径按你实际解压位置改 cd labelImg-master # 启动主程序 python labelImg.py界面能弹出来说明链路通了。这里有个参数说明labelImg.py后面可以跟图片目录或预定义类别文件比如python labelImg.py /path/to/images predefined_classes.txt启动时直接加载省得进去再点。predefined_classes.txt放在data/下一行一个类别名改完重启生效。我习惯先把类别定死再开标避免标到一半发现类别名拼错、回头批量改 XML 的血泪经验。2.2 快捷键和保存格式决定你后面返工多少界面起来后真正影响效率的是保存格式和快捷键。右下角有个格式切换默认 Pascal VOC 的 XML也能切 YOLO 的 txt。这个选择不是随手点的得看你下游训练用什么。用 YOLO 系列就切 YOLO用 Faster R-CNN 这类就留 VOC。切错了不是不能救但要写转换脚本多一道工序。常用操作我列一下都是肌肉记忆级别的操作快捷键说明画框w拖拽出矩形松手弹类别输入下一张d保存当前标注并跳转上一张a回看上一张保存CtrlS手动存当前 XML/txt删除框Delete选中框后删放大缩小Ctrl滚轮小目标必用画框时有个细节类别输入框支持下拉选预定义类别但如果你没加载predefined_classes.txt就得手打手打就容易出现“scratch”和“Scratch”两种写法后面统计类别直接裂开。所以第 2.1 节说的先定类别文件不是可选项。保存路径默认跟图片同目录文件名同名、后缀换 xml 或 txt。批量标的时候我建议开“自动保存”在菜单里勾上每切一张自动落盘避免标了五十张忘了存、一个误操作全没的后悔药场景。YOLO 格式下还会生成一个classes.txt记录类别顺序这个文件千万别丢训练时类别索引对不上模型学出来的全是错位标签。3. 格式转换与批量处理VOC、YOLO 之间怎么来回倒3.1 两种格式的坐标逻辑差的不只是后缀VOC 的 XML 存的是绝对像素坐标xmin, ymin, xmax, ymax直观但跟图片分辨率绑死。YOLO 的 txt 存的是归一化的中心点加宽高class_id cx cy w h全部除以图片宽高范围 0 到 1。这个差异决定了换分辨率、做多尺度训练时YOLO 格式更省心但要人工核对框位置VOC 的绝对坐标更好读。labelImg 切到 YOLO 模式保存时会自动读图片尺寸做归一化你不用手算。但有个坑如果图片是 CMYK 模式或者带 EXIF 旋转信息读出来的宽高可能跟肉眼看到的不一致归一化就偏了。常见做法是标注前先用脚本把图片统一转成 RGB、剥掉 EXIF 旋转再进 labelImg。我一般会跑一遍预处理from PIL import Image, ImageOps import os src_dir raw_images dst_dir clean_images os.makedirs(dst_dir, exist_okTrue) for name in os.listdir(src_dir): if not name.lower().endswith((.jpg, .jpeg, .png)): continue path os.path.join(src_dir, name) img Image.open(path) # 按 EXIF 方向摆正避免宽高颠倒 img ImageOps.exif_transpose(img) # 统一转 RGB丢掉 CMYK / 调色板模式 img img.convert(RGB) img.save(os.path.join(dst_dir, name))这段逻辑说明exif_transpose处理手机拍的图带旋转标记的情况convert(RGB)保证后续读尺寸稳定。参数上没太多可调的目录名按你实际改。跑完再进 labelImg归一化坐标就不会莫名其妙偏一截。3.2 已有 VOC 标注要转 YOLO写个脚本一次搞定现实里经常是前人用 VOC 标了一批你现在要喂 YOLO。labelImg 本身不做批量转换得自己写。下面这个脚本读 XML、按图片实际尺寸归一化、输出 txt同时生成classes.txtimport os import xml.etree.ElementTree as ET from PIL import Image voc_dir annotations # XML 所在目录 img_dir clean_images # 对应图片目录 out_dir labels_yolo # 输出 txt 目录 os.makedirs(out_dir, exist_okTrue) classes [] for xml_name in os.listdir(voc_dir): if not xml_name.endswith(.xml): continue tree ET.parse(os.path.join(voc_dir, xml_name)) root tree.getroot() # 用图片真实尺寸做归一化别信 XML 里的 size 字段 img_path os.path.join(img_dir, xml_name.replace(.xml, .jpg)) w, h Image.open(img_path).size lines [] for obj in root.findall(object): cls obj.find(name).text if cls not in classes: classes.append(cls) cid classes.index(cls) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 转中心点 宽高再归一化 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cid} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(os.path.join(out_dir, xml_name.replace(.xml, .txt)), w) as f: f.write(\n.join(lines)) with open(os.path.join(out_dir, classes.txt), w) as f: f.write(\n.join(classes))逻辑说明类别索引按首次出现顺序累积所以classes.txt的顺序必须跟训练配置里的names完全一致否则标签全错位。参数上:.6f保留六位小数够用YOLO 官方也是这个精度。注意我特意用Image.open读真实尺寸而不是 XML 里的width/height因为有些标注工具写的 size 字段跟实际图对不上这是踩过的坑。转完抽几张用可视化脚本画框核对别直接开训。4. 避坑与排查标注环节最容易翻车的五件事4.1 启动报 Qt 平台插件错误现象命令行跑python labelImg.py弹could not find or load the Qt platform plugin windows。原因多半是 PyQt5 装得不完整或者环境里混了多个 Qt 版本。解决先pip uninstall pyqt5 pyqt5-tools再重装pip install pyqt5确保在激活的虚拟环境里操作。还不行就检查QT_QPA_PLATFORM_PLUGIN_PATH有没有被别的软件污染临时清掉再试。4.2 中文路径导致图片加载失败现象图片目录带中文列表里能看到文件名但预览是空白。原因底层读图库对非 ASCII 路径处理不稳。解决把图片和标注目录都挪到纯英文路径下比如D:/dataset/images。这是最省事的办法别去改源码编码改完这个环境换个机器又崩。4.3 标完发现类别名拼错要批量改现象标了三百张才发现“defect”打成了“defct”。原因没加载预定义类别文件手打失误。解决写脚本批量替换 XML 里的name文本或 YOLO txt 里改classes.txt顺序后重映射 class_id。血泪经验是开标前一定用predefined_classes.txt锁死类别比事后补救便宜太多。4.4 YOLO 标签训练时全错位现象训练 loss 不降可视化预测框全在奇怪位置。原因classes.txt的类别顺序跟训练配置的names不一致或者转换时用了 XML 里的错误尺寸。解决核对两边类别顺序逐行比对转换脚本强制用Image.open读真实宽高。这个黑匣子一旦出现排查顺序永远是先查类别映射、再查坐标归一化。4.5 大图小目标画框手抖现象4K 图上标几十像素的缺陷框总是偏。原因默认缩放级别下像素太密。解决Ctrl滚轮放大到目标占屏幕合适比例再画画完用方向键微调框边。另外可以开“十字准星”辅助定位。别在缩略视图下硬标偏差几个像素在归一化后会被放大。5. 进阶把标注质量卡在入库前而不是训练后标完不等于能用。我现在的习惯是labelImg 产出之后、进训练之前强制走一遍质检脚本把明显有问题的样本拦下来。这一步花十分钟能省掉训练一晚上发现数据脏的崩溃。质检主要看三件事框是否越界坐标小于 0 或大于 1、宽高是否为零或异常小、类别 id 是否超出classes.txt范围。下面这段扫一遍 YOLO 标签目录import os label_dir labels_yolo num_classes 3 # 跟 classes.txt 行数保持一致 bad [] for name in os.listdir(label_dir): if not name.endswith(.txt) or name classes.txt: continue with open(os.path.join(label_dir, name)) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: bad.append((name, i, 字段数不对)) continue cid int(parts[0]) cx, cy, w, h map(float, parts[1:]) # 越界、零面积、类别越界都记下来 if cid 0 or cid num_classes: bad.append((name, i, 类别越界)) if not (0 cx 1 and 0 cy 1): bad.append((name, i, 中心点越界)) if w 0 or h 0 or w 1 or h 1: bad.append((name, i, 宽高异常)) for item in bad: print(item) print(f问题条目共 {len(bad)} 条)逻辑说明num_classes必须跟classes.txt实际行数对齐这是最容易忘的参数。越界判断用闭区间因为归一化后理论上限就是 1。跑出来有问题条目回到 labelImg 定位到具体图片重修别在脚本里自动裁剪——自动裁剪会把框改小语义可能就变了。再补一个习惯每批标完随机抽 5% 用可视化脚本把框画回图上人眼过一遍。机器质检能抓坐标错误抓不了“框住了但框错对象”这种语义错误。我一般会写个十行的 PIL 脚本叠框出图扫一眼就知道这批质量稳不稳。从那以后我每次交付数据集前都强制走一遍“脚本质检 抽检可视化”这两道再没出现过训练到一半发现标签错位的翻车。希望这套流程帮到你少走我当年那些弯路。本文还有配套的精品资源点击获取