转自:LabelImg标注的VOC格式xml标签与YOLO格式txt标签相互转换_wangmj_hdu的博客-CSDN博客

1、VOC标签格式说明

VOC数据格式,会直接把每张图片标注的标签信息保存到一个xml文件中。

例如我在做仓储托盘检测的时候,需要对图片中的托盘进行标注,标注的标签信息会保存到一个跟图片对应的xml文件中(每张图片与每个xml文件一一对应),xml中的信息如下:

<annotation><folder>Images</folder><filename>1.jpg</filename><path>/home/wangmj/pallet_data/Images/1.jpg</path><source><database>Unknown</database></source><size><width>1920</width><height>1080</height><depth>3</depth></size><segmented>0</segmented><object><name>forklift_pallet</name><pose>Unspecified</pose><truncated>0</truncated><difficult>0</difficult><bndbox><xmin>437</xmin><ymin>557</ymin><xmax>1230</xmax><ymax>660</ymax></bndbox></object>
</annotation>

xml文件中的关键信息说明:

1.jpg,这是图片名称,则xml文件名为1.xml;
    /home/wangmj/pallet_data/Images/1.jpg,这是存放该图片的绝对路径;
    1920 * 1080,这是图片分辨率,3代表三通道图片;
    forklift_pallet,这是类别名;
    xmin,ymin,xmax,ymax,定义了每个目标的标定框坐标:即左上角的坐标和右下角的坐标;

2、YOLO标签格式说明

YOLO标签格式,会直接把每张图片标注的标签信息保存到一个txt文件中。

我的图片名称为1.jpg,则对应的txt文件名称为1.txt。

同样例如我在做仓储托盘检测的时候,需要对图片中的托盘进行标注,标注的标签信息会保存到一个跟图片对应的txt文件中,txt中的信息如下:

0 0.433594 0.562037 0.409896 0.092593

txt文件中的关键信息说明:

每一行代表标注的一个目标,我这张图中只标注了一个目标,所以只有一行;
    第一个数字0代表标注目标的类别;
    后面四个数字代表标注框的中心坐标和标注框的相对宽和高(进行了归一化处理);
    五个数据从左到右依次为:class x_center y_center width height

同时还会生成一个classes.txt,里面内容如下:

forklift_pallet

注意这个是分类的类型,需要在后面的yolo转voc_xml时根据自己的类型种类进行更改

3、voc格式转化为yolo格式

标注好的voc格式的标签xml文件,主要信息为:

1.jpg,这是图片名称;
    /home/wangmj/pallet_data/Images/1.jpg,这是存放该图片的绝对路径;
    1920 * 1080,这是图片分辨率,3代表三通道图片;
    forklift_pallet,这是类别名;
    xmin,ymin,xmax,ymax,定义了每个目标的标定框坐标:即左上角的坐标和右下角的坐标;
例如下面一张图:

原图大小为1920 * 1080
    紫色框代表标注物体的框,紫色框的左上角的坐标为(xmin,ymin)=(372,518),右下角的坐标为(xmax,ymax)=(1344,674)

voc_to_yolo.py的目的就是把voc数据格式转换为yolo格式:

voc格式标签:图片的实际宽高,标注框的左上角和右下角坐标;
    yolo格式标签:标注框的中心坐标(归一化),标注框的宽和高(归一化)。

voc格式转换为yolo格式计算公式:

框中心的实际坐标(x,y),一般可能还会在后面减1

归一化以后的中心坐标(x,y)

框的高和宽(归一化后)

voc格式的xml标签文件转化yolo格式的txt标签文件代码:voc_to_yolo.py

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import joindef convert(size, box):# size=(width, height)  b=(xmin, xmax, ymin, ymax)# x_center = (xmax+xmin)/2        y_center = (ymax+ymin)/2# x = x_center / width            y = y_center / height# w = (xmax-xmin) / width         h = (ymax-ymin) / heightx_center = (box[0]+box[1])/2.0y_center = (box[2]+box[3])/2.0x = x_center / size[0]y = y_center / size[1]w = (box[1] - box[0]) / size[0]h = (box[3] - box[2]) / size[1]# print(x, y, w, h)return (x,y,w,h)def convert_annotation(xml_files_path, save_txt_files_path, classes):  xml_files = os.listdir(xml_files_path)# print(xml_files)for xml_name in xml_files:# print(xml_name)xml_file = os.path.join(xml_files_path, xml_name)out_txt_path = os.path.join(save_txt_files_path, xml_name.split('.')[0] + '.txt')out_txt_f = open(out_txt_path, 'w')tree=ET.parse(xml_file)root = tree.getroot()size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)for obj in root.iter('object'):difficult = obj.find('difficult').textcls = obj.find('name').textif cls not in classes or int(difficult) == 1:continuecls_id = classes.index(cls)xmlbox = obj.find('bndbox')b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))# b=(xmin, xmax, ymin, ymax)# print(w, h, b)bb = convert((w,h), b)out_txt_f.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')if __name__ == "__main__":# 把forklift_pallet的voc的xml标签文件转化为yolo的txt标签文件# 1、需要转化的类别classes = ['forklift_pallet']#注意:这里根据自己的类别名称及种类自行更改# 2、voc格式的xml标签文件路径xml_files1 = r'/home/wangmj/pallet_data/Annotations'# 3、转化为yolo格式的txt标签文件存储路径save_txt_files1 = r'/home/wangmj/pallet_data/test'convert_annotation(xml_files1, save_txt_files1, classes)

4、yolo格式转化为voc格式

voc格式中保存的信息为:xmin,ymin,xmax,ymax,所以只要根据上面的公式,就可以推导出这四个值。

yolo格式的txt标签文件转化voc格式的xml标签文件代码:yolo_to_voc.py

import os
import xml.etree.ElementTree as ET
from xml.dom.minidom import Document
import cv2'''
import xml
xml.dom.minidom.Document().writexml()
def writexml(self,writer: Any,indent: str = "",addindent: str = "",newl: str = "",encoding: Any = None) -> None
'''class YOLO2VOCConvert:def __init__(self, txts_path, xmls_path, imgs_path):self.txts_path = txts_path   # 标注的yolo格式标签文件路径self.xmls_path = xmls_path   # 转化为voc格式标签之后保存路径self.imgs_path = imgs_path   # 读取读片的路径各图片名字,存储到xml标签文件中'''#注意:这里根据自己的类别名称及种类自行更改'''self.classes = ['forklift_pallet']#注意:这里根据自己的类别名称及种类自行更改# 从所有的txt文件中提取出所有的类别, yolo格式的标签格式类别为数字 0,1,...# writer为True时,把提取的类别保存到'./Annotations/classes.txt'文件中def search_all_classes(self, writer=False):# 读取每一个txt标签文件,取出每个目标的标注信息all_names = set()txts = os.listdir(self.txts_path)# 使用列表生成式过滤出只有后缀名为txt的标签文件txts = [txt for txt in txts if txt.split('.')[-1] == 'txt']print(len(txts), txts)# 11 ['0002030.txt', '0002031.txt', ... '0002039.txt', '0002040.txt']for txt in txts:txt_file = os.path.join(self.txts_path, txt)with open(txt_file, 'r') as f:objects = f.readlines()for object in objects:object = object.strip().split(' ')print(object)  # ['2', '0.506667', '0.553333', '0.490667', '0.658667']all_names.add(int(object[0]))# print(objects)  # ['2 0.506667 0.553333 0.490667 0.658667\n', '0 0.496000 0.285333 0.133333 0.096000\n', '8 0.501333 0.412000 0.074667 0.237333\n']print("所有的类别标签:", all_names, "共标注数据集:%d张" % len(txts))return list(all_names)def yolo2voc(self):# 创建一个保存xml标签文件的文件夹if not os.path.exists(self.xmls_path):os.mkdir(self.xmls_path)# 把上面的两个循环改写成为一个循环:imgs = os.listdir(self.imgs_path)txts = os.listdir(self.txts_path)txts = [txt for txt in txts if not txt.split('.')[0] == "classes"]  # 过滤掉classes.txt文件print(txts)# 注意,这里保持图片的数量和标签txt文件数量相等,且要保证名字是一一对应的   (后面改进,通过判断txt文件名是否在imgs中即可)if len(imgs) == len(txts):   # 注意:./Annotation_txt 不要把classes.txt文件放进去map_imgs_txts = [(img, txt) for img, txt in zip(imgs, txts)]txts = [txt for txt in txts if txt.split('.')[-1] == 'txt']print(len(txts), txts)for img_name, txt_name in map_imgs_txts:# 读取图片的尺度信息print("读取图片:", img_name)img = cv2.imread(os.path.join(self.imgs_path, img_name))height_img, width_img, depth_img = img.shapeprint(height_img, width_img, depth_img)   # h 就是多少行(对应图片的高度), w就是多少列(对应图片的宽度)# 获取标注文件txt中的标注信息all_objects = []txt_file = os.path.join(self.txts_path, txt_name)with open(txt_file, 'r') as f:objects = f.readlines()for object in objects:object = object.strip().split(' ')all_objects.append(object)print(object)  # ['2', '0.506667', '0.553333', '0.490667', '0.658667']# 创建xml标签文件中的标签xmlBuilder = Document()# 创建annotation标签,也是根标签annotation = xmlBuilder.createElement("annotation")# 给标签annotation添加一个子标签xmlBuilder.appendChild(annotation)# 创建子标签folderfolder = xmlBuilder.createElement("folder")# 给子标签folder中存入内容,folder标签中的内容是存放图片的文件夹,例如:JPEGImagesfolderContent = xmlBuilder.createTextNode(self.imgs_path.split('/')[-1])  # 标签内存folder.appendChild(folderContent)  # 把内容存入标签annotation.appendChild(folder)   # 把存好内容的folder标签放到 annotation根标签下# 创建子标签filenamefilename = xmlBuilder.createElement("filename")# 给子标签filename中存入内容,filename标签中的内容是图片的名字,例如:000250.jpgfilenameContent = xmlBuilder.createTextNode(txt_name.split('.')[0] + '.jpg')  # 标签内容filename.appendChild(filenameContent)annotation.appendChild(filename)# 把图片的shape存入xml标签中size = xmlBuilder.createElement("size")# 给size标签创建子标签widthwidth = xmlBuilder.createElement("width")  # size子标签widthwidthContent = xmlBuilder.createTextNode(str(width_img))width.appendChild(widthContent)size.appendChild(width)   # 把width添加为size的子标签# 给size标签创建子标签heightheight = xmlBuilder.createElement("height")  # size子标签heightheightContent = xmlBuilder.createTextNode(str(height_img))  # xml标签中存入的内容都是字符串height.appendChild(heightContent)size.appendChild(height)  # 把width添加为size的子标签# 给size标签创建子标签depthdepth = xmlBuilder.createElement("depth")  # size子标签widthdepthContent = xmlBuilder.createTextNode(str(depth_img))depth.appendChild(depthContent)size.appendChild(depth)  # 把width添加为size的子标签annotation.appendChild(size)   # 把size添加为annotation的子标签# 每一个object中存储的都是['2', '0.506667', '0.553333', '0.490667', '0.658667']一个标注目标for object_info in all_objects:# 开始创建标注目标的label信息的标签object = xmlBuilder.createElement("object")  # 创建object标签# 创建label类别标签# 创建name标签imgName = xmlBuilder.createElement("name")  # 创建name标签imgNameContent = xmlBuilder.createTextNode(self.classes[int(object_info[0])])imgName.appendChild(imgNameContent)object.appendChild(imgName)  # 把name添加为object的子标签# 创建pose标签pose = xmlBuilder.createElement("pose")poseContent = xmlBuilder.createTextNode("Unspecified")pose.appendChild(poseContent)object.appendChild(pose)  # 把pose添加为object的标签# 创建truncated标签truncated = xmlBuilder.createElement("truncated")truncatedContent = xmlBuilder.createTextNode("0")truncated.appendChild(truncatedContent)object.appendChild(truncated)# 创建difficult标签difficult = xmlBuilder.createElement("difficult")difficultContent = xmlBuilder.createTextNode("0")difficult.appendChild(difficultContent)object.appendChild(difficult)# 先转换一下坐标# (objx_center, objy_center, obj_width, obj_height)->(xmin,ymin, xmax,ymax)x_center = float(object_info[1])*width_img + 1y_center = float(object_info[2])*height_img + 1xminVal = int(x_center - 0.5*float(object_info[3])*width_img)   # object_info列表中的元素都是字符串类型yminVal = int(y_center - 0.5*float(object_info[4])*height_img)xmaxVal = int(x_center + 0.5*float(object_info[3])*width_img)ymaxVal = int(y_center + 0.5*float(object_info[4])*height_img)# 创建bndbox标签(三级标签)bndbox = xmlBuilder.createElement("bndbox")# 在bndbox标签下再创建四个子标签(xmin,ymin, xmax,ymax) 即标注物体的坐标和宽高信息# 在voc格式中,标注信息:左上角坐标(xmin, ymin) (xmax, ymax)右下角坐标# 1、创建xmin标签xmin = xmlBuilder.createElement("xmin")  # 创建xmin标签(四级标签)xminContent = xmlBuilder.createTextNode(str(xminVal))xmin.appendChild(xminContent)bndbox.appendChild(xmin)# 2、创建ymin标签ymin = xmlBuilder.createElement("ymin")  # 创建ymin标签(四级标签)yminContent = xmlBuilder.createTextNode(str(yminVal))ymin.appendChild(yminContent)bndbox.appendChild(ymin)# 3、创建xmax标签xmax = xmlBuilder.createElement("xmax")  # 创建xmax标签(四级标签)xmaxContent = xmlBuilder.createTextNode(str(xmaxVal))xmax.appendChild(xmaxContent)bndbox.appendChild(xmax)# 4、创建ymax标签ymax = xmlBuilder.createElement("ymax")  # 创建ymax标签(四级标签)ymaxContent = xmlBuilder.createTextNode(str(ymaxVal))ymax.appendChild(ymaxContent)bndbox.appendChild(ymax)object.appendChild(bndbox)annotation.appendChild(object)  # 把object添加为annotation的子标签f = open(os.path.join(self.xmls_path, txt_name.split('.')[0]+'.xml'), 'w')xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')f.close()if __name__ == '__main__':# 把yolo的txt标签文件转化为voc格式的xml标签文件# yolo格式txt标签文件相对路径txts_path1 = './test_txt'# 转化为voc格式xml标签文件存储的相对路径xmls_path1 = './test_xml'# 存放图片的相对路径imgs_path1 = './Images'yolo2voc_obj1 = YOLO2VOCConvert(txts_path1, xmls_path1, imgs_path1)labels = yolo2voc_obj1.search_all_classes()print('labels: ', labels)yolo2voc_obj1.yolo2voc()

VOC格式xml标签与YOLO格式txt标签相互转换相关推荐

  1. labelimg标注的VOC格式标签xml文件和yolo格式标签txt文件相互转换

    目录 1 labelimg标注VOC格式和yolo格式介绍 1.1 voc格式 1.2 yolo数据格式介绍 2 voc格式数据和yolo格式数据相互转换 2.1 voc转yolo代码 2.2 yol ...

  2. 将VOC格式标注文件转换为Yolo格式

    这篇文章主要参考博客中的代码,对原博客VOC格式数据集转yolo格式代码进行一定修改.添加注释,此外还在后面添加了我自己写的一段关于对转换后的图片和标注文件进行整理的脚本代码. 关于数据集在Yolo格 ...

  3. 【目标检测】TT100K数据集使用,提取标注信息并转换成VOC格式的xml文件或yolo格式的txt文件

    1 TT100K 官网 TT100K官网 1.1 数据集介绍 本人下载的是2021的数据集,训练集 6105张图片, 测试集 3071 张图片,每张图片的分辨率为2048 * 2048,共有232 种 ...

  4. 100种目标检测数据集【voc格式yolo格式json格式coco格式】+YOLO系列算法源码及训练好的模型

    提示:本文介绍并分享了应用于各行业.各领域非常有用的目标检测数据集(感谢您的关注+三连,数据集持续更新中-),其中绝大部分数据集作者已应用于各种实际落地项目,数据集整体质量好,标注精确,数据的多样性充 ...

  5. Visdrone2019数据集.txt标签文件转换为voc格式.XML标签文件

    最近有同学问是否有Visdrone数据集的xml文件,由于本人之前训练数据的时候没有保存xml文件,所以无法共享. 为了解决这个问题,重新写了转换代码并贴出,供大家共同学习使用.(文末附上数据下载网盘 ...

  6. 把LabelImg标注的YOLO格式标签转化为VOC格式标签 和 把VOC格式标签转化为YOLO格式标签

    把LabelImg标注的YOLO格式标签转化为VOC格式标签 和 把VOC格式标签转化为YOLO格式标签 文章目录: 1 用LabelImgvoc和yolo标注标签格式说明 1.1 LabelImg标 ...

  7. BDD100K数据集转YOLO格式

    前言 BDD100K由伯克利大学AI实验室(BAIR)发布,是目前最大规模.内容最具多样性的公开驾驶数据集.BDD100K 数据集包含10万段高清视频,每个视频约40秒,720p,30 fps .每个 ...

  8. yolo数据集txt标注转voc数据集xml标注格式

    yolo数据集txt标注格式为: 0 0.159375 0.552083 0.121875 0.381944 0 0.776953 0.747222 0.099219 0.361111 代码如下: i ...

  9. python 将YOLO(txt)格式的标注数据批量转换为PascalVOC(XML)格式的标注数据

    python 将YOLO(txt)格式的标注数据批量转换为PascalVOC(XML)格式的标注数据 准备工作 修改代码路径 运行代码 程序bug(没时间看所以还没解决): 准备工作 需在目标文件夹中 ...

最新文章

  1. 消息处理机制之Handler
  2. AIX HACMP集群切换测试实际案例解析
  3. CMD下netstat ping等命令提示:不是内部或外部命令,也不是可运行的程序或批处理文件。
  4. 如何查看数据库是否是rac,如何查看数据库是否是单实例
  5. 软件测试linux笔试题目,linux基础面试题
  6. Kubernetes入门——从零搭建k8s集群
  7. wenbao与cf整数直角三角形
  8. LeetCode之翻转二叉树以匹配先序遍历
  9. Unity中利用反射自动读取Excel配置
  10. UnboundLocalError: local variable 'XXX' referenced before assignment
  11. 使用matlab进行深度学习
  12. 一天搞懂深度学习—学习笔记1
  13. jmeter请求grpc接口
  14. 小米路由器3开启千兆_使用评测 篇三:家庭网络进入千兆时代—小米路由器4开箱及评测...
  15. Ted英语单词-A brief history of alcohol
  16. Torvalds的linux
  17. scrcpy替换minicap
  18. mysql命令查看表内容
  19. POI导出Excel(二)
  20. outlook删除特定年份邮件_Outlook中删除只保留30天邮件文件夹

热门文章

  1. 什么是数据驱动测试?学习创建框架
  2. ESP8266使用MQTT接入阿里IoT
  3. SXT:聚合与组合的理解
  4. 如何使用node.js后端框架中的egg.js框架
  5. matlab距离平方和公式推导,lstopt 非线性拟合:相关系数之平方(R^2)和决定系数(DC)计算公式是?...
  6. 靠着“反转”设计,这些短视频火了
  7. 【动态】码绘VS手绘的对比——有点萌的开关
  8. ONF执行主席Dan Pitt:SDNFV会聚而合
  9. matlab emd功率谱密度,基于EMD方法的地心运动时间序列分析
  10. The slave I/O thread stops because master and slave have equal MySQL server UUID