百度网盘链接:https://pan.baidu.com/s/12x2t-EYbRC6q2IqqiznZVQ?pwd=LIIB
提取码:LIIB
环境搭建网上搜一下,cuda cudnn nvidia驱动 anconda pytorch
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
pytorch 安装与cuda驱动一致的版本
图片放在my_data的images下
标注xml数据将文件放my_data的Annotations下运行xml_txt.py
标注txt文件直接将结果放在my_data的labels(xml文件最终是要转为txt的,所以上面在转换)
上述结束运行my_data下的data.py将数据集划分为3组 放置在VOCData文件下
回到yolov7下运行:
//训练用
python train.py --weights ./yolov7.pt --cfg ./cfg/training/yolov7.yaml --data ./myvoc.yaml --device 0 --batch-size 4 --epoch 300
//训练结束测试用
python detect.py --weigths ./runs/train/exp24/weights/best.pt --source ./VOCData/1/
1.数据集xml文件转txt格式 xml_data.py
import glob
import os
# xml文件的路径
xml_path = './Annotations/'
#定义从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)]
#print(w,h)
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 == 'head':
label = 0
elif name == 'trail':
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)]
print(obj_struct)
objects.append(obj_struct)
return objects
#接下来是写入txt文件中
if __name__ == '__main__':
#定义一个空的字符串
t = ''
# txt文件存放的路径
txt_path = "./labels/"
#获取所有的xml文件路径
allfilepath = []
for file in os.listdir(xml_path):
if file.endswith('.xml'):
file = os.path.join(xml_path,file)
allfilepath.append(file)
# print(allfilepath)
else:
pass
#生成需要的对应xml文件名的txt
for file in allfilepath:
print("file", file)
#获取xml的文件名
filename = file.split('/')[2]
indexname = filename.split('.')[0]
# print('indexname', indexname)
result = _read_anno(file)
# print('result', result)
#跳过空列表
if len(result)==0:
continue
#写入信息,注意每次循环结束都把t重新定义,result是一个二维列表(行数为目标个数,列对应label和位置信息),为了避免读取出错(还有一个原因是我菜),我们一个一个的写入。
txtfile = open(os.path.join(txt_path,indexname+'.txt'), 'w')
for line in result:
for a in line:
# print('a', a)
t = t + str(a) + ' '
# print('t', t)
txtfile.writelines(t)
t = ''
txtfile.writelines('\n')
2.创建训练data.py
# 将图片和标注数据按比例切分为 训练集和测试集
import shutil
import random
import os
# 原始路径
image_original_path = "./images/"
label_original_path = "./labels/"
cur_path = os.getcwd()
# 训练集路径
train_image_path = os.path.join(cur_path, "../VOCData/images/train/")
train_label_path = os.path.join(cur_path, "../VOCData/labels/train/")
# 验证集路径
val_image_path = os.path.join(cur_path, "../VOCData/images/val/")
val_label_path = os.path.join(cur_path, "../VOCData/labels/val/")
# 测试集路径
test_image_path = os.path.join(cur_path, "../VOCData/images/test/")
test_label_path = os.path.join(cur_path, "../VOCData/labels/test/")
# 训练集目录
list_train = os.path.join(cur_path, "../VOCData/train.txt")
list_val = os.path.join(cur_path, "../VOCData/val.txt")
list_test = os.path.join(cur_path, "../VOCData/test.txt")
train_percent = 0.6
val_percent = 0.2
test_percent = 0.2
def del_file(path):
for i in os.listdir(path):
file_data = path + "\\" + i
os.remove(file_data)
def mkdir():
if not os.path.exists(train_image_path):
os.makedirs(train_image_path)
else:
del_file(train_image_path)
if not os.path.exists(train_label_path):
os.makedirs(train_label_path)
else:
del_file(train_label_path)
if not os.path.exists(val_image_path):
os.makedirs(val_image_path)
else:
del_file(val_image_path)
if not os.path.exists(val_label_path):
os.makedirs(val_label_path)
else:
del_file(val_label_path)
if not os.path.exists(test_image_path):
os.makedirs(test_image_path)
else:
del_file(test_image_path)
if not os.path.exists(test_label_path):
os.makedirs(test_label_path)
else:
del_file(test_label_path)
def clearfile():
if os.path.exists(list_train):
os.remove(list_train)
if os.path.exists(list_val):
os.remove(list_val)
if os.path.exists(list_test):
os.remove(list_test)
def main():
mkdir()
clearfile()
file_train = open(list_train, 'w')
file_val = open(list_val, 'w')
file_test = open(list_test, 'w')
total_txt = os.listdir(label_original_path)
num_txt = len(total_txt)
list_all_txt = range(num_txt)
num_train = int(num_txt * train_percent)
num_val = int(num_txt * val_percent)
num_test = num_txt - num_train - num_val
train = random.sample(list_all_txt, num_train)
# train从list_all_txt取出num_train个元素
# 所以list_all_txt列表只剩下了这些元素
val_test = [i for i in list_all_txt if not i in train]
# 再从val_test取出num_val个元素,val_test剩下的元素就是test
val = random.sample(val_test, num_val)
print("训练集数目:{}, 验证集数目:{}, 测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))
for i in list_all_txt:
name = total_txt[i][:-4]
srcImage = image_original_path + name + '.jpg'
srcLabel = label_original_path + name + ".txt"
if i in train:
dst_train_Image = train_image_path + name + '.jpg'
dst_train_Label = train_label_path + name + '.txt'
shutil.copyfile(srcImage, dst_train_Image)
shutil.copyfile(srcLabel, dst_train_Label)
file_train.write(dst_train_Image + '\n')
elif i in val:
dst_val_Image = val_image_path + name + '.jpg'
dst_val_Label = val_label_path + name + '.txt'
shutil.copyfile(srcImage, dst_val_Image)
shutil.copyfile(srcLabel, dst_val_Label)
file_val.write(dst_val_Image + '\n')
else:
dst_test_Image = test_image_path + name + '.jpg'
dst_test_Label = test_label_path + name + '.txt'
shutil.copyfile(srcImage, dst_test_Image)
shutil.copyfile(srcLabel, dst_test_Label)
file_test.write(dst_test_Image + '\n')
file_train.close()
file_val.close()
file_test.close()
if __name__ == "__main__":
main()