简介这是一份面向深度学习与计算机视觉初学者、数据标注实践者的 labelImg 图像标注工具资源包基于 Python 与 Qt 构建主要用于在图像上绘制边界框、标注多类别目标并将结果保存为 PASCAL VOC 标准 XML服务于目标检测等任务的数据准备。压缩包共 108 个文件约 6.61MB包含 21 个 py 源码、38 个 png 界面与示例图、15 个 pyc 编译文件、6 个 svg 图标、6 个 sh 脚本以及 rst、md、txt 等说明文档兼顾运行、界面资源与二次开发参考。已有 1145 人学习下载。资源保留完整工程结构与示例图片支持跨平台使用、自定义类别、快捷键调整边界框标注结果可对接 TensorFlow、PyTorch 等框架其图形界面直观支持 JPEG、PNG 等常见格式并提供 W、A、S、D、Q 等快捷键辅助框选与微调适合缺少编程背景的标注人员快速上手。读者可据此了解工具实现、快速搭建标注环境并用于物体检测、医学影像分析等场景的数据预处理。1. labelImg 装不上多半是 Python 与 Qt 绑定的版本没用对上周某实验室的 A 同学把 labelImg 装到第三遍才跑起来第一次在 Python 3.11 环境下安装 PyQt5 时编译报错第二次是因为源码目录里缺了libs/resources.py导致启动直接报 ImportError第三次pip install明明成功了敲labelImg却提示命令不存在。labelImg 这个图像标注工具在深度学习数据准备环节出现频率极高安装本身不难难的是 Python 版本、PyQt5 绑定和启动入口这三件事同时匹配到正确组合。这篇记录按「选版本 → 装包 → 配参数 → 排错 → 验证」的顺序走一遍主线环境是 Windows 11 Python 3.9 虚拟环境Linux 和 macOS 的差异单独标出来。新手照着敲能跑通熟手可以直接跳到版本取舍和排查那两章。2. 选版本与备环境labelImg 1.8.6 该落在哪个 Python 上labelImg 安装失败多数情况不是 labelImg 自己的问题而是它所依赖的 PyQt5 没装稳。这个工具从很早就开始流行一路迭代到 1.8.x代码里用到了不少 PyQt5 的早期 API同时又依赖 lxml 解析 Pascal VOC 的 XML。所以动手之前的第一件事不是敲 pip而是先把 Python、PyQt5、labelImg 三者的版本关系定下来。我一般会在装之前确认两件事这台机器上有没有 Python 3.8 或 3.9 可用以及全局环境里是不是已经有别的项目占了 PyQt5。这两条确认完后面 90% 的意外都能提前避开。2.1 Python 版本与 PyQt5 的对应关系labelImg 1.8.6 的setup.py里写的是 Python 3.6但这只是最低门槛不代表高版本就顺。真正的分水岭在 PyQt5 的预编译轮子wheel覆盖到哪个 Python 版本以及pyrcc5这个资源编译工具还能不能正常工作。Python 版本PyQt5 安装表现建议3.6 / 3.7轮子齐全但已停止维护lxml 新版可能装不上不推荐只在老机器上妥协3.8全部有预编译轮子labelImg 1.8.6 实测最稳首选3.9全部有预编译轮子与 3.8 表现基本一致首选3.10PyQt5 5.15.9 可用个别发行版要手动补依赖可用遇到问题先回退 3.93.11 / 3.12pip 解析 PyQt5 时容易拉到需要本地编译的源码包Windows 上大概率卡住别在这个版本上折腾我一般固定用 Python 3.9 PyQt5 5.15.9 这一组。PyQt5 不要装最新版5.15.10 之后部分发行版把 Qt 的插件路径改了labelImg 启动时会去platforms目录找qwindows.dll而找不到报出来的错跟 Python 一点关系都没有很容易被误导。锁 5.15.9 是最省事的选择。注意不要在一个已经装了 PyQt6 或 PySide6 的全局环境里装 labelImg。三者共用 Qt 的运行时目录混装后Qt platform plugin报错会间歇性出现排查成本极高。2.2 三种安装方式pip 轮子、源码、免安装可执行文件labelImg 的获取方式有三条路选哪条取决于你的网络条件、是否需要改代码、以及目标机器能不能装 Python。方式适合场景优点代价pip install labelImg本机开发、有 Python 环境一条命令自动带 PyQt5 和 lxml装的是发布版改不了源码源码编译需要改界面、改保存逻辑、打补丁可调试、可打包要手动编译resources.qrc免安装可执行文件标注外包、非开发同事的机器双击即用不碰 Python版本固定出问题只能换包标注团队里常见的做法是算法同学用 pip 或源码装标注同学统一发免安装包。这不是技术洁癖而是标注同学的机器上往往还装着一堆办公软件一旦让他们自己配 Python 环境变量问题就会成倍增加。2.3 虚拟环境与目录规划不管走哪条路都不要装进全局 site-packages。labelImg 对 PyQt5 的版本很敏感一旦跟别的项目撞上修起来比重装还慢。# Windowscmd 或 PowerShell 都适用 python -m venv .venv-labelimg .venv-labelimg\Scripts\activate python -V# Linux / macOS python3.9 -m venv .venv-labelimg source .venv-labelimg/bin/activate python -V第一段是 Windows 的激活脚本路径Scripts目录下同时会生成labelImg.exe第二段是类 Unix 系统激活脚本在bin下。python -V这一步别省很多人激活失败但没察觉后面 pip 照样装到全局去了。如果习惯用 condaconda create -n labelimg python3.9效果一样好处是 PyQt5 可以直接走 conda 的二进制渠道省掉编译。目录上我一般这么排路径用途D:\labelimg\.venv-labelimg虚拟环境不提交、不迁移D:\labelimg\src源码目录走源码安装时D:\dataset\images待标注图片D:\dataset\annotations标注结果输出目录D:\dataset\predefined_classes.txt预定义类别虚拟环境和数据集目录分开放是因为虚拟环境动辄几百兆而数据集经常要拷来拷去。把两者放进同一个文件夹同步盘一开就会把 site-packages 一起传上去血泪经验。3. 装 labelImgpip 一条命令背后实际发生了什么确认好 Python 版本和虚拟环境接下来的安装反而快。但快不等于可以盲敲知道 pip 那一条命令替你做了什么出问题时才知道往哪看。3.1 pip 安装与启动入口# 先升级 pip老版本 pip 在解析 PyQt5 依赖时容易拉到源码包 python -m pip install --upgrade pip # 锁定 labelImg 版本避免团队里各人装到不同小版本 pip install labelImg1.8.6 # 确认包装到了当前虚拟环境里 pip show labelImg这三步里第二步锁版本是关键。不锁版本时pip 会取最新发布版不同人装出来的界面可能差一个按钮的位置团队协作时沟通成本很高。第三步pip show会打出Location字段那串路径如果指向全局 site-packages说明虚拟环境根本没激活回去重来。装完启动有两个入口# 入口一直接敲命令前提是 Scripts / bin 目录在 PATH 里 labelImg # 入口二入口不在 PATH 时用模块方式启动最稳 python -m labelImgWindows 上pip install会在.venv-labelimg\Scripts\下生成labelImg.exe虚拟环境激活后这个目录会被临时加进 PATH所以能直接敲。退出虚拟环境后再敲就会提示「不是内部或外部命令」这不是装坏了是入口不在 PATH 里。python -m labelImg不依赖 PATH任何时候都能用我一般把它当作默认启动方式。pip 装下来的 wheel 里已经包含了编译好的libs/resources.py所以 pip 路线不需要碰pyrcc5。这一点很重要——后面源码路线报的错pip 路线根本不会遇到。3.2 源码安装先补上 libs/resources.py 再谈启动需要改界面、改导出逻辑或者打包分发时走源码。源码包解压后进入目录依次做四件事装依赖、编译资源、确认入口、启动。# 进入解压后的源码目录 cd labelImg-1.8.6 # 按 requirements 装依赖PyQt5 单独锁版本 pip install pyqt55.15.9 lxml # 把 resources.qrc 编译成 Python 模块这一步漏了必然 ImportError pyrcc5 -o libs/resources.py resources.qrc # 启动 python labelImg.pyresources.qrc是 Qt 的资源描述文件里面登记了图标、样式表这些二进制资源。pyrcc5是 PyQt5 自带的资源编译器作用是把.qrc翻译成一个可以直接import的resources.py。源码仓库里只放.qrc不放编译产物所以任何一次全新拉取或解压源码都必须重新编译一遍。-o libs/resources.py里的-o是输出路径必须落在libs/目录下因为labelImg.py顶部写的是from libs.resources import *。有人习惯编译到当前目录然后启动时报ModuleNotFoundError: No module named libs.resources原因就在这里。libs目录下没有__init__.py也没关系Python 3 的命名空间包机制能处理。装完依赖后可以先跑一次自检确认 Qt 能加载# 单独验证 PyQt5 是否可用不涉及 labelImg 代码 python -c from PyQt5.QtWidgets import QApplication; print(qt ok)能打qt ok说明 PyQt5 这一层通了后面再报错就只可能是 labelImg 自己的问题排查范围一下缩小一半。3.3 离线机器把依赖打成轮子带过去标注机器经常是内网连不上任何包源。这时候在有网机器上把整串依赖下载成 wheel 文件拷过去离线安装。# 在有网的同架构机器上执行--only-binary 保证只下预编译轮子 pip download labelImg1.8.6 \ --python-version 3.9 \ --platform win_amd64 \ --only-binary:all: \ -d ./wheels--python-version和--platform必须和目标机器完全一致写错一个就会下到不适用的包拷过去装的时候报is not a supported wheel on this platform。-d ./wheels是输出目录跑完之后目录里应该有 labelImg、PyQt5、PyQt5-Qt5、PyQt5-sip、lxml 这几组 wheel。离线机器上的安装# --no-index 禁止联网--find-links 指向本地轮子目录 pip install --no-index --find-links./wheels labelImg1.8.6--no-index关掉包源索引--find-links让 pip 只在本地目录里找。两个参数少一个pip 都会尝试联网内网环境下会卡到超时再回退看着像卡死。这套流程我在几个隔离环境里跑过比现场配源稳定得多。4. 配标注环境类别文件、保存格式与启动参数工具装起来只是能开界面真正决定标注产出的是类别文件、保存格式和启动参数这三项配置。这三项配错标注出来的数据在训练脚本里读不出来返工成本比装环境高一个量级。4.1 预定义类别data/predefined_classes.txt 只负责少打字labelImg 支持一个预定义类别列表界面上双击创建标注框时下拉框里直接给出这些类别不用每次手打。文件位置分两种情况pip 安装的在site-packages/labelImg/data/predefined_classes.txt源码安装的在源码目录的data/predefined_classes.txt。person vehicle helmet格式极简一行一个类别不能有逗号、不能有编号、不能有空行夹在中间。文件编码用 UTF-8Windows 记事本另存时容易存成带 BOM 的 UTF-8labelImg 读到第一行会带一个不可见字符界面上表现为第一个类别名前面多一个方块训练时这个类别永远匹配不上。改完文件必须重启 labelImg 才生效因为它只在启动时读一次。这里有个常见误解要说清预定义类别文件只影响下拉框的候选项不做任何校验。你完全可以在界面上手打一个不在列表里的类别名labelImg 会照写不误。所以团队协作时这份文件是约定不是约束最终还是要靠导出后的校验脚本兜底。提示把predefined_classes.txt和数据集一起放进版本库谁改了类别顺序都能追溯。类别顺序在 YOLO 格式里是硬约定顺序一变历史标注全部错位。4.2 保存格式Pascal VOC 与 YOLO 的切换时机labelImg 支持 Pascal VOC 的 XML、YOLO 的 txt以及 CreateML 的 json。格式不是全局设置而是在保存的那一刻由界面上的格式开关决定。这意味着两件事切换格式必须在开始标注之前标到一半再切前面那些图还是老格式以及「更改保存目录」是独立的改目录不会自动改格式。YOLO 格式的一行长这样# 说明用真实文件里不能带 # 开头的注释行 # 格式为 class_id x_center y_center width height后四个值已归一化到 0~1 0 0.482353 0.561111 0.175294 0.244444 2 0.812500 0.336111 0.121569 0.188889class_id从 0 开始对应classes.txt里的行序第一行是 0第二行是 1以此类推。后四个值是相对整图宽高的比例不是像素所以换分辨率不会失效。这四个数由 labelImg 自动算不用手填但校验的时候要拿它们反算回像素确认框没超出图边界。YOLO 模式要求保存目录下存在一个classes.txtlabelImg 第一次在该目录保存时会尝试生成。如果目录是只读的或者挂的是网络盘生成会失败表现是标注框能画但保存后 txt 里只有数字没有类别映射后面训练时类别名全丢。我一般会在开始标注前手动放一个classes.txt进去内容跟predefined_classes.txt完全一致多一层保险。格式输出文件适用训练框架注意点Pascal VOC每图一个.xml多数检测框架的 VOC 数据集加载器坐标是绝对像素换分辨率要重算YOLO每图一个.txt 一个classes.txtYOLO 系列坐标归一化类别 id 依赖行序CreateML单个.jsonApple 生态的训练工具全部标注汇总在一个文件里多人协作易冲突4.3 启动参数与快捷键启动时可以带参数直接把图片目录和类别文件喂进去省掉每次开界面再点目录。# 第一个参数是图片目录第二个是预定义类别文件 labelImg D:\dataset\images D:\dataset\predefined_classes.txt # 自动保存模式 关闭标签排序批量标注时效率提升明显 labelImg D:\dataset\images D:\dataset\predefined_classes.txt --autosave --nosortlabels--autosave让每次切图时自动落盘代价是没有「这张还没标完」的缓冲画错一个框也会被立刻写进文件。--nosortlabels关掉标签列表的字母排序改成按出现顺序排列标注类别多的时候找起来更快。这两个参数在批量作业里我基本默认开着。参数作用什么时候用--autosave切图时自动保存大批量、流程固定的标注--nosortlabels标签列表不排序类别超过 10 个--labels从文件加载标签列表类别集中管理--keep-prev保留上一张图的标注框视频抽帧、连续画面--config指定配置文件路径多套数据集切换--keep-prev这个参数值得单独说一句。视频抽帧出来的连续图片前后帧目标位置几乎一样保留上一帧的框再微调比每次从零画快好几倍。但它也是双刃剑目标走出画面后如果忘了删就会留下一堆错标校验脚本一定要能查出框超出边界的记录。常用快捷键记住六个就够日常用快捷键动作W创建矩形框Ctrl S保存当前标注D下一张A上一张Ctrl U加载目录下全部图片Del删除选中的框Ctrl U和直接指定目录的区别在于前者会把目录下所有图片一次性列进左侧文件列表后者只加载当前这一张。批量标注一定要用Ctrl U否则每换一张都要重新点开文件对话框。5. 常见问题排查labelImg 起不来、存不下的五个现场下面五条是我在实际环境里反复遇到的按「现象 → 原因 → 解决」记遇到同类问题可以直接对号。5.1 启动报 No module named libs.resources现象源码目录下执行python labelImg.py立刻抛出ModuleNotFoundError: No module named libs.resources界面根本不出现。原因resources.qrc没有编译或者编译产物没落在libs/目录下。源码仓库不包含这个生成文件每次全新拉取都要重新生成一次。解决在源码根目录执行pyrcc5 -o libs/resources.py resources.qrc然后确认libs/resources.py确实存在且大小不为 0。如果提示pyrcc5: command not found说明 PyQt5 没装进当前虚拟环境先pip install pyqt55.15.9再重试。5.2 Linux 上 Qt platform plugin xcb 加载失败现象命令行启动后报qt.qpa.plugin: Could not load the Qt platform plugin xcb in even though it was found程序直接退出。原因精简版 Linux 发行版或容器镜像里缺 xcb 相关的系统库PyQt5 的platforms/libqxcb.so找不到依赖。这跟 Python 包无关是系统层的动态库缺失。解决先定位到底缺哪个库再按名字补装。常见做法是装libxcb-xinerama0、libxcb-icccm4、libxcb-image0、libxcb-keysyms1、libxcb-render-util0这一组。实在定位不出来时临时设export QT_DEBUG_PLUGINS1再启动日志会把缺失的.so全名打出来。5.3 macOS 上双击图标闪退命令行也没输出现象启动后窗口闪一下就消失终端里没有任何堆栈。原因macOS 新版本对 Qt 的窗口管理接口做了调整PyQt5 5.15.x 早期的某些构建与之不兼容表现为进程直接被杀连 Python 的异常处理都来不及触发。解决把 PyQt5 降到 5.14.0 试一次pip install pyqt55.14.0如果还不行改用 conda 渠道安装 PyQt5conda install pyqt5conda 的构建针对 macOS 做过适配。两条都不通时直接用免安装可执行文件别在源码层死磕。5.4 图片列表是空的或者点开显示一片白现象Ctrl U选了目录左侧文件列表里有文件名但主编辑区一片空白缩放也没反应。原因路径里带中文或空格或者图片本身是 CMYK 色彩空间、16 位深这类非标准格式。labelImg 走 Qt 的图像解码路径对非 RGB 8 位图的兼容性一般。解决先把图片目录改成纯英文路径试一次这一步能排掉大部分情况。如果路径没问题用脚本把图片统一转成 RGB 8 位再标PIL三行就能批量处理。别指望在原图上硬标标出来的坐标可能和训练时读到的尺寸对不上。5.5 换机器后标注全乱框还在但类别不对现象数据集从一台机器拷到另一台打开同一批图框的位置没错但类别名全变了或者干脆显示成数字。原因YOLO 格式只存类别 id类别名靠classes.txt的行序还原。两台机器的classes.txt行序不一致同一个 id 就指向了不同类别。这种错最阴因为文件本身没坏只有对回原图才能发现。解决把classes.txt和数据集绑定一起进版本库、一起拷、一起校验。校验脚本里加一条读classes.txt的行数和标注文件里出现的最大 id 做比对id 越界直接报错。从那以后我给任何数据集加的第一道闸就是这个。6. 装完怎么验证拿十张图走一遍闭环判断 labelImg 有没有真正装好不看界面能不能弹出而看标注产出能不能被下游读进去。我的做法是固定拿十张图跑一遍完整闭环全过了才算这台机器可用过不了就退回上一章排查。十张图覆盖的典型场景是五张正常单目标、两张多目标、一张小目标贴边、一张文件名带空格、一张分辨率特别大。这十张跑完环境层面能踩的坑基本都暴露了。具体步骤是新建一个干净的输出目录启动时用labelImg D:\dataset\images D:\dataset\predefined_classes.txt --autosave逐张画框、切图最后检查输出目录里的文件数量和命名是否与图片一一对应。数量对不上多半是某张图换格式前就保存了或者保存目录中途被改过。然后拿脚本把产出反读一遍这一步比肉眼检查可靠得多# verify_voc.py反读 Pascal VOC 标注确认坐标合法、类别非空 import glob import os import xml.etree.ElementTree as ET for xml_path in sorted(glob.glob(dataset/annotations/*.xml)): root ET.parse(xml_path).getroot() size root.find(size) w, h int(size.find(width).text), int(size.find(height).text) objects root.findall(object) assert objects, f{xml_path} 没有任何标注对象 for obj in objects: name obj.find(name).text assert name and name.strip(), f{xml_path} 存在空类别名 box obj.find(bndbox) x1, y1 int(box.find(xmin).text), int(box.find(ymin).text) x2, y2 int(box.find(xmax).text), int(box.find(ymax).text) # 坐标必须落在图内且左上小于右下否则下游训练会直接崩 assert 0 x1 x2 w and 0 y1 y2 h, f{xml_path} 坐标越界: {name} print(os.path.basename(xml_path), OK, f{w}x{h})ET.parse读 XML 树size节点拿到原图尺寸object节点逐个取类别名和四个坐标。三条断言分别卡三件事有没有标注、类别名空不空、坐标是否越界。最后一行打印文件名和尺寸滚一遍就知道哪张漏了。走 YOLO 格式时把这段换成读 txt、把归一化值乘回宽高再断言逻辑一样。检查项通过标准不通过时先看哪输出文件数等于图片数保存目录、格式切换时机类别名全部在classes.txt里预定义类别文件编码坐标范围在0~宽/高之间--keep-prev残留框类别 id小于classes.txt行数两台机器的行序是否一致大图尺寸与原图一致缩放后是否误存这套检查我一开始觉得麻烦直到有一次用--keep-prev标了两千多张视频帧训练时才发现有一批框整体偏了一个目标位置只能全部返工。从那以后我每次装完 labelImg都强制拿十张图走一遍「标注 → 反读 → 断言」的闭环机器换了、环境重装了、版本升级了一个都不省略。希望帮到你。本文还有配套的精品资源点击获取