前几天在做一个关于防护背心头盔安全帽检测数据集格式转化,数据集标签格式如下,分为训练集,测试集,验证集:
以测试集为例,打开测试集,格式如下:
数据集格式不是标准的 yolov5格式,测试集所有图像的标签都放在一个txt里面,第一个是图像名称,而且坐标是(xmin,ymin,xmax,ymax),即左上角和右下角坐标,最后一个是类别。
为了将数据集格式转换成yolov5类似的格式,即每张图像对应一个txt文件,并将所有的txt放在同一个labels目录下(train,test,valid合并到labels文件夹下),代码如下:
import os
# 1个txt转多个txt
label_num = os.listdir('Labels/Labels')
# i表示从train,test,valid等3个txt文件中取
for i in label_num:
f = open('Labels/Labels/'+i,'r')
data = f.readlines()
for j in data:
# 按' '分割txt的一行的内容,txt里面空格是中文的
line_data = j.strip().split(" ")
img_path = line_data[0].replace('.jpg','.txt')
with open('Labels/'+img_path,"w") as file:
file.write(j)
f.close()
处理后labels文件夹里的结果如下:
以第一张为例,image_from_china(1).txt里的结构:
然后对每个txt转换成xml格式:
# txt转换到xml
# ! /usr/bin/python
# -*- coding:UTF-8 -*-
import os
import cv2
def txt_to_xml(txt_path, img_path, xml_path):
# 字典对标签中的类别进行转换
dict = {'0': "hat",
'1': "vest",
'2': "person"
}
# 找到txt标签文件夹
files = os.listdir(txt_path)
# 遍历文件夹
for i, name in enumerate(files):
# 许多人文件夹里有该文件,默认的也删不掉,那就直接pass
if name == "desktop.ini":
continue
# 打开txt
txtFile = open(txt_path + name,'r')
# 读取所有内容
txtList = txtFile.readlines()
# 读取图片名称
img_name = name.split(".")[0]
pic = cv2.imread(img_path + img_name + ".jpg")
# 获取图像大小信息
Pheight, Pwidth, Pdepth = pic.shape
# 5.遍历txt文件中每行内容
for row in txtList:
# 按' '分割txt的一行的内容,我这里的是中文的空格
oneline = row.strip().split(" ")
# 6.新建xml文件
xml_file = open((xml_path + img_name + '.xml'), 'w')
xml_file.write('<annotation>\n')
xml_file.write(' <folder>VOC2007</folder>\n')
xml_file.write(' <filename>' + img_name + '.jpg' + '</filename>\n')
xml_file.write(' <source>\n')
xml_file.write(' <database>orgaquant</database>\n')
xml_file.write(' <annotation>organoids</annotation>\n')
xml_file.write(' </source>\n')
xml_file.write(' <size>\n')
xml_file.write(' <width>' + str(Pwidth) + '</width>\n')
xml_file.write(' <height>' + str(Pheight) + '</height>\n')
xml_file.write(' <depth>' + str(Pdepth) + '</depth>\n')
xml_file.write(' </size>\n')
xml_file.write(' <segmented>0</segmented>\n')
for data_line in oneline[1:]:
data = data_line.split(',')
xml_file.write(' <object>\n')
xml_file.write(' <name>' + dict[data[4]] + '</name>\n')
xml_file.write(' <pose>Unspecified</pose>\n')
xml_file.write(' <truncated>0</truncated>\n')
xml_file.write(' <difficult>0</difficult>\n')
xml_file.write(' <bndbox>\n')
xml_file.write(' <xmin>' + str(
int(float(data[0]))) + '</xmin>\n')
xml_file.write(' <ymin>' + str(
int(float(data[1]))) + '</ymin>\n')
xml_file.write(' <xmax>' + str(
int(float(data[2]))) + '</xmax>\n')
xml_file.write(' <ymax>' + str(
int(float(data[3]))) + '</ymax>\n')
xml_file.write(' </bndbox>\n')
xml_file.write(' </object>\n')
xml_file.write('</annotation>')
xml_file.close()
print("Done !")
# 修改成自己的文件夹 注意文件夹最后要加上/
txt_to_xml("Labels/","Images/Images/","XML/")
以上就完成了到xml格式的转化。
最后说明一下,我这里的转换的txt格式也不是yolov5的标准格式。yolov5的格式如下:
每行第1元素代表类别,第2,3表示目标框的中心位置,第4,5表示目标框的大小。而且都是归一化后的结果。归一化除以的是图像的w,h。