Voc标签文件转Yolo标签文件程序

为了方便,我将代码封装成了桌面程序,GUI部分我就不介绍了,泛泛而谈到时啥都没学会。

一、yolo标签格式

我们看一下yolo标签的格式:

<class index> <x center> <y center> <width> <height> \text{<class index> <x center> <y center> <width> <height>} <class index> <x center> <y center> <width> <height>

上述格式【class_index】是某类别对应的标签索引,为整型;后面4个参数均为比例,而不是实际参数,我们举个例子

1 0.759623 0.749454 0.079443 0.081878

我假设“汽车”这个类别对应的标签索引为1。那么上述例子表示我们标了一个框,这个框的类别索引为1,表示为类别“汽车”。

前两个浮点参数表示这个框的中心坐标分别相对于整个图像宽度和高度的比例,用比例来表示中心点的位置;后两者表示框的宽度和高度分别相对于整个图像的比例,用比例来表达框的大小。

二、载入XML文件

首先我们使用python自带模块【os】来将指定目录(XML文件所在目录)【self.source_path】的所有文件名载入到文件名列表【Files】中。

然后我们使用for训练,遍历文件列表的每一个文件名,如果文件名的扩展名是【.XML】,则表示是标签文件,此时调用Process进行转换

def LoadVocTag(self):Files = os.listdir(self.source_path)# 处理每一个xml文件for File in Files:if File.endswith('.xml'):self.Process(File)

三、获取类别标签对应类别索引字典

代码中【self.classes_file】表示含有对应关系的txt文件路径,现在我们要把它载入,做成字典。我们看一个类别标签和类别索引的对应关系的txt文件内容:

纸类 1
塑料类 2
金属类 3
衣品类 4
其他 5

上述内容,类别标签和类别索引之间用空格隔开了,因此我们打开文件后,逐行读取内容,然后使用空格进行分割成两段。前段是类别标签,后段时类别索引,类别索引读出来是文本,我们转换成整型后添加到字典就好了。

我相信现在看下面的代码就一目了然了:

def GetTag(self):# 类别字典class_dict = {}# 打开含有号码和类别对应关系的txt文件with open(self.classes_file, 'r', encoding='utf-8') as CF:# 获取txt文件的每一行信息for line in CF:parts = line.strip().split(' ')# 每行的第一部分是类别的中文描述,第二部分是相应的数字class_dict[parts[0]] = int(parts[1])# 返回类别字典return class_dict

四、格式转换

这一部分需要解析XML文件,解析XML文件,我呢使用轻量级的【xml.etree.ElementTree】模块,在小文件中,这个模块用来解析是非常方便的。

先获取对应关系的字典,便于后面解析文件得到类别后转换成类别索引:

# 获取类别字典,方便后续得到类别对应的号码
Class_Dict = self.GetTag()

for循环用tree.iterfind(‘object’)自动解析XML文件,循环查找 <object></object> \text{<object></object>} <object></object>标记,因为一个object表示我们锚的一个框。

# 查找object标签,每一个object标签,代表一个框
for object in tree.iterfind('object'):

VOC标签文档中object标记下第一行是 <name></name> \text{<name></name>} <name></name>标记,表示类别名字,也就是object[0]表示 <name></name> \text{<name></name>} <name></name>标记,其属性text就是标记的内容,该内容就是类别名字。

# 获取当前框所对应的类别名字
name = object[0].text

从字典中得到类别索引:

# 从类别字典中获取该类别对应的号码
tag = Class_Dict[name]

接下来就是计算转换部分了,下面代码中,【self.image_width】和【self.image_height】是图片尺寸,这个是需要输入的,其他的部分计算原理来自yolo标签的原理,可见第一部分的讲解

# 获取边框盒,该标记包含了目标框的4个角的坐标
box = object.find('bndbox')
# 获取4个角坐标(相对于图像左上角)
xmin = float(box.find('xmin').text)
ymin = float(box.find('ymin').text)
xmax = float(box.find('xmax').text)
ymax = float(box.find('ymax').text)# 计算中心点坐标
center_x = (xmin + xmax) / 2
center_y = (ymin + ymax) / 2
# 计算宽度和高度
width = xmax - xmin
height = ymax - ymin
# 图像的宽度和高度(实际应根据图像尺寸来调整)# 归一化为相对于图像宽度和高度的比例,YOLO标签以比例表示
normalized_center_x = center_x / self.image_width
normalized_center_y = center_y / self.image_height
normalized_width = width / self.image_width
normalized_height = height / self.image_height

接着我们将计算得到的结果严格按照yolo标签的格式组合在一起,每个参数之间用空格隔开,每个比例保留6位小数。content是一个列表,存储一张图片中包含的所有锚框标签信息。

# 格式化将写入txt文件的标签信息
info = f'{tag} {normalized_center_x:.6f} {normalized_center_y:.6f} {normalized_width:.6f} {normalized_height:.6f}'
# 给当前txt文件添加一行,表示处理完一个框
content.append(info)

五、保存txt标签文件

这部分需要将content列表的内容,逐个写入,每个占一行

def SaveToYoloTag(self, FileName, content):name = os.path.join(self.object_path, FileName.split('.')[0] + '.txt')with open(name, 'w') as yolo:# 按行写入for item in content:yolo.write(f'{item}\n')# 在滚动窗口中显示输出信息showname=name.split("\\")[-1]show=f'{showname} has been saved'self.output_textedit.append(show)

六、完整程序

import os
import xml.etree.ElementTree as ET
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QFileDialog, QLineEdit, QTextEdit,QDesktopWidgetclass YoloConverterApp(QWidget):def __init__(self):super().__init__()self.source_path = Noneself.object_path = Noneself.classes_file = Noneself.image_width = Noneself.image_height = Noneself.init_ui()def init_ui(self):layout = QVBoxLayout()self.source_label = QLabel('VOC标签文件路径:')layout.addWidget(self.source_label)self.object_label = QLabel('YOLO标签文件路径:')layout.addWidget(self.object_label)self.classes_label = QLabel('类别指示文件路径:')layout.addWidget(self.classes_label)self.width_label = QLabel('图像宽度:')layout.addWidget(self.width_label)self.width_input = QLineEdit()layout.addWidget(self.width_input)self.height_label = QLabel('图像高度:')layout.addWidget(self.height_label)self.height_input = QLineEdit()layout.addWidget(self.height_input)source_button = QPushButton('选择VOC标签文件路径')source_button.clicked.connect(self.choose_source_path)layout.addWidget(source_button)object_button = QPushButton('选择YOLO标签文件路径')object_button.clicked.connect(self.choose_object_path)layout.addWidget(object_button)classes_button = QPushButton('选择类别指示文件路径')classes_button.clicked.connect(self.choose_classes_file)layout.addWidget(classes_button)convert_button = QPushButton('转换')convert_button.clicked.connect(self.convert)layout.addWidget(convert_button)# 添加滚动窗口用于显示输出信息self.output_textedit = QTextEdit()self.output_textedit.setReadOnly(True)layout.addWidget(self.output_textedit)self.setLayout(layout)self.setWindowTitle('Yolo Converter')# 获取桌面尺寸desktop = QDesktopWidget()screen_rect = desktop.screenGeometry()width = screen_rect.width() * 0.5height = screen_rect.height() * 0.5# 设置窗口大小为桌面大小的50%self.setGeometry(100, 100, int(width), int(height))def open_file_dialog(self, label):# 创建文件对话框的选项options = QFileDialog.Options()options |= QFileDialog.DontUseNativeDialog# 创建 QFileDialog 实例file_dialog = QFileDialog()file_dialog.setOptions(options)# 将文件模式设置为选择目录file_dialog.setFileMode(QFileDialog.Directory)# 如果用户选择了目录并点击了确定if file_dialog.exec_():# 获取所选路径selected_path = file_dialog.selectedFiles()[0]# 将提供的标签的文本设置为所选路径label.setText(selected_path)def convert(self):self.image_width = int(self.width_input.text())self.image_height = int(self.height_input.text())self.LoadVocTag()def choose_source_path(self):self.open_file_dialog(self.source_label)self.source_path = self.source_label.text()def choose_object_path(self):self.open_file_dialog(self.object_label)self.object_path = self.object_label.text()def choose_classes_file(self):# 创建文件对话框的选项options = QFileDialog.Options()options |= QFileDialog.DontUseNativeDialog# 创建 QFileDialog 实例file_dialog = QFileDialog()file_dialog.setOptions(options)# 如果用户选择了文件并点击了确定if file_dialog.exec_():# 获取所选文件selected_file = file_dialog.selectedFiles()[0]# 将类别标签的文本设置为所选文件self.classes_label.setText(selected_file)# 将类别文件属性设置为所选文件路径self.classes_file = selected_filedef LoadVocTag(self):Files = os.listdir(self.source_path)# 处理每一个xml文件for File in Files:if File.endswith('.xml'):self.Process(File)# 处理单个XML文件def Process(self, File):# 获取解析树tree = ET.parse(os.path.join(self.source_path, File))# 获取类别字典,方便后续得到类别对应的号码Class_Dict = self.GetTag()# 存储要写入txt文件的内容,content的元素个数就是该图片含有的目标框数content = []# 查找object标签,每一个object标签,代表一个框for object in tree.iterfind('object'):# 获取当前框所对应的类别名字name = object[0].text# 从类别字典中获取该类别对应的号码tag = Class_Dict[name]# 获取边框盒,该标记包含了目标框的4个角的坐标box = object.find('bndbox')# 获取4个角坐标(相对于图像左上角)xmin = float(box.find('xmin').text)ymin = float(box.find('ymin').text)xmax = float(box.find('xmax').text)ymax = float(box.find('ymax').text)# 计算中心点坐标center_x = (xmin + xmax) / 2center_y = (ymin + ymax) / 2# 计算宽度和高度width = xmax - xminheight = ymax - ymin# 图像的宽度和高度(实际应根据图像尺寸来调整)# 归一化为相对于图像宽度和高度的比例,YOLO标签以比例表示normalized_center_x = center_x / self.image_widthnormalized_center_y = center_y / self.image_heightnormalized_width = width / self.image_widthnormalized_height = height / self.image_height# 格式化将写入txt文件的标签信息info = f'{tag} {normalized_center_x:.6f} {normalized_center_y:.6f} {normalized_width:.6f} {normalized_height:.6f}'# 给当前txt文件添加一行,表示处理完一个框content.append(info)# 保存为yolo格式的标签self.SaveToYoloTag(File, content)# 获取类别标签对应的字典def GetTag(self):# 类别字典class_dict = {}# 打开含有号码和类别对应关系的txt文件with open(self.classes_file, 'r', encoding='utf-8') as CF:# 获取txt文件的每一行信息for line in CF:parts = line.strip().split(' ')# 每行的第一部分是类别的中文描述,第二部分是相应的数字class_dict[parts[0]] = int(parts[1])# 返回类别字典return class_dict# 将处理后的标签信息保存为YOLO格式的文件def SaveToYoloTag(self, FileName, content):name = os.path.join(self.object_path, FileName.split('.')[0] + '.txt')with open(name, 'w') as yolo:# 按行写入for item in content:yolo.write(f'{item}\n')# 在滚动窗口中显示输出信息showname=name.split("\\")[-1]show=f'{showname} has been saved'self.output_textedit.append(show)if __name__ == '__main__':app = QApplication(sys.argv)converter_app = YoloConverterApp()converter_app.show()sys.exit(app.exec_())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/636692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用LibreOffice做出第一个开源贡献的6种简单方法

2022年5月是LibreOffice月。这里有一些简单的方法来完成您的第一个开源贡献。 参与开源似乎有点令人困惑。从哪里开始?如何编码?和谁说话?别人怎么知道你做出了贡献&#xff0c;除此之外&#xff0c;还有人关心你吗? 事实上&#xff0c;这些问题都有一个简单的答案:LibreO…

蓝桥杯官网题目:2.包子凑数

链接:题目点这里 首先要知道一个数学定理裴蜀定理&#xff0c;还有完全背包的基本运用&#xff0c;这里只介绍前者 也可以看一下我的个人理解&#xff0c;我是第一次听说这个定理&#xff0c;理解可能有误差。 假设gcd(a,b)d,gcd是最大公约数的意思。即a&#xff0c;b的最大…

fabric.js 组件 图片上传裁剪并进行自定义区域标记

目录 0. 前言 1. 安装fabric与引入 2. fabric组件的使用 3. 属性相关设置 4. 初始化加载 4. 方法 5. 全代码 0. 前言 利用fabric组件&#xff0c;实现图片上传、图片”裁剪“、自定义的区域标记一系列操作 先放一张效果图吧&#x1f447; 1. 安装fabric与引入 npm i …

随身WiFi到底能不能买?一篇文章给你讲清楚!随身WiFi哪个品牌最靠谱 ,随身WiFi推荐第一名

随着移动设备的普及&#xff0c;人们对无线网络的需求越来越高。传统WiFi虽然覆盖面广&#xff0c;但移动性差&#xff0c;不能满足人们在外出、旅行或商务场合的上网需求。此时&#xff0c;随身WiFi的出现填补了这一空白。那么&#xff0c;随身WiFi究竟有何优势和劣势&#xf…

Zabbix 系统监控详解

1 介绍 1.1 摘要 本文深入浅出&#xff0c;切近实际运维应用&#xff0c;由 zabbix 3.4 版本入手&#xff0c;学习 zabbix 监控告警实现方式&#xff0c;由 zabbix 5.0 浅出实现快速部署、快速应用。本人从业多年&#xff0c;关注 zabbix 开源社区&#xff0c;以及 zabbix 官…

【开发必备】泳道图编辑工具及使用

1.什么是泳道图 事情的起因在与博主要和几位小伙伴一起开发一个小程序&#xff0c;那么涉及的人多时就需要用到需求文档这个玩意。然后博主当然要扛起写需求文档这项项目经理 &#xff08;牛马&#xff09;的职责了&#xff01; 然后&#xff0c;博主就发现需求文档中一个看似…

【C++算法】构建最优哈夫曼树

【C算法】构建最优哈夫曼树 作者&#xff1a;爱写代码的刚子 时间&#xff1a;2024.1.20 前言&#xff1a;本篇博客的代码均为自己独立完成&#xff0c;可能会有瑕疵 代码实现 #include <iostream> #include <vector> #include <queue> using namespace std…

idea上传本地项目到gitlab

1. idea上传本地项目到gitlab 1. 配置idea里本地安装的git位置 即选择 Settings -> Version Control -> Git -> Path to Git executable 2. 在idea创建本地仓库 即选择 VCS -> Create Git Repository 然后选择目录&#xff0c;默认就是选择的当前项目&#xff…

【Linux】03 GCC编译器的使用

一、编译过程 在使用gcc编译程序时&#xff0c;编译过程可以简要划分为4个阶段&#xff1a; 预处理、编译、汇编、链接 1.1 预处理&#xff08;preprocessing&#xff09; 这个阶段主要处理源文件中的#indef、#include和#define预处理命令&#xff1b; 这里主要是把一些include…

低代码开发让量化交易插上翅膀

随着技术的不断发展&#xff0c;低代码开发平台逐渐在各个领域崭露头角。其中&#xff0c;量化交易是一个领域&#xff0c;通过低代码开发平台&#xff0c;使得量化交易策略的开发和实施更加高效、灵活和可持续。 量化交易是基于算法和数学模型的自动化交易策略&#xff0c;近年…

RT-DETR算法优化改进:DCNv4更快收敛、更高速度、更高性能,效果秒杀DCNv3、DCNv2等 ,助力检测

💡💡💡本文独家改进:DCNv4更快收敛、更高速度、更高性能,完美和RT-DETR结合,助力涨点 DCNv4优势:(1) 去除空间聚合中的softmax归一化,以增强其动态性和表达能力;(2) 优化存储器访问以最小化冗余操作以加速。这些改进显著加快了收敛速度,并大幅提高了处理速度,DC…

Linux指令(四)

1.more指令 我们知道cat指令是用来读取文本文件的&#xff0c;但是如果是大文件&#xff0c;其实是不适合cat读取的&#xff0c;原因是&#xff1a;cat读取会直接到文本的结尾&#xff0c;所以我们引入&#xff1a;more指令 该指令不会将文件直接读到结尾&#xff0c;而是将最…

Cocos creator 的事件处理(鼠标事件、键盘事件、触摸事件、自定义事件、控制精灵移动Demo)

鼠标事件 //鼠标事件this.node.on(cc.Node.EventType.MOUSE_DOWN, (e: cc.Event.EventMouse) > {cc.log(e.getLocation() "")if (e.getButton() cc.Event.EventMouse.BUTTON_LEFT) {cc.log("鼠标左键")}})键盘事件 //键盘事件cc.systemEvent.on(cc.Sy…

Python中二维数据(数组、列表)索引和切片的Bug

Python中有关数据结构索引和切片引起的Bug 一维数据索引和切片一维数组一维列表 二维数据的索引和切片二维数组二维(错误)列表 一维数据索引和切片 一维数组 对于一维数据进行索引和切片操作&#xff0c;大家都比较熟悉通过下面代码进行实现 import numpy as np data np.ra…

AP1400-2-HW1---一个c++的线性代数库

&#xff08;1&#xff09;random库&#xff08;随机数矩阵&#xff09;&#xff1a; 1. &#xff08;1&#xff09;std::random_device是一个产生非确定性随机数的类。 在大多数情况下&#xff0c;它会产生基于硬件的随机数&#xff0c;比如通过硬件噪声等方式。 &#xff…

[陇剑杯 2021]webshell

[陇剑杯 2021]webshell 题目做法及思路解析&#xff08;个人分享&#xff09; 问一&#xff1a;单位网站被黑客挂马&#xff0c;请您从流量中分析出webshell&#xff0c;进行回答&#xff1a; 黑客登录系统使用的密码是_____________。 题目思路&#xff1a; 分析题目&…

logstack 日志技术栈-02-ELK 的缺点?loki 更轻量的解决方案?

ELK/EFK日志系统 如果今天谈论到要部署一套日志系统&#xff0c;相信用户首先会想到的就是经典的ELK架构&#xff0c;或者现在被称为Elastic Stack。 Elastic Stack架构为Elasticsearch Logstash Kibana Beats的组合&#xff0c;其中&#xff0c;Beats负责日志的采集&…

多表形成树形结构

多表形成树形结构&#xff1a; package com.js.archive.assistant.domain.vo;import com.js.core.domain.vo.BaseVO; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode;import…

mysql中建立一个用户,只能看到某个指定的数据库

MySQL用户管理及权限控制 在MySQL数据库中&#xff0c;用户管理和权限控制是非常重要的功能。通过正确地设置用户和权限&#xff0c;可以保护数据库的安全性&#xff0c;防止未授权的访问和数据泄露。本文将介绍如何在MySQL中创建一个用户&#xff0c;并限制该用户只能访问特定…

假设检验:以样本服从二项分布举例

目录 假设检验一、假设检验的思想二、假设检验的基本步骤1. 确定要进行检验的假设2. 选择检验统计量3. 确定用于做决策的拒绝域4. 求出检验统计量的值5. 查看样本结果是否位于拒绝域内6. 做出决策 三、举例说明例子1——某公司治疗打鼾例子2——女士品茶的故事 假设检验 一、假…