尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
roLabelImg源码解析:旋转框标注工具从安装到二次开发
简介roLabelImg是一款支持旋转矩形框标注的开源图像标注工具源码主要面向目标检测研究者、计算机视觉学生及标注工具二次开发人员。源码基于Python/PyQt编写包含核心标注界面、Pascal VOC格式读写、画布缩放、标签管理与颜色设置等模块附带多张测试图片、示例XML文件及预定义类别清单能直观展示旋转框从鼠标绘制、类别选择到标签导出的完整处理链路。整个压缩包共94个文件以Python脚本、PNG与SVG图标资源、XML标注样例、shell构建脚本等为主整体大小16.44MB目录按libs、icons、build-tools、tests等模块组织便于按需定位核心代码、界面资源与构建配置。目前已有630人学习下载适合希望自研或改造旋转框标注工具、深入理解数据标注流程及界面交互实现的开发者亦可据此扩展自定义标注格式与快捷键操作。1. 旋转框标注为什么绕不开 roLabelImg先搞清楚它到底解决什么问题做遥感目标检测的人大概率都经历过这样的场景一副航拍图里停着几十辆车用水平矩形框去标一个框里常常塞进两辆车IoU 怎么算都别扭。换到车位、船舶、建筑物这类有明确朝向的目标水平框的回归损失会一直震荡模型学到的东西也打了折扣。roLabelImg 就是为这个场景而生的开源标注工具——它本质上是 LabelImg 的旋转框分支核心能力是让你在图上拖出一个带角度的矩形框并把角度写进标注文件里。标题里的“源码”两个字是重点。它意味着你不只是拿到一个能用的标注 GUI更可以读代码去改交互、改保存格式、接自己的数据管线。很多团队的检测流程里roLabelImg 往往是整个数据中台的上游入口标注质量直接决定后续旋转检测模型的收益上限。这篇实战笔记打算从源码机制讲到安装、标注、格式转换和排错让你从「听说过这个工具」一路走到「能自己改源码做定制」并看清它值不值得引入你的项目。2. 旋转框的数据结构与绘制原理源码里最核心的机制2.1 旋转矩形在源码里是怎么表示的roLabelImg 和 LabelImg 最大的区别在于它不再用(xmin, ymin, xmax, ymax)这种轴对齐四元组而是换成了带角度的表示方式。源码里常见的数据结构是一个五元组(cx, cy, w, h, angle)分别代表中心点 x、中心点 y、半宽、半高、旋转角。也有部分实现直接用四个顶点坐标构成四边形但在保存成 XML 时roLabelImg 通常会用robndbox标签其中记录了cx, cy, w, h, angle这五个值而w和h值得一提的是这里存的并不是半宽半高而是完整宽度和高度读取时要留意。这个表示方式对后续做数据增强非常友好——你可以直接用矩阵旋转公式对中心点和角度做变换而不是对四个顶点做透视变换。在训练端很多旋转检测模型比如带旋转分支的检测头接收的输入也是(x, y, w, h, angle)这种格式因此从标注到训练基本上可以无缝对接。2.2 绘制旋转框的鼠标交互逻辑在源码的坐标转换部分绘制交互通常遵循这样一个流程鼠标按下时记录起始点作为旋转框的中心鼠标拖动时计算当前点相对于中心点的偏移向量由此确定宽度、高度和角度鼠标释放后在画布上绘制出对应的旋转矩形。这个过程会在 mousePressEvent 和 mouseMoveEvent 里反复触发面板上顺便显示当前的角度值。这个交互设计比较反直觉的地方是一般画框是先定一个角再拖出对角roLabelImg 是先定中心再拉出长轴方向。第一次用的人往往会觉得「失控」。如果你后期要改源码我一般会建议把角度显示做到状态栏里并且把旋转步长做成可配置项例如按 R 键微调旋转 1 度ShiftR 旋转 10 度这样能显著降低标注的误操作率。# 伪代码根据两个鼠标点计算旋转框参数 import math def compute_rotated_rect(start_point, current_point): # start_point: 鼠标按下的起点作为矩形中心 # current_point: 当前鼠标位置决定长边方向和大小 dx current_point[0] - start_point[0] dy current_point[1] - start_point[1] length math.sqrt(dx * dx dy * dy) if length 1e-6: return None # 用长边的方向作为角度atan2 返回弧度转成角度存到标注里 angle math.degrees(math.atan2(dy, dx)) # 宽度初始化为固定值或者根据鼠标垂直偏移动态计算 height 20 return { cx: start_point[0], cy: start_point[1], w: length, h: height, angle: angle }这段伪代码对应了源码中computeRotatedRect一类函数的核心思想。逻辑说明宽度取的是起点到当前点的欧氏距离高度默认取一个固定值这样只要拖一次就能看到旋转框的效果。参数说明length是旋转框的长边angle的范围是 -180 到 180 度atan2 能自动判断象限避免出现正负 90 度边界上的跳跃。真实源码里通常还会考虑当前点相对起点的垂向偏移用偏移量来计算高度你可以按需调整。2.3 角度存弧度还是存角度一个必须统一的问题读 roLabelImg 源码时你会遇到一个很容易踩坑的分叉路口XML 里的angle字段到底存的是弧度还是角度。不同版本、不同二开分支的实现并不一致。一些较早的分支用弧度制另一些分支在保存前做了math.degrees()转换输出的是角度制。这个问题的坑在于模型训练脚本读 XML 时如果默认是角度制一旦遇到弧度制的标注文件角度值的范围从 -180~180 跳成 -3.14~3.14几何上会彻底乱掉。我的做法是拿到任何一份 roLabelImg 源码后先去savePascalXML或对应的save_txt函数里找angle的写入逻辑。如果是按弧度写入我就加一行转换保证全流程统一用角度制因为后续转训练格式时角度制最直观也不需要额外换算。3. 把 roLabelImg 源码跑起来环境配置与最小启动命令3.1 环境依赖的版本组合选择roLabelImg 是典型的 PyQt 项目依赖集中在PyQt5和lxml。从实操角度讲环境配置最省心的组合是 Python 3.6 到 3.8 配合 PyQt5 5.15 系列。Python 版本太高比如 3.10 以上某些旧分支的语法和 Qt 绑定会出现不兼容版本太低比如 Python 2.7虽然一些老版本源码支持但后续你可能需要自己动手改代码才能在 PyQt5 下跑通。另外lxml 的版本不需要刻意最新能解析 XML 就行。如果你在安装 PyQt5 时遇到 wheels 下载慢或者超时可以考虑用国内镜像源或者直接改用系统包管理器安装。实际踩坑经验里最省时间的做法是建一个干净的虚拟环境把 Python 版本锁在 3.8避免污染其他项目。# bash创建虚拟环境并安装核心依赖 conda create -n rol python3.8 -y conda activate rol pip install PyQt55.15.10 lxml4.9.3逻辑说明先创建独立环境再固定 PyQt5 和 lxml 的版本这样你在多台机器之间迁移时能保持行为一致。参数说明PyQt5 版本选择 5.15.10 而非更高的 5.15.11是因为这个版本在某类中文字体渲染上相对稳定lxml 4.9.3 是比较稳妥的解析版本不追新就不会遇到 API 变动导致的报错。3.2 启动 GUI 前必须做的一步直接运行会出错如果你以为装完依赖直接跑python main.py就能弹出界面那多半会在终端里看到一堆关于libpng warning或 Qt 平台插件的报错。这类问题的根因是 PyQt5 的插件加载路径没有找到常见于 Windows 环境有时候 Linux 下也会出现。解决方式有两种。常见做法是在启动脚本里手动设置QT_QPA_PLATFORM_PLUGIN_PATH指向 PyQt5 安装目录下的plugins/platforms。也可以把主程序封装成一个入口文件在 import 界面库之前先配置好环境变量。由于 roLabelImg 的源码通常不是以 package 方式组织的修改源码里入口位置的全局配置是最直接的路径。# python在入口文件最前面配置 Qt 插件路径 import os import sys if sys.platform.startswith(win): # 这里的路径要改成你环境里 PyQt5 实际的 plugins 目录 qt_plugins os.path.join(sys.prefix, Lib, site-packages, PyQt5, Qt5, plugins, platforms) os.environ[QT_QPA_PLATFORM_PLUGIN_PATH] qt_plugins from PyQt5.QtWidgets import QApplication from main_window import MainWindow逻辑说明这段代码是在 import 窗口类之前把 Qt 的 platform 插件路径写进环境变量避免 QApplication 初始化时找不到 windows 平台的 dll。参数说明sys.prefix指向当前虚拟环境的根目录这样换机器换环境都不用硬编码绝对路径如果你源码里启动窗口的入口是main.py直接把这几行加到文件头部即可。3.3 首次启动验证打开一张图和保存一份 XML 的检查项启动成功后不要急着开始标注先用一张分辨率为 1024x1024 左右的普通图片做一次「画框-保存-重新打开」的闭环测试。这一步能提前暴露保存路径问题、编码问题和 XML 结构问题避免你在批量标注到一百张时才后悔。我一般会在第一次保存后打开生成的 XML确认里面object节点下同时存在bndbox和robndbox。bndbox是轴对齐的包围盒相当于旋转框的外接矩形robndbox才是旋转框的精确定义。如果只有前者没有后者说明当前源码的保存逻辑可能有 bug或者是标注时用的还是普通的水平框工具需要回到界面操作层面去排查。4. 完整的旋转标注落地流程从打开图片到产出可训练数据集4.1 标注操作与快捷键的配合进入标注界面后推荐的完整操作是先用W键进入创建旋转框模式在目标中心按下鼠标左键沿着目标长轴方向拖动看到框的宽度和角度随鼠标变化后松开左键完成创建。接着按CtrlS保存该图的 XML然后按D键进入下一张。对于几百张图的批次任务鼠标加键盘的组合效率远比纯鼠标高。源码里快捷键通常定义在keyPressEvent里常见的还有A上一张、CtrlZ撤销上一个框、Del删除当前选中的框。如果你觉得旋转框的默认宽度不好控制可以在源码里把工具默认宽度改成 40 或 50 像素但更高效的办法是画完后再选中框用滚轮或预设的旋转键微调角度而不是反复重画。# bash用一个最小脚本把标注目录里所有 PNG 转成 JPG # 某些源码对图片格式识别不友好统一格式能减少中断 for img in ./images/*.png; do convert $img ${img%.png}.jpg done这段命令是把原始图片统一转成 JPEG因为 roLabelImg 某些版本的图片读取路径对格式依赖较强统一格式后批量标注时切图不会卡住。逻辑说明循环遍历 images 目录下所有 PNG用 ImageMagick 的 convert 命令输出同名 JPG。参数说明${img%.png}是 bash 的变量替换去掉后缀名保证转出来的文件名与原始文件名一致这样标注完的 XML 也能按原文件名关联上。4.2 XML 的字段定义和读取方式保存后的 XML 结构基本上继承了 Pascal VOC 的样式但object内部多了一个robndbox子节点。下面是典型的字段示意annotation folderimages/folder filename000001.jpg/filename size width1024/width height768/height depth3/depth /size object namevehicle/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin100/xmin ymin120/ymin xmax420/xmax ymax380/ymax /bndbox robndbox cx260/cx cy250/cy w320/w h200/h angle30/angle /robndbox /object /annotation读取的时候我建议直接把robndbox解析成五元组别去看bndbox因为在旋转目标检测里bndbox只用于兼容旧流程。逻辑说明cx、cy是旋转框中心在像素坐标系下的坐标w和h是旋转框的宽度与高度angle是长边与 x 轴正方向的夹角。参数说明角度单位以你的源码输出为准业界常见的做法是统一成角度制也就是 0~180 度正方向、0~-180 度负方向训练脚本里负责归一化到 -90~90 度。4.3 把旋转 XML 转成 YOLO 旋转格式的脚本转到训练阶段最常用的目标格式有两种一种是转成四点坐标的多边形格式另一种是转成cx cy w h angle的 YOLO 扩展格式。后一种需要做归一化宽度和高度要除以图片宽高角度保持不变。# python批量解析 XML 并转换成 YOLO 旋转格式 import os import math import xml.etree.ElementTree as ET def convert_xml_to_yolo(xml_path, out_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text rob obj.find(robndbox) cx float(rob.find(cx).text) / img_w cy float(rob.find(cy).text) / img_h w float(rob.find(w).text) / img_w h float(rob.find(h).text) / img_h angle float(rob.find(angle).text) # 统一角度制范围到 0~180 或 -90~90 angle math.radians(angle) lines.append(f{name} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f} {angle:.6f}) with open(out_path, w) as f: f.write(\n.join(lines)) # 用法示例读取 images/000001.xml生成 labels/000001.txt convert_xml_to_yolo(images/000001.xml, labels/000001.txt, 1024, 768)逻辑说明这段脚本的核心是找到每个 object 节点下的 robndbox将 cx、cy、w、h 分别除以图片宽高做归一化angle 从角度转弧度再按类别名和五个数值拼成一行文本。参数说明img_w和img_h必须和图片的实际尺寸一致如果你的数据集中图片尺寸不一致不要硬编码在转换前用图像库读一遍真实宽高。angle是否转弧度取决于你训练脚本的约定有些框架内部要求弧度制有些则直接吃角度制务必先确认再转换。4.4 数据校验把转换后的标注画回图上转换完的标注文件如果不画出来看你很难发现坐标系搞反、角度符号反了这类问题。常见做法是用 OpenCV 读取图片在图上绘制旋转矩形和 XML 里对应的目标做肉眼对比。这一步听起来繁琐但在第一次跑通流程时值得做因为后续你可能会用它作为自动检查脚本批量核对几百张图的转换质量。# python校验旋转框是否贴合目标 import cv2 import numpy as np def draw_rotated_box(image_path, cx, cy, w, h, angle): img cv2.imread(image_path) # 旋转矩形的四个顶点 rect ((cx, cy), (w, h), angle) box cv2.boxPoints(rect) box np.int0(box) cv2.drawContours(img, [box], 0, (0, 255, 0), 2) cv2.imshow(check, img) cv2.waitKey(0)逻辑说明OpenCV 推荐的boxPoints方式可以直接用中心点、宽高、角度来算四个顶点省去自己手写三角函数。参数说明angle在 OpenCV 里规定为顺时针旋转角度如果你的坐标体系是逆时针为正画出来就是反的这时要在传入前加一个正负号调整w和h用的是像素值也就是画回图上时的真实尺寸而不是归一化后的数值。5. roLabelImg 踩坑记录与排查手册标注到一半翻车时的自救方案5.1 启动后窗口一直黑屏或闪退现象安装完依赖运行主程序窗口能弹出来但界面是空的点哪都没反应偶尔几秒后直接闪退。原因大概率是 PyQt5 与 OpenCV 的 Qt 插件冲突或者源码里的图形资源路径没加载成功。尤其在同时安装了 opencv-python 的环境里OpenCV 自带的 Qt 插件会干扰 PyQt 的窗口初始化。解决先检查终端是否有cv2相关的 dll 报错如果有在启动脚本里把import cv2移到 PyQt 界面的 import 之后如果资源加载失败去源码里找到图标和样式表的相对路径改成基于当前文件绝对路径。按这两个方向调整后问题多半能解决。5.2 保存的 XML 里只有 bndbox没有 robndbox现象画完框也点了保存打开 XML 一看每个 object 下只有bndbox完全没有旋转角度信息。原因最常见的情况是你用的不是旋转框工具。检查一下界面左侧工具栏确认当前选中的是Create Rotated Rect而不是Create Rect。另一种可能你用的源码是旧分支保存逻辑里只写了bndbox。解决如果是工具选错切换工具重新画如果是源码问题找到savePascalXML函数把bndbox的写入逻辑后面补上robndbox节点数据从当前的旋转框对象里取。对前者我不推荐靠后处理去补角度因为角度一旦丢失重画的成本往往比修复源码更高。5.3 角度值读出来差 90 度或方向相反现象同一个目标标注时界面显示的角度是 30 度转换脚本读出来却是 120 度或者界面显示 30 度但图上画出来明显朝向相反。原因界面上显示的角度可能已经做了某种补偿而 XML 里保存的是原始计算值还有一种情况是坐标轴方向定义不同像素坐标系 y 轴向下旋转正方向是顺时针而数学坐标系逆时针为正两套体系混用时角度值就容易差 90 度。解决不要凭感觉猜在源码里加一行日志把鼠标拖动过程中的原始角度和保存时写入的角度同时打印出来跑一次对比。然后固定一个规则以图像坐标系的顺时针为正方向统一到 0~180 和 0~-180 的区间。这算是我反复强调的一个点因为在旋转目标检测项目里角度符号错误导致的损失异常最隐蔽模型也许还能收敛但检测结果会有系统性偏差。5.4 标注图片路径含中文导致 XML 关联失败现象标注完的图片复制到另一台机器标签文件仍在但训练脚本报找不到图片或打开 XML 里的 filename 字段发现路径中文字符变成了乱码。原因早期源码对文件名编码处理不完善存 XML 时直接用了系统的本地编码换环境后就无法正确还原。解决项目一开始就把所有图片路径和工作目录改成纯英文这是成本最低的方案。如果你必须保留中文名就自己加一个os.path.basename处理逻辑并且读取 XML 时固定用 UTF-8 编码解析。标注工具毕竟是拿来批量出数的不要在命名规范上省事。5.5 批量转换时内存被打满越跑越慢现象用上面的转换脚本处理几千张图时一开始挺快跑到五六百张后内存占用肉眼可见地飙升速度越来越慢。原因脚本里解析 XML 的部分没有释放资源或者循环外持有大量图片引用。如果用了 matplotlib 画图验证默认交互模式下图窗不关闭也会积压内存。解决转换脚本里已经用ET.parse每次解析完就释放如果还慢检查是不是在循环内存了原图数组。画图校验时用plt.close(all)显式关闭画布。按这个排查路径处理几千张图的转换控制在几分钟内没有问题。6. 把标注源码改造成你要的形态三个高性价比的小改动源码最有价值的地方不是你拿它原样跑通一个项目而是能改造成贴合自己流程的能力。这里列三个性价比非常高的改动方向任一都能明显提升标注与训练的对接效率。第一个改动是给旋转框增加键盘微调角度功能。在keyPressEvent里监听 R 键和 ShiftR 键让当前选中的旋转框角度旋转 1 度或 10 度。这个改动实现量很小但对标注效率的提升是质的尤其是目标的朝向比较规整时你先大致画个框再用键盘微调到贴合比重新画一条边快得多。第二步可以在源码里加一个「导出训练格式」的按钮把当前文件或整个目录的 XML 直接转成 YOLO 旋转格式的 TXT省去每次跑外部脚本的环节。第三个改动是增加标注质量抽查模式。很多团队用 roLabelImg 时没有把标注质量反馈闭环做出来往往是标完几万张才发现某一批的坐标偏移。我建议在源码里加一个简单的 validator保存前自动检查当前框的面积是否小于某个阈值、角度是否在合理范围内、有没有明显超出图片边界把异常框弹窗提示出来。这个机制能在标注过程中实时拦截错误比事后清洗数据节约的时间多得多。我自己经历过的教训是第一版标注流程没有做自动检查两周后训练出来的模型在目标错位问题上表现很差回头排查才发现一个版本分支的角度写入逻辑在某些情况下会翻负号。后来把 validator 加进源码这种问题在标注当天就能发现。希望这些做法能帮到你也欢迎你在实践中找出新的坑绕过去让旋转检测的数据管线少一些玄学多一些确定性。本文还有配套的精品资源点击获取
RELATED

相关推荐

数据库图书管理系统实训全流程:从E-R图到JDBC事务与并发控制

数据库图书管理系统实训全流程:从E-R图到JDBC事务与并发控制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/12 2:52:34
图像质量评估模型Python实战:PSNR/SSIM/BRISQUE量化指南

图像质量评估模型Python实战:PSNR/SSIM/BRISQUE量化指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/12 2:52:34
CLion搭建树莓派Pico C/C++开发环境:从零到断点调试全攻略

CLion搭建树莓派Pico C/C++开发环境:从零到断点调试全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/12 2:52:34
MORE NEWS

更多资讯

📰

声呐阵列信号处理——声呐阵列波束形成(第一章第三节)

一、声呐阵列模型3.接收数据模型(1)数据组成阵元的实际接收数据是信号、噪声等干扰的叠加,所以接收数据模型建立的前提需是信号模型、噪声模型的构建。对于第m个阵元,其接收数据可以表示为数据中包含期望信号,D个干扰信…

📰

深入 Freelens 扩展契约测试桩:`@freelensapp/fixture-extension` 如何让“静默破坏“无处遁形

云原生开发工具运维 【免费下载链接】freelens Free IDE for Kubernetes 项目地址: https://gitcode.com/gh_mirrors/fr/freelens 点击查看 免费下载 导读 Freelens(Kubernetes 免费 IDE)通过 freelensapp/extensions 向第三方暴露扩展契约…

📰

ant-design-blazor TreeSelect 弹出位置(placement)完全指南:手动指定下拉弹出方向与底层实现解析

前端UI组件设计系统 【免费下载链接】ant-design-blazor 基于 Ant Design 与 Blazor 的前端组件库。让开发者解放生产力,实现更大价值。 项目地址: https://gitcode.com/ant-design-blazor/ant-design-blazor 点击查看 免费下载 placement 是 ant-desig…

📰

使用 Jaeger Go 客户端(jaeger-client-go)为 Go 服务接入 OpenTracing 分布式追踪

云原生可观测性容器编排运维 【免费下载链接】scope Monitoring, visualisation & management for Docker & Kubernetes 项目地址: https://gitcode.com/gh_mirrors/sc/scope 点击查看 免费下载 jaeger-client-go 是 Uber 提供的 Jaeger 官方 Go 探针库&am…

📰

Infosec_Reference 之 ICS/SCADA 安全资源指南:从协议原理到攻防工具链

网络安全教程 【免费下载链接】Infosec_Reference An Information Security Reference That Doesnt Suck; https://rmusser.net/git/admin-2/Infosec_Reference for non-MS Git hosted version. 项目地址: https://gitcode.com/gh_mirrors/in/Infosec_Reference 点击…

📰

基于微信小程序与SSM的小区管理系统开发实践

1. 项目概述与选题背景第一次看到“基于微信小程序的小区管理系统”这个题目,很多人的第一反应是:这不就是一个普通的CRUD项目吗?其实真做下来你会发现,这个项目的难度不在代码量,而在“业务流程的闭环”和“多端数据的…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬