目标检测小白笔记系列~数据集的数据集的转换VOC2YOLOV4,YOLOV5官方数据集形式

本文的内容结构

本文内容分为2个部分,
第一部分介绍各个版本yolo使用的数据集的情况及3个转换代码,有经验的可以直接取用。
第二部分是详细转换教程适合没有经验的小白朋友,按照说明无脑操作就行
PS:本文中文件夹结构是一句url1中来的
url1:https://github.com/bubbliiiing/yolov4-pytorch
url2:https://blog.csdn.net/qq_45359151/article/details/107591434?utm_medium=distribute.pc_relevant.none-task-blog-baidulandingword-2&spm=1001.2101.3001.4242

在yolo各个版本中使用的略有不同

yolov4,v5可用的数据形式比较多。
YOLOV4:
例如url1中是yolov4网络,使用的是xml格式转换的(详见VOCdevkit中的voc2yolo4.py)
url1:https://github.com/bubbliiiing/yolov4-pytorch

YOLOV5:
对于yolov5要特殊说面下,支持3种数据读取方式的(应该说coco.yaml支持)
在这里插入图片描述
网上转换的大多是第二种,但是由于未知原因,第二种方法转换出来的数据我总是报错。所以我索性在此基础上写了个小程序,转化成第一种形式,因为V5作者用的是这种形式所以在这里称为官方形式。
第一种形式的转换:
官方是这种文件中train与valid下images/labels拆开的形式,下图是我自己的ship是数据集,问了个大神他也推荐官方这种方式。详细转换过程看本文第二部分
在这里插入图片描述

第二种形式的转换:
url2中是yolov5网络,使用的是txt格式(需要两次转化),可以看到第一个make_txt.py其实就上面的voc2yolo4.py,第二个是2voc_label.py(本文中称为voc2yolo5)
PS:本文中文件夹结构是一句url1中来的

url2:https://blog.csdn.net/qq_45359151/article/details/107591434?utm_medium=distribute.pc_relevant.none-task-blog-baidulandingword-2&spm=1001.2101.3001.4242

voc2yolo4.py

# reference:https://blog.csdn.net/qq_45359151/article/details/107591434?utm_medium=distribute.pc_relevant.none-task-blog-baidulandingword-2&spm=1001.2101.3001.4242
import os
import random 
#读取路径查看然后修改相对路径
wd = os.getcwd()
print(wd)
xmlfilepath='Annotations' #mark,标签读取地址
saveBasePath="ImageSets/Main/"#mark存放都着急哦
 
trainval_percent=0.9 #测试集比例(10%),如果有另外单独的测试集则设为1,则表示该目录下所有的数据皆为测试集
train_percent=1

temp_xml = os.listdir(xmlfilepath)
total_xml = []
for xml in temp_xml:
    if xml.endswith(".xml"):
        total_xml.append(xml)

num=len(total_xml)  
list=range(num)  
tv=int(num*trainval_percent)  
tr=int(tv*train_percent)  
trainval= random.sample(list,tv)  
train=random.sample(trainval,tr)  
 
print("train and val size",tv)
print("traub suze",tr)
ftrainval = open(os.path.join(saveBasePath,'trainval.txt'), 'w')  
ftest = open(os.path.join(saveBasePath,'test.txt'), 'w')  
ftrain = open(os.path.join(saveBasePath,'train.txt'), 'w')  
fval = open(os.path.join(saveBasePath,'val.txt'), 'w')  
 
for i  in list:  
    name=total_xml[i][:-4]+'\n'  
    if i in trainval:  
        ftrainval.write(name)  
        if i in train:  
            ftrain.write(name)  
        else:  
            fval.write(name)  
    else:  
        ftest.write(name)  
  
ftrainval.close()  
ftrain.close()  
fval.close()  
ftest .close()

voc2yolo5.py(其实就是2voc_label.py)

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets = ['train', 'test','val']
classes = ['ship'] #需要更改
def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    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('Annotations/%s.xml' % (image_id)) #需要更改
    out_file = open('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 or int(difficult) == 1:
            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')
wd = getcwd()
print(wd)
for image_set in sets:
    if not os.path.exists('labels/'):
        os.makedirs('labels/')
    image_ids = open('ImageSets/Main/%s.txt' % (image_set)).read().strip().split() #需要更改
    list_file = open('%s_sets_directory.txt' % (image_set), 'w')
    labels_list_file = open('%s_labels_directory.txt' % (image_set), 'w')
    for image_id in image_ids:
        list_file.write('images/%s.jpg\n' % (image_id))
        labels_list_file.write('labels/%s.txt\n' % (image_id))
        convert_annotation(image_id)
    list_file.close()
    labels_list_file.close()

03get_pic_label.py(转移图片和label)

import os
import shutil

# ------------------------------------------------------------------
# @function:将images和labels对应文件放入对应的train和valid下
# @autor:hongqing.wang
# @comment:
    #代码测试时通过的,如果出问题一般都是路径问题
# ------------------------------------------------------------------

#打印当前路径
wd = os.getcwd()
print(wd)

#取出对应文件放入对应文件
def get_picture_labels(object_directry, target_directoty):
    print('the direct is \" {} \"'.format(os.getcwd()))
    '''
    open & read content of the specific diretory
    '''
    with open(object_directry) as  f:  # mark1,根据输出的地址调节
        name_result = f.readlines()
        for i, str in enumerate(name_result):
            name_result[i] = (str.replace('\n', ''))
            # print('now  i is {},str is {}'.format(i , str)) #用于显示文件名或调试
            shutil.move(name_result[i], target_directoty)
    print((name_result))
    print('*********************************the type of name_result is {}*********************************'.format(type(name_result)))
    print('*********************************the trsnsfer is done*********************************')
    print('*********************************the trsnsfer is done*********************************')
    print('*********************************the trsnsfer is done*********************************')
    print('*********************************the trsnsfer is done*********************************')
    print('*********************************the trsnsfer is done*********************************')


def main():
    '''
    #transfer train pic
    '''
    object_directry = './train_sets_directory.txt'
    img_target_directoty = './ship/train/images'
    get_picture_labels(object_directry, img_target_directoty)
    '''
    #transfer vaild pic
    '''
    object_directry = './test_sets_directory.txt'
    img_target_directoty = './ship/valid/images'
    get_picture_labels(object_directry, img_target_directoty)
    '''
    #transfer train label
    '''
    object_directry = './train_labels_directory.txt'
    img_target_directoty = './ship/train/labels'
    get_picture_labels(object_directry, img_target_directoty)
    '''
    #transfer valid label
     '''
    object_directry = './test_labels_directory.txt'
    img_target_directoty = './ship/valid/labels'
    get_picture_labels(object_directry, img_target_directoty)


if __name__ == '__main__':
    main()

官方数据格式转换教程

在这里插入图片描述

step1:下载我的代码(or自己建立如上图文件结构,注意此时文件夹都是空的)
https://github.com/hellogithubsir/data_transfer.git
step2:路径中把VOC数据形式的标签放入Annotations,图片放入images中
step3:运行01,02,03后,
最后:my_datasets就是最后我们要的数据文件夹,“my_datasets”文件夹名字改成你自己要的
PS:因为懒得考虑多种意外形式,没做容错处理,但是只要按照我步骤来就没问题。如果真的出来什么问题文件结构如上图所示重来一次就不会出错,公司里也一直用的是这个程序。

下面演示流程及对应输出结果:
step1:下载我的代码(or自己建立如上图文件结构,注意此时文件夹都是空的)
在这里插入图片描述
step2:路径中把VOC数据形式的标签放入Annotations,图片放入images中,“my_datasets”文件夹名字改成你自己的
可以看到已经由空的编程可以文件展开的形式,这里图片太多所以没在载入完我就截图了
在这里插入图片描述

step3
运行01,在main文件夹下出现了4个txt
在这里插入图片描述
运行02后
出现了6个txt,其中*_sets_directory.txt就是第一部分中提到的YOLOV5支持的第二种形式,就是很多教程中的train.txt,test.txt,个人认为很容易与main中的同名文件混淆,所以我这里改了。
在这里插入图片描述

运行03后
可以看见my_datasets下的空文件夹编程了可展开的形式,“my_datasets”实际中根据自己需求改名字,它就是最后我们要的数据集,直接移走使用就行。
PS:我这里是将images和labels的文件移动到对应文件家下,如果想保留的话将03代码26行的move改为copy就行了
在这里插入图片描述

版权声明:本文为CSDN博主「一天天的就知道学习」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35679701/article/details/109988372

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

object detection with faster rCNN

Proposal and CropAndResize
1 custom plugin
config.py 是为convert_to_uff 命令定义的。config.py文件中应该通过修改op字段将自定义层映射到TensorRT中的插件名称