yolov5使用自己的数据集相关代码

前言

yolov5已经很成熟了,作为一个拥有发展系列的检测器,它拥有足够的精度和满足现实中实时性要求,所以许多项目和比赛都能用的上,自己也拿来参加过比赛。
这里整理和分享下,自己搜集和修改的voc和coco格式转yolo格式的代码

yolo格式的数据集准备

1.voc格式转yolo

如果自己的数据集是voc格式的数据集。里面包含文件xml和jpg文件。voc转yolo格式的所有需要和生成的文件如图所示:
在这里插入图片描述
(1)Annotations:保存voc格式xml文件的文件夹,名称不重要,修改下面代码的输入就行
(2) images:保存的数据集图片,复制过来就行,名字就要是images!!!不然就要到数据预处理的代码里修改,较麻烦,建议就这样。
(3)ImageSets:划分训练集,验证集和测试集的txt文件夹
(4) labels:训练和验证集的labels(就是自己数据集对应的所有labels),同images一样,名字就要是labels!!!
(5)train,val,test.txt:里面写入的是读取的图片绝对路径(下面代码里可以改成相对路径,有些情况相对路径好像更好

首先,我们对数据集进行划分,ImageSets下生成的文件如图所示:
在这里插入图片描述

  • 划分数据集代码:split_train_val.py
import os
import random
# import argparse
#	终端输入路径,设置了默认路径,修改成机子的路径即可
parser = argparse.ArgumentParser()
parser.add_argument('--xml_path', default='/data/datasets/yolo/Annotations',type=str, help='input xml label path')
parser.add_argument('--txt_path', default='/data/datasets/yolo/ImageSets/Main',type=str, help='output txt label path')
# opt = parser.parse_args()
# xml_path = '/data/datasets/yolo/Annotations' # xml文件保存路劲
# txt_path = '/data/datasets/yolo/ImageSets/Main'  # 划分数据集文件的保存路径
trainval_percent = 1.0
train_percent = 0.9
xmlfilepath = xml_path
txtsavepath = txt_path
total_xml = os.listdir(xmlfilepath)  
if not os.path.exists(txtsavepath):
  os.makedirs(txtsavepath)

num=len(total_xml)
list=range(num)

ftrainval = open(txtsavepath + '/trainval.txt', 'w')
ftest = open(txtsavepath + '/test.txt', 'w')
ftrain = open(txtsavepath + '/train.txt', 'w')
fval = open(txtsavepath + '/val.txt', 'w')

for i in list:
    name=total_xml[i][:-4]+'\n'
    ftrainval.write(name)
    if i >= int(num*train_percent):  # 给定的val占比
        fval.write(name)
    else:
        ftrain.write(name)	# 这里只给了训练和验证集的,测试的为0,如果
							# 想要测试的,自己写个判断语句就行
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

其次,因为yolo读取数据集的格式:
1.数据集训练集,验证集读取图片路径(tain.txt文件)
2.数据集labels(图片名称.txt文件)
所以,接下来对划分的训练集和验证集生成对应的labels.
1,2步骤如图所示:
在这里插入图片描述
在这里插入图片描述

  • 创建labels代码:voc_label.py
    这里txt,文件里保存图片读取路径。可以绝对路径和相对路径。
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join

sets=['train', 'val', 'test']	# 划分的数据集名称,测试集一般不给
classes = ["seaurchin","seacucumber","scallop"] # 类别名

abs_path = os.getcwd()
def convert(size, box):  
    dw = 1./(size[0])  # dw,dh除以原始图像的尺寸
    dh = 1./(size[1])
    x = (box[0] + box[1])/2.0 - 1  # yolo的格式中心坐标-1
    y = (box[2] + box[3])/2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x*dw   # 归一化
    w = w*dw
    y = y*dh
    h = h*dh
    return (x,y,w,h)
def convert_annotation(image_id):
    in_file = open('/data/datasets/yolo/Annotations/%s.xml'%( image_id))
    out_file = open('/data/datasets/yolo/labels/%s.txt'%(image_id), 'w')  
    tree=ET.parse(in_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').text
        cls = obj.find('name').text
        if cls not in classes :
            continue
        cls_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))
        bb = convert((w,h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

if __name__ == '__main__':

    for image_set in sets:
        if not os.path.exists('/data/datasets/yolo/labels/'):
            os.makedirs('/data/datasets/yolo/labels/')
        image_ids = open('/data/datasets/yolo/ImageSets/Main/%s.txt'%(image_set)).read().strip().split()
        list_file = open('/data/datasets/yolo/%s.txt'%(image_set), 'w')
        for image_id in image_ids:
       		 # 写入绝对路径,
            list_file.write('/data/datasets/yolo/images/%s.jpg\n'%(image_id))  
            #相对路径这样写
            # list_file.write('./images/%s.jpg\n' % (image_id)) 
            convert_annotation(image_id)
        list_file.close()

2.coco格式转yolo

COCO 格式的数据集转化为 YOLO 格式的数据集
coco格式一般会给你划分好训练,验证集,这里就不进行数据集划分了。直接生成labels。
这里会生成一个classes.txt,表示数据集的类别数(如不需要可以不生成):
在这里插入图片描述

  • 生成数据集的labels代码:这里生成什么数据集就把相应的json文件输入,不如train.json和val.json。
import os
import json
from tqdm import tqdm
import argparse

# --json_path 输入的json文件路径
# --save_path 保存的文件夹名字,默认为当前目录下的labels。
parser = argparse.ArgumentParser()
#这里根据自己的json文件位置,换成自己的就行
parser.add_argument('--json_path', default='train/annotations/trainall.json',type=str, help="input: coco format(json)")
#这里设置.txt文件保存位置
parser.add_argument('--save_path', default='datasets/yolo_underwater/labels', type=str, help="specify where to save the output dir of labels")
arg = parser.parse_args()

def convert(size, box): # size:图像大小
    dw = 1. / (size[0])
    dh = 1. / (size[1])
    x = box[0] + box[2] / 2.0
    y = box[1] + box[3] / 2.0
    w = box[2]
    h = box[3]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
#round函数确定(xmin, ymin, xmax, ymax)的小数位数
    # x = round(x * dw, 6)
    # w = round(w * dw, 6)
    # y = round(y * dh, 6)
    # h = round(h * dh, 6)
    return (x, y, w, h)

if __name__ == '__main__':
    json_file = arg.json_path # COCO Object Instance 类型的标注
    ana_txt_save_path = arg.save_path  # 保存的路径

    data = json.load(open(json_file, 'r'))
    if not os.path.exists(ana_txt_save_path):
        os.makedirs(ana_txt_save_path)

    id_map = {
    
    } # coco数据集的id不连续!重新映射一下再输出!
    with open(os.path.join(ana_txt_save_path,'classes.txt'), 'w') as f:
        # 写入classes.txt
        for i, category in enumerate(data['categories']):
            f.write(f"{
      
      category['name']}\n")
            id_map[category['id']] = i
    # print(id_map)
    #这里需要根据自己的需要,更改写入图像相对路径的文件位置。
    list_file = open(os.path.join(ana_txt_save_path,'train.txt'), 'w')
    for img in tqdm(data['images']):
        filename = img["file_name"]
        img_width = img["width"]
        img_height = img["height"]
        img_id = img["id"]
        head, tail = os.path.splitext(filename)
        ana_txt_name = head + ".txt"  # 对应的txt名字,与jpg一致
        f_txt = open(os.path.join(ana_txt_save_path, ana_txt_name), 'w')
        for ann in data['annotations']:
            if ann['image_id'] == img_id:
                box = convert((img_width, img_height), ann["bbox"])
                f_txt.write("%s %s %s %s %s\n" % (id_map[ann["category_id"]], box[0], box[1], box[2], box[3]))
        f_txt.close()
        #将图片的相对路径写入
        list_file.write('./images/%s.jpg\n' %(head)) # bmp,jpg
    list_file.close()

制作自己数据集的yaml文件

在前面将自己的数据集转换成yolo的格式之后,还要在yolov5-master/data的文件下,创建自己的数据集的.yaml文件,如下图所示:

在这里插入图片描述
给出自己生成训练和验证数据集的路径,同时给出类别数量和类别名称。这样后面就可以利用自己的数据集在yolov5上进行训练了。

总结

yolov5网络结构部分见:https://editor.csdn.net/md/?articleId=127169478

猜你喜欢

转载自blog.csdn.net/weixin_41311686/article/details/125210057