本文针对用yolov5训练安全帽数据集,由于初始的安全帽数据集数据较少,因此我找了三个数据集进行了融合,其中两个数据集的xml文件中分别以’0’,'1’代表没戴安全帽和戴安全帽,另一个数据集通过‘white’,‘red’,‘blue’等颜色来表示戴了安全帽以及安全帽的颜色,‘none’来表示没有带。
第一种xml格式如下图:
第二种如下:
除此之外,还有一些问题比如不同的数据及都是用数字来命名的,因此会重名,yolov5需要的信息是x,y,w,h,xml中提供的是x1,y1,x2,y2,那么我们如何解决呢 ?
第一步:对不同的数据集进行改名,将本代码和数据集文件夹放在同一文件下,并且我的数据集中图片和xml标注文件都是放在一起的,这样操作更方便点
import os
# 1. 获取一个要重命名的文件夹的名称:
folder_name = "anquanmao/"
# 2. 获取那个文件夹中所有的文件名字:
file_names = os.listdir(folder_name)
# 3. 循环用新名字代替旧名字(xml)
for name in file_names:
if name.split('.')[-1] == 'xml':
old_file_name = os.path.join(folder_name, name)
#这里我选择在其中一个数据集图片名称前边加上‘new’,大家可以根据需要自己修改
new_file_name = os.path.join(folder_name, 'new'+ name.split('.')[0].split('_')[0]+'.xml')
os.rename(old_file_name, new_file_name)
# 4. 循环用新名字代替旧名字(jpg)
if name.split('.')[-1] == 'jpg':
old_file_name = os.path.join(folder_name, name)
new_file_name = os.path.join(folder_name, 'new'+ name.split('.')[0].split('_')[0]+'.xml')
os.rename(old_file_name, new_file_name)
另一个数据集用同样的方式处理,然后我们就可以将三个数据集放在一起啦,注意是全部(包括图片和xml标注文件),然后生成训练需要的txt文件。
import glob
import os
xml_path = 'your_path'
#定义从xml获取信息的函数
def _read_anno(filename):
import xml.etree.ElementTree as ET
tree = ET.parse(filename)
#获取宽w和高h
a = tree.find('size')
w,h = [int(a.find('width').text),
int(a.find('height').text)]
objects = []
#这里是针对错误xml文件,图片的w和h都为0,这样的xml文件可以直接忽视,返回空列表
if w == 0:
return []
#这里需要根据需要修改,因为我训练的目的是判断是否戴了头盔,因此从xml获取的name为none或者0的label都为0,其他的颜色或者1都为1
for obj in tree.findall('object'):
#获取name,我上边的实例图片中的红色区域
name = obj.find('name').text
#修改label,这里是不同数据集大融合的关键
if name == 'none' or name == 0:
label = 0
else:
label = 1
#读取检测框的左上、右下角点的坐标
bbox = obj.find('bndbox')
x1, y1, x2, y2 = [int(bbox.find('xmin').text),
int(bbox.find('ymin').text),
int(bbox.find('xmax').text),
int(bbox.find('ymax').text)]
#这里也很关键,yolov5需要中心点以及宽和高的标注信息,并且进行归一化,下边label后边的四个值即是归一化后保留4位有效数字的x,y,w,h
obj_struct = [label,round((x1+x2)/(2.0*w),4), round((y1+y2)/(2.0*h),4), round((x2-x1)/(w),4),round((y2-y1)/(h),4)]
objects.append(obj_struct)
return objects
#接下来是写入txt文件中
if __name__ == '__main__':
#定义一个空的字符串
t = ''
#获取所有的xml文件路径
allfilepath = []
for file in os.listdir(xml_path):
if file.endswith('.xml'):
file = os.path.join(xml_path,file)
allfilepath.append(file)
else:
pass
#生成需要的对应xml文件名的txt
for file in allfilepath:
txt_path = file.split('.')[0] + '.txt'
result = _read_anno(file)
#跳过空列表
if len(result)==0:
continue
#写入信息,注意每次循环结束都把t重新定义,result是一个二维列表(行数为目标个数,列对应label和位置信息),为了避免读取出错(还有一个原因是我菜),我们一个一个的写入。
with open(txt_path,'w') as f:
for line in result:
for a in line:
t = t+str(a)+' '
f.writelines(t)
f.writelines('\n')
t =''
ok,txt文件都已经生成了,之后我会再写一个生成训练集train.txt和验证集val.txt的代码