
1. 为什么在 Ubuntu 18.04 上还要折腾 roLabelImg如果你做过目标检测相关的标注工作大概率绕不开 LabelImg 这个工具。它足够简单、足够直接画框、打标签、导出 XML一套流程下来很顺手。但问题也很明显它只能画水平矩形框遇到航拍图像、遥感影像、文档版面分析、工业质检里的倾斜目标就彻底没辙了。你只能眼睁睁看着一个斜着的飞机、一个旋转的零件、一段倾斜的文字被迫用一个巨大的水平框把它包进去框里塞满了背景噪声模型训练出来效果自然好不到哪去。roLabelImg 就是冲着这个痛点来的。它在 LabelImg 的基础上做了扩展支持**旋转矩形框Oriented Bounding Box简称 OBB**的标注可以画出带角度信息的框导出格式也兼容常见的旋转目标检测训练框架。我第一次接触它是在处理一批遥感图像的时候图像里的船只、飞机、储油罐全是任意方向的用水平框标注简直是灾难。换成 roLabelImg 之后标注效率和质量都上了一个台阶。这篇文章面向的是需要在 Ubuntu 18.04 环境下使用 roLabelImg 做旋转框标注的从业者不管你是刚入门的新手还是已经用过 LabelImg 想迁移过来的老手都能从中找到可以直接复现的步骤和踩坑经验。我会从环境准备讲起一直讲到实际标注操作、格式解析、常见问题排查把整个流程拆开揉碎说清楚。提示Ubuntu 18.04 虽然已经不是最新版本但在很多工业现场和实验室环境里仍然是主力系统Python 版本、Qt 库版本、依赖包版本都有其特殊性这也是为什么单独拿出来讲的原因。2. 环境准备与依赖安装的完整思路2.1 为什么 Ubuntu 18.04 的环境需要特别对待Ubuntu 18.04 默认自带的是 Python 3.6系统级的 Qt 库版本也比较老。roLabelImg 基于 PyQt5 开发而 PyQt5 在不同版本之间 API 差异不小尤其是和 Python 3.6 搭配的时候稍不注意就会遇到版本冲突。我在第一次安装的时候就因为 pip 直接拉取了最新版 PyQt5结果运行时报了一堆sip相关的错误折腾了大半天才定位到是版本不匹配的问题。所以核心思路是不要盲目追求最新版本而是选择与 Python 3.6 兼容的稳定版本组合。这是整个安装过程中最重要的一条原则。2.2 系统级依赖的安装在开始装 Python 包之前先把系统层面的依赖补齐。roLabelImg 运行需要 Qt 的图形界面支持如果你的 Ubuntu 是最小化安装的可能缺少一些基础库。sudo apt update sudo apt install -y python3-pip python3-pyqt5 python3-pyqt5.qtsvg \ python3-dev libxml2-dev libxslt1-dev python3-lxml \ libqt5gui5 libqt5core5a libqt5widgets5这里解释一下几个关键包的作用。python3-pyqt5是 Qt5 的 Python 绑定roLabelImg 的整个界面都靠它python3-lxml用于解析和生成 XML 标注文件LabelImg 系列的标注格式都是 Pascal VOC 风格的 XMLlxml 处理起来比标准库的 ElementTree 更高效libxml2-dev和libxslt1-dev是 lxml 编译时需要的头文件如果你用 pip 安装 lxml 而不是 apt 安装这两个就必不可少。注意如果你打算用 apt 安装 python3-pyqt5那 pip 里就不要再装 PyQt5 了两者会冲突。我建议统一用 apt 管理 Qt 相关的包pip 只用来装 roLabelImg 本身和纯 Python 的依赖。2.3 roLabelImg 的获取与安装roLabelImg 的源码托管在代码仓库上直接克隆下来即可。这里不指定具体地址你可以在常用的代码托管平台上搜索项目名找到它。cd ~ git clone roLabelImg仓库地址 cd roLabelImg克隆下来之后先别急着运行。看一下目录结构通常会有labelImg.py作为主入口libs/目录下放着核心逻辑resources.py是 Qt 资源文件。有些版本还需要先把.ui文件编译成.py不过大多数维护良好的版本已经帮你编译好了。安装 Python 依赖的时候我建议用虚拟环境隔离避免污染系统 Python。但 Ubuntu 18.04 的 python3-venv 有时候不太好使如果你嫌麻烦直接在当前用户下用pip3 install --user也可以。pip3 install --user pyqt55.10.1 lxmlPyQt5 的版本我特意锁在 5.10.1这是经过实测在 Python 3.6 上比较稳定的一个版本。如果你装的是 5.15 以上的版本很可能会遇到QtCore.Qt枚举访问方式变化导致的报错因为新版本把很多枚举改成了 scoped enum老代码里直接写Qt.AlignCenter这种用法就会失效。2.4 验证安装是否成功装完之后进入 roLabelImg 目录直接运行python3 labelImg.py如果界面正常弹出来说明环境没问题。如果报错大概率是以下几类ModuleNotFoundError: No module named PyQt5说明 PyQt5 没装好或者装到了错误的 Python 环境下ImportError: cannot import name uic说明 PyQt5 的工具模块缺失需要额外安装pyqt5-toolssymbol lookup error这种一般是系统 Qt 库和 pip 装的 PyQt5 冲突了需要卸载 pip 版本改用 apt 版本。3. 旋转框标注的核心操作与界面解析3.1 界面布局与基本操作逻辑roLabelImg 的界面和原版 LabelImg 非常相似左侧是文件列表中间是图像显示区右侧是标签和标注列表顶部是工具栏。区别在于工具栏上多了几个和旋转相关的按钮标注列表里每个框也会多出角度信息。打开一张图像之后默认的绘制模式还是水平矩形框。要切换到旋转框模式需要点击工具栏上的旋转框按钮或者用快捷键。不同版本的快捷键可能不一样常见的是CtrlR或者R。我建议你先在设置里确认一下当前版本的快捷键映射因为有些 fork 版本改过键位。绘制旋转框的操作方式和水平框类似在目标的一个角点按下鼠标左键拖到对角位置松开就生成了一个初始的旋转矩形。生成之后框的四个角上会出现控制点你可以拖动控制点调整大小也可以拖动框中间的旋转手柄来调整角度。3.2 旋转框的角度定义与坐标系这是整个工具里最容易让人困惑的地方必须重点讲清楚。roLabelImg 导出的旋转框通常用中心点坐标、宽、高、角度这五个参数来表示也就是常说的(cx, cy, w, h, angle)。但角度的定义方式在不同版本、不同训练框架里是不一样的。常见的有两种约定一种是角度表示矩形长边与水平轴的夹角范围是[-90, 0)或者[0, 90)另一种是用弧度表示范围是[-π/2, 0)。roLabelImg 默认导出的 XML 里角度通常以角度制存储但有些版本会存弧度这个一定要在标注前确认清楚否则训练时角度全错模型根本学不到东西。我踩过的坑是这样的标注了几百张图之后才发现导出的角度是弧度制而训练代码里按角度制解析结果所有框的旋转都是乱的。后来我在标注前先拿一张图测试画一个明显倾斜的框导出 XML 看一眼数值确认角度单位之后再批量标注。这个习惯救了我很多次。提示判断角度单位有个简单方法画一个大约 45 度的框如果导出值是 0.78 左右就是弧度如果是 45 左右就是角度。3.3 标注过程中的实用技巧标注旋转框比水平框费时得多因为你要同时控制位置、大小和角度。我总结了几条能显著提速的经验。第一先画水平框再旋转。不要一上来就试图直接拖出带角度的框那样很难控制。先把目标用水平框大致框住然后再旋转到贴合目标的方向最后微调四个角点。这样操作步骤虽然多一步但精度和速度都更好。第二善用键盘微调。很多版本支持用方向键微调框的位置用Shift方向键微调角度。对于只需要小幅调整的情况键盘比鼠标精确得多。第三角度归一化要统一。对于同一个类别的目标尽量保持角度定义的一致性。比如船头朝向你可以约定所有框的角度都表示长边方向避免同一个目标一会儿用长边一会儿用短边导致角度值跳变。第四标注顺序有讲究。我习惯按类别分批标注先把所有 A 类目标标完再标 B 类。这样切换标签的次数少思路也更连贯。4. 标注文件格式解析与格式转换4.1 XML 标注文件的结构roLabelImg 导出的标注文件是 XML 格式整体结构继承自 Pascal VOC但在每个object节点里增加了旋转相关的字段。一个典型的标注文件长这样annotation folderimages/folder filenamedemo_001.jpg/filename size width1024/width height768/height depth3/depth /size object nameship/name poseUnspecified/pose truncated0/truncated difficult0/difficult robndbox cx512.0/cx cy384.0/cy w120.0/w h40.0/h angle0.785/angle /robndbox /object /annotation关键就在robndbox这个节点它替代了普通 LabelImg 里的bndbox。cx和cy是中心点坐标w和h是宽高angle是旋转角度。注意这里的angle是弧度值0.785 约等于 45 度。4.2 角度单位与坐标系的坑前面提到角度单位的问题这里再深入说一下。不同版本的 roLabelImg 对angle的定义可能有差异有的用弧度有的用角度有的以水平轴为基准逆时针为正有的顺时针为正。你在拿到标注文件之后第一件事应该是写个小脚本把几个框画出来可视化一下确认解析方式和你的训练代码一致。我常用的验证方法是用 OpenCV 把旋转框画到原图上import cv2 import numpy as np import xml.etree.ElementTree as ET def draw_robndbox(img, cx, cy, w, h, angle): rect ((cx, cy), (w, h), np.degrees(angle)) box cv2.boxPoints(rect) box np.int0(box) cv2.drawContours(img, [box], 0, (0, 0, 255), 2) img cv2.imread(demo_001.jpg) tree ET.parse(demo_001.xml) root tree.getroot() for obj in root.findall(object): rbox obj.find(robndbox) cx float(rbox.find(cx).text) cy float(rbox.find(cy).text) w float(rbox.find(w).text) h float(rbox.find(h).text) angle float(rbox.find(angle).text) draw_robndbox(img, cx, cy, w, h, angle) cv2.imwrite(vis.jpg, img)如果画出来的框和目标贴合说明解析正确如果框歪了或者方向反了就要检查角度单位和正负方向。这个验证步骤花不了几分钟但能避免后面大量的返工。4.3 转换到常见训练框架格式标注完成之后通常需要把 XML 转换成训练框架能直接读取的格式。不同框架要求不一样这里说几个常见的。DOTA 数据集格式用的是(x1, y1, x2, y2, x3, y3, x4, y4, category, difficult)这样的八点坐标加类别。从 roLabelImg 的 XML 转过去需要把中心点宽高角度转换成四个角点坐标。转换逻辑是先用角度算出旋转矩阵再把矩形的四个角旋转过去。import math def robndbox_to_polygon(cx, cy, w, h, angle): dx w / 2.0 dy h / 2.0 cos_a math.cos(angle) sin_a math.sin(angle) points [] for sx, sy in [(-dx, -dy), (dx, -dy), (dx, dy), (-dx, dy)]: px cx sx * cos_a - sy * sin_a py cy sx * sin_a sy * cos_a points.extend([px, py]) return pointsCOCO 格式本身不直接支持旋转框但有些扩展版本会用[cx, cy, w, h, angle]的形式存在bbox字段里。如果你的训练框架用的是这种格式转换就简单多了直接读取即可。注意转换的时候要特别小心坐标系的 y 轴方向。图像坐标系里 y 轴向下而数学坐标系里 y 轴向上角度正方向的定义会因此不同。转换前一定要确认清楚否则框会上下翻转。5. 常见问题排查与避坑经验实录5.1 启动与运行类问题问题一运行时报qt.qpa.plugin: Could not load the Qt platform plugin xcb。这是 Ubuntu 上跑 Qt 程序最经典的错误。原因通常是 Qt 找不到平台插件或者插件依赖的库缺失。解决方法先试export QT_DEBUG_PLUGINS1然后重新运行看详细报错。常见的是缺libxcb-xinerama0装一下就好sudo apt install -y libxcb-xinerama0如果还不行检查一下是不是 pip 装的 PyQt5 和系统 Qt 冲突了卸载 pip 版本改用 apt 版本通常能解决。问题二界面能打开但显示乱码或者字体极小。这是 Qt 在高分屏或者缺少中文字体时的表现。装一下中文字体然后设置 Qt 的缩放sudo apt install -y fonts-wqy-zenhei export QT_AUTO_SCREEN_SCALE_FACTOR15.2 标注操作类问题问题三旋转框拖不动或者角度跳变。这种情况多半是鼠标灵敏度或者版本 bug。先试试用键盘微调如果键盘正常说明是鼠标事件处理的问题。有些版本在图像缩放比例不是 100% 的时候坐标换算会有偏差建议标注时把缩放调到 100%。问题四保存的 XML 里角度值全是 0。检查一下是不是在水平框模式下标注的。只有用旋转框工具画的框才会带角度信息水平框转成 robndbox 时角度默认是 0。另外确认一下保存格式设置有些版本需要在设置里手动勾选“保存旋转框信息”。5.3 数据一致性类问题问题五多人协作标注时角度定义不统一。这是团队标注里最头疼的问题。解决办法是提前制定标注规范明确角度的基准方向和正负号并且用几张典型图做示例。标注前先让每个人标同一张图对比结果确认一致之后再批量开工。问题六标注文件里的类别名拼写不一致。比如一会儿写ship一会儿写Ship训练时会被当成两个类别。建议在 roLabelImg 的预定义类别文件里把类别名固定好标注时只从下拉列表选不要手动输入。5.4 常见问题速查表问题现象可能原因解决方法启动报 xcb 插件错误缺 libxcb 依赖安装 libxcb-xinerama0界面乱码缺中文字体安装 fonts-wqy-zenhei角度值全为 0用了水平框模式切换到旋转框工具重新标注框位置偏移图像缩放非 100%调整缩放比例后重新标注类别重复手动输入拼写不一致使用预定义类别列表保存后文件为空权限问题或路径含中文检查目录权限避免中文路径6. 提升标注效率的进阶技巧6.1 预标注与半自动流程纯手工标注旋转框效率很低尤其是目标密集的图像。一个可行的优化思路是先用已有的水平框检测模型做一遍预标注把结果转成旋转框格式导入 roLabelImg人工只需要微调角度和位置。虽然预标注的框不一定准但至少省去了从零画框的时间。具体做法是用水平框模型推理得到(xmin, ymin, xmax, ymax)然后转换成(cx, cy, w, h, 0)的旋转框格式写成 roLabelImg 能读取的 XML。导入之后标注人员只需要旋转和微调效率能提升不少。6.2 快捷键自定义与批量操作roLabelImg 支持自定义快捷键把常用的操作映射到顺手的位置能明显提速。我通常会把“下一张图”“保存”“复制上一个框”这几个操作设成单键减少手在鼠标和键盘之间切换的频率。另外对于尺寸和角度都相近的目标可以用“复制框”功能。先标好一个复制之后平移到下一个目标位置再微调角度。这在标注排列整齐的目标比如停车场里的车、货架上的商品时特别有用。6.3 标注质量的抽检方法标注完成之后一定要抽检不能直接拿去训练。抽检的方法是随机选一批图把标注框可视化出来肉眼检查是否贴合。我一般会抽 5% 到 10% 的样本重点看边界情况特别小的目标、特别密集的区域、角度接近 90 度的目标。这些地方最容易出错。如果发现系统性偏差比如所有框都偏右几个像素那可能是标注工具的坐标换算有问题需要整体修正而不是逐个改。7. 我在实际项目中的几点体会用 roLabelImg 做旋转框标注工具本身不算复杂真正花时间的是标注规范的制定和质量控制。我经历过最惨的一次是标了三千多张图之后发现角度定义和训练代码不一致只能全部返工。从那以后我养成了一个习惯任何标注任务开始之前先标十张图走一遍完整的训练流程确认数据格式、角度定义、类别映射全部对齐之后再大规模铺开。另一个体会是旋转框标注对标注人员的要求比水平框高不少。水平框只要框住目标就行旋转框还要考虑角度是否合理、长宽是否对应目标的主轴方向。培训标注人员的时候一定要把角度规范讲透最好准备一份带正反例的文档让大家对“什么算标得好”有统一的认知。最后说一个工具层面的小技巧roLabelImg 的某些版本在打开大图比如 4000x3000 以上时会比较卡标注体验很差。如果遇到这种情况可以先把图像切分成小块分别标注最后再合并标注文件。虽然多了一步但操作流畅度会好很多。