简介:这是一款适配历史环境与旧版依赖的LabelImg可运行版本,面向需要在目标检测、图像识别预处理中完成矩形框或多边形标注的算法工程师、科研人员及入门学习者。相比新版,该版本更轻量且兼容性稳定,适合遇到新版依赖冲突或特定版本要求的场景。压缩包共含75个文件,大小约977KB,以Python脚本(py/pyc)为主,配以Qt界面所需的png/svg图标、启动脚本sh及配置文件txt/md等,解压后即可按流程配置运行。目前已有4714人学习下载,可见其作为历史版本仍被不少开发者选用。资源内包含Qt界面交互、画布标注、标签管理及Pascal VOC/YOLO格式读写等核心模块源码,以及预定义类别文件、示例图片和跨平台构建脚本,既能直接用于图像标注,也便于二次开发或移植改造,能帮助读者快速搭建标注环境并理解工具底层实现。此外,目录中还保留了构建工具与环境配置脚本,方便在Windows、macOS或Linux上自行编译调整。
1. 可运行版LabelImg到底卡在哪:环境比标注本身更费劲
搜索"LabelImg可运行版本 下载"的人,多半不是不会标注,而是被黑匣子一样的启动报错挡在门外。LabelImg是最常用的图像标注工具之一,但直接从源码跑经常翻车:双击无反应、报"No module named 'libs.resources'"、Qt平台插件加载失败。问题根源往往不在工具本身,而在Python与PyQt5的版本组合,以及一个没有编译出来的资源文件。
这篇笔记把"可运行版本"拆成三件事:选对Python和PyQt5组合、把资源文件编译出来、避开五个高频启动坑。新手按"conda建环境 + 获取源码 + 编译资源"三步走,一小时内能跑通;熟手可以直接看第4章避坑清单和第5章自检脚本。读完你会有一个真正能开窗口、能存XML、能接进YOLO训练流程的LabelImg。
多说一句:并不存在官方发布的"可运行版"压缩包,所谓可运行版本就是一套满足条件的本地环境。与其到处找包,不如把环境一次搭对,以后换机器照着重演即可。
2. 把运行骨架说透:LabelImg为什么挑环境
2.1 三个零件:Python入口、PyQt5界面、资源文件
LabelImg的本质是一个Python程序,入口是labelImg.py。它调用libs目录下的模块完成读图、画框、写XML这些核心操作;界面渲染由PyQt5提供;resources.qrc这个Qt资源清单则把图标、字体、翻译文件打包进程序。三部分缺了任何一个,程序都起不来。
很多人试过网上流传的"免安装版"或旧预编译包,双击没反应,原因大多是这些包基于很多年前的Qt4构建,现代系统上早就没有对应运行库了。而源码包跑不起来,九成卡在resources_rc.py这个文件上。它本应由resources.qrc编译生成,但源码仓库不会常驻这个生成物,需要你手动用pyrcc5做一次编译。
libs目录里真正干活的是canvas.py和shape.py:canvas负责把鼠标事件转成画布坐标,shape管理矩形框的数据结构。理解它们不是必须的,但知道这些核心模块都在libs下,就能明白为什么源码包必须保持目录完整——只把labelImg.py单独拷出来跑,一定会失败。同理,编译资源文件时路径不对,界面照样不完整。
所以"可运行版本"的定义很具体:Python解释器能import PyQt5、resources_rc.py已经存在于libs目录、lxml等依赖已经装齐。三个条件同时满足,窗口必然出现;任何一个不满足,就会看到各种表面上毫无关联的报错。搞懂这个框架,排查就有方向了,不会被一条Traceback带着乱转。
2.2 Python与PyQt5的兼容矩阵:先把版本锁死
我一般会建议用Python 3.8或3.9配PyQt5 5.15.x,这是社区里验证过的最稳组合。
| Python版本 | PyQt5版本 | 实际表现 |
|---|---|---|
| 3.7 / 3.8 | 5.15.2~5.15.9 | 最稳,推荐 |
| 3.9 | 5.15.x | 推荐 |
| 3.10 | 5.15.x | 可用,个别平台有插件warning |
| 3.11+ | 5.15.x | 部分环境图标缺失、菜单异常 |
为什么PyQt5版本这么敏感?因为LabelImg源码用的是PyQt5时代的Qt API,放到PyQt6上直接AttributeError;而太老的PyQt5(比如5.9)在Python 3.8上又没有对应wheel包。5.15系列是两者的交集,兼容性验证最充分,因此是性价比最高的选择。这不是拍脑袋定的,是被反复验证过的共识。
判断当前环境到底装了哪个版本,有现成命令:python -c "from PyQt5.QtCore import QT_VERSION_STR; print(QT_VERSION_STR)",输出5.15.x就说明PyQt5与内部Qt运行库一致。如果输出了6.x,说明import顺序被另一个环境截胡了,先检查which python。
这里有个常被忽略的点:PyQt5和它的运行库包(PyQt5-Qt5)版本必须一致。用pip安装pyqt5时会自动带上匹配的运行库,但如果机器上之前装过别的Qt组件,或者conda环境里混入了系统Qt,两个不同版本的Qt库叠在一起,就会出现"Python层面import成功、C++层面插件加载失败"的玄学问题。第4章的第二个坑就是这种现场。
2.3 三条安装路线:pip直装、conda隔离、预编译包怎么选
常见做法有三条,按适用场景选。pip直装最快,一条命令完成,适合临时标注一批图片、用完就走的场景;缺点是依赖直接灌进当前环境,如果这台机器还跑着TensorFlow、OpenCV之类的重型库,Qt插件冲突只是时间问题。conda隔离是我最推荐的方式,独立环境里Python版本和PyQt5都锁死,翻车了删掉环境重建,等于有后悔药。预编译包不推荐,除非你确认它是近期为你的操作系统构建的,否则大概率是Qt4时代遗物,省下的十分钟会在后面加倍还回来。
conda还解决了一个pip解决不了的问题:Python版本锁定。pip只能安装当前解释器能用的包,如果系统默认Python是3.11,你想给LabelImg配3.8还得先折腾多版本管理;conda直接一个命令建出3.8环境,干净利落。这也是后面所有步骤都建立在conda上的原因。
离线环境怎么办?常见做法是:在一台能联网的机器上执行pip download pyqt5==5.15.7 lxml -d wheelhouse,把wheel文件拷贝到目标机器,再执行pip install --no-index --find-links=wheelhouse pyqt5==5.15.7 lxml。这样版本完全可控,不受目标机器网络状况影响。
另一个值得强调的教训:别在系统预装Python里直接跑labelImg.py,尤其是系统包管理器严格管控Python的发行版。直接在系统环境pip安装PyQt5,极可能把被其他软件依赖的库搞坏。标注工具不重,但它脆,给一个独立环境是成本最低的保护。
3. 用conda在本地跑通LabelImg:从零到窗口出现的完整命令
3.1 创建隔离环境:Python 3.8与PyQt5 5.15的最稳组合
conda create -n labelimg python=3.8 -y conda activate labelimg python --versionconda create的-n参数指定环境名为labelimg,python=3.8锁定解释器大版本,-y跳过安装确认。activate之后,后续所有pip和python命令都只作用于这个环境。python --version应该输出3.8.x,这一步确认切换真的生效,避免后面包装进别的环境。
建好的环境默认放在conda安装目录下的envs/labelimg,执行conda env list可以看到所有环境,里面出现labelimg就说明创建成功。Windows用户注意:conda activate在原生cmd里可能提示需要先conda init,按提示执行后重开终端即可;macOS和Linux的shell默认支持activate,基本碰不到这个问题。
我习惯把环境名取成labelimg而不是test或env这类通用名字,因为几个月后再执行conda env list,一眼就知道这个环境是干什么用的。
3.2 安装依赖并获取源码:两条命令解决九成启动问题
pip install pyqt5==5.15.7 lxml mkdir -p ~/tools && cd ~/tools git clone <LabelImg维护仓库地址> # 或从该仓库的Release页面下载源码zip,解压到当前目录 cd labelImgpip install固定版本号是为了让环境可复现。pyqt5==5.15.7锁定界面库版本,lxml是标注结果写XML时的解析后端,必须一起装。获取源码时,优先选还在维护的仓库:一些老fork长期不更新,setup.py可能还是Python 2时代的写法,在Python 3.8上根本装不上。
安装完成后执行pip list,确认能看到pyqt5、PyQt5-Qt5、lxml三项,版本分别对应5.15.7、5.15.x和较新的lxml。这个确认动作不是形式主义,排错时第一个问题永远是"你环境里装了什么版本",先确认再启动能省十几分钟。
如果机器上没有git,或者git clone频繁失败,直接在源码托管页面的Release列表下载最新的zip包。注意选和克隆相同的版本节点,太新的开发分支可能有额外的系统依赖要求。zip解压后的目录名通常带后缀,进入目录时注意别多进一层导致路径错误。
3.3 编译资源文件并首次启动:pyrcc5是窗口出现的最后一公里
cd labelImg pyrcc5 -o libs/resources_rc.py resources.qrc python labelImg.pypyrcc5是PyQt5自带的Qt资源编译器,读取resources.qrc这个XML格式的资源清单,输出Python模块resources_rc.py。程序运行时执行的import libs.resources,实际就是在找这个文件。资源文件缺失是源码版标注工具最常见的问题,跳过编译直接启动,一定会被第4章第一个坑拦住。
注意:pyrcc5必须在labelImg根目录下执行,否则-o参数里的相对路径libs/resources_rc.py会指向错误位置,编译出来的文件没进libs目录,启动照样报错。
如果提示找不到pyrcc5命令,说明当前环境的Scripts目录没进PATH,改用模块方式调用:
python -m PyQt5.pyrcc_main -o libs/resources_rc.py resources.qrc python labelImg.py启动成功的标志很直观:屏幕上出现带工具栏的主窗口,顶部有Open、Open Dir、Change Save Dir按钮,左侧是画布,右侧能选标注类别。看到这个窗口,环境搭建部分就算彻底完成了。之后所有标注操作都是点鼠标的事,不会再被环境问题打断。
启动失败时看什么?最有效的信号是终端最后几行:ModuleNotFoundError说明某个Python包缺失或路径错误;Segmentation fault说明Qt库层面冲突,基本是环境混装;qt.qpa.plugin说明插件路径问题。第4章会把最常见的几种对号入座。
4. LabelImg避坑与排查:5个让标注工具罢工的典型现场
环境按上面搭好后,绝大多数问题都出在细节上。下面五类问题是我实际遇到和帮同事排查最多的,按出现频率排序,每条按现象、原因、解决的顺序写,可以照着对号入座。
4.1 启动即报No module named 'libs.resources'
现象:在labelImg目录执行python labelImg.py,立刻出现Traceback,最后一行是ModuleNotFoundError: No module named 'libs.resources',窗口没有出现的机会。
原因:libs/resources_rc.py这个资源模块不存在。它由pyrcc5编译资源清单后生成,源码仓库一般不带,必须现场编译。
解决:在labelImg根目录执行pyrcc5 -o libs/resources_rc.py resources.qrc;如果提示找不到命令,就换成python -m PyQt5.pyrcc_main -o libs/resources_rc.py resources.qrc。编译完再启动。
这个报错是源码版最常见的一道坎,遇到它不是环境坏了,只是一个文件没生成。对照第3章的步骤补上编译即可。还有一种变体是工具栏图标全部缺失,按钮变成了空白,原因同样是资源文件没编译或编译路径不对。
4.2 Qt平台插件加载失败:窗口弹不出来的玄学现场
现象:Linux上启动报Could not load the Qt platform plugin "xcb",Windows上报plugin "windows" load failed,程序要么闪退要么白屏卡住。
原因:环境里存在多份Qt运行库,常见来源包括系统自带Qt、pip装的PyQt5-Qt5、conda的qt包。PyQt5加载平台插件时找到了错误版本,于是C++层面加载失败,但Python层面import又是成功的,这种割裂感特别迷惑人。
解决:先确认环境干净。conda activate labelimg后执行pip list,看有没有PyQt5相关包重复;有就在这个环境里卸载多余项,只保留PyQt5和PyQt5-Qt5。仍然不行就把环境删掉重建,全新环境只装pip install pyqt5==5.15.7 lxml,不再引入其他Qt来源。
提示:执行QT_QPA_PLATFORM=offscreen python labelImg.py可以快速区分是插件版本问题还是显示环境问题。上下换成offscreen后不再报插件错误,说明程序本身是好的,问题出在平台插件加载路径;但offscreen模式没有可见窗口,只能用来验证,不能用来正式标注。
4.3 中文路径:标注完保存XML时翻车
现象:图片放在"数据集"这类中文目录中,画框、选类别都正常,点Save或Save As时报UnicodeEncodeError,或生成的XML文件下次Load直接打不开。
原因:LabelImg读写文件时直接拼接文件系统路径,没有做显式的编码转换,依赖系统locale。Windows中文区域设置下偶尔能跑,Linux英文locale下中文路径基本必炸。
解决:把整个工作目录挪到纯ASCII路径下,例如~/data/labelimg_workspace;图片文件名也不要带中文和空格。这是成本最低的解法,不建议去改源码,改了下次升级同样的问题还在。
4.4 快捷键失灵、画框画不出:输入法和图片体积的双重因素
现象:窗口正常打开,图片也显示出来了,但按住鼠标拖不出矩形框,W/D/A/S这四个移动快捷键也没反应。
原因:中文输入法处于激活状态时,字母键被输入法截获,Qt窗口收不到KeyPress事件,快捷键自然失效。另一个常见因素是图片超大,超过5000像素的大图在加载时会阻塞主线程,画框前卡住几秒甚至几十秒。
解决:标注前把输入法切成英文模式或直接关闭;超大图先压缩或裁剪再标注,坐标换算回原图再做。这两件事都不起眼,但合在一起是日常标注效率最大的两个杀手。
4.5 多Python环境串台:报错路径指向另一个环境
现象:已经conda activate labelimg,执行python labelImg.py仍然报错,而且报错里的路径指向系统Python或者另一个conda环境。
原因:shell的PATH里conda环境没有排在最前面,activate没真正生效;或者之前设置过PYTHONPATH且没清理,Python会优先读它。
解决:先执行which python看解释器路径,再执行python -c "import sys; print(sys.prefix)"确认环境前缀是labelimg。不是的话,用conda deactivate后再重新activate;有PYTHONPATH残留就unset PYTHONPATH,然后重启。
5. 从跑通到干活:自检脚本与两个让标注效率翻倍的进阶
5.1 三分钟自检脚本:环境、资源、依赖一次查清
每次搭完环境都从头试错很浪费时间。我习惯把检查写成一个脚本,放在labelImg目录旁边,每次启动前跑一遍:
cd labelImg python - <<'EOF' import os, sys try: from PyQt5.QtCore import QT_VERSION_STR except ImportError: raise SystemExit('PyQt5 missing, run: pip install pyqt5==5.15.7') try: import lxml except ImportError: raise SystemExit('lxml missing, run: pip install lxml') if not os.path.exists('libs/resources_rc.py'): raise SystemExit('resources_rc.py missing, run: pyrcc5 -o libs/resources_rc.py resources.qrc') print('Python:', sys.version.split()[0]) print('Qt:', QT_VERSION_STR) print('all checks passed, window should open') EOF python labelImg.py这段脚本在启动前把三个必要条件都验证一遍:PyQt5能import、lxml已安装、资源文件已编译。任何一项缺失都直接告诉你缺什么、补哪个命令,不用对着完整Traceback猜。把"可运行"从感觉变成可验证,这就是最小成本。
5.2 把标注结果接进训练流程:VOC XML批量转YOLO txt
LabelImg默认输出Pascal VOC格式的XML,而YOLO系列训练要的是每张图一个txt。批量转换脚本我一直在用:
import os import xml.etree.ElementTree as ET classes = ['person', 'car', 'bike'] # 顺序必须与训练配置一致 def convert(xml_path, out_dir): root = ET.parse(xml_path).getroot() w = int(root.find('size/width').text) h = int(root.find('size/height').text) lines = [] for obj in root.findall('object'): name = obj.find('name').text if name not in classes: continue b = obj.find('bndbox') x1, y1 = float(b.find('xmin').text), float(b.find('ymin').text) x2, y2 = float(b.find('xmax').text), float(b.find('ymax').text) cx, cy = (x1 + x2) / 2 / w, (y1 + y2) / 2 / h bw, bh = (x2 - x1) / w, (y2 - y1) / h lines.append(f"{classes.index(name)} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") base = os.path.splitext(os.path.basename(xml_path))[0] open(os.path.join(out_dir, base + '.txt'), 'w').write('\n'.join(lines)) os.makedirs('yolo_labels', exist_ok=True) for f in os.listdir('Annotations'): if f.endswith('.xml'): convert(os.path.join('Annotations', f), 'yolo_labels')转换逻辑是把xmin/xmax/ymin/ymax的绝对坐标,换算成中心点加宽高的相对坐标,类别名替换成索引。classes列表的顺序必须和训练时的类别配置完全一致,否则会出现"框标对了、类别却是错的"这类隐蔽问题,到训练阶段才暴露。
5.3 改两个配置,标注效率立刻不一样
第一个是data/predefined_classes.txt,每行一个类别名。打开新图时右侧类别下拉框直接列出全部预设,省去每次手打。初始内容一般是示例类别,换成你项目实际用的即可。第二个是启动后先用Change Save Dir指定输出目录,否则每次保存都会弹路径选择框。
还有一个常被忽略的习惯:标注过程中定期按Ctrl+S。LabelImg写XML是直接覆盖文件,程序一旦崩溃,未保存的框会全部丢失。我的血泪经验是先配Save Dir再开图,标一张存一张,大项目再加一层增量备份。
环境这个问题,本质上就是一次性成本。我最早直接在系统Python里装PyQt5,和项目里的其他依赖打架,整整调试了一下午窗口都出不来,最后全部推倒用conda单独建环境,十分钟就通了。LabelImg本身不复杂,复杂的是环境;把环境隔离做好,剩下都是点鼠标的活。希望帮到你。
本文还有配套的精品资源,点击获取