转化Foggy_Cityscapes数据集为voc和yolo格式用作目标检测

目录

一、数据集下载

(1)解压后文件夹目录

(2)gtFine格式如下所示:

二、转换为VOC数据集格式

(1)生成xml标签

 (2)将leftImg8bit生成的xml标签转换为leftImg8bit_foggy版本的

(3)将leftImg8bit_foggy中的图片拷贝到JPEGImages中

(4)执行Main.py文件划分数据集train/val/test

(5)训练时首先执行voc_annotation获得txt图片路径文件

三、转换为yolo数据集格式

(1)将原版Cityscapes数据集leftImg8bit转换为yolo格式

(2)转换为foggy版yolo


一、数据集下载

数据集下载地址:https://www.cityscapes-dataset.com/downloads/

 进入下载官网后,我们首先下载上方箭头标注的两个文件,然后再往下滑下载已经转换为雾天环境的数据集

数据集的种类classes:

'''
    ['rectification border', 'road', 'sidewalk', 'car', 'sky', 'terrain', 'building', 'vegetation', 'pole', 
    'traffic sign', 'static', 'bicycle', 'person', 'license plate', 'rider', 'ground', 'traffic light', 
    'dynamic', 'wall', 'cargroup', 'fence', 'bicyclegroup', 'motorcycle', 'parking', 'persongroup', 
    'bus', 'bridge', 'trailer', 'polegroup', 'tunnel', 'caravan', 'truck', 'guard rail', 'rail track', 
    'train', 'motorcyclegroup', 'ridergroup', 'truckgroup'] 38
    纠正边界、道路、人行道、汽车、天空、地形、建筑物、植被、杆子、,
    ‘交通标志’、‘静态’、‘自行车’、‘人’、‘车牌’、‘骑手’、‘地面’、‘交通灯’,
    “动态”、“墙”、“车组”、“围栏”、“自行车组”、“摩托车”、“停车场”、“个人组”,
    “公共汽车”、“桥梁”、“拖车”、“极群”、“隧道”、“大篷车”、“卡车”、“护栏”、“轨道”,
    “火车组”、“摩托车组”、“骑行组”、“卡车组”
    '''

其中test测试数据集在gtFine的txt标签文件中没有上面种类标签,只在gtFine的json中有下面两个标签信息

'out of roi', 'ego vehicle'

(1)解压后文件夹目录

然后分别将三个文件解压到将其内部文件夹放在同一个文件夹中,pycharm目录如下

文件夹leftImg8bit_trainvaltest/leftImg8bit:分train/val/test三个文件夹,每个文件夹下按城市分子文件夹,每个城市文件夹下就是png图像

文件夹leftImg8bit_trainvaltest_foggy/leftImg8bit_foggy:foggy_cityscapes没有标签,可以直接使用cityscapes的标签;

对应关系:
                cityscapes的一张原图对应到foggy_cityscapes中有3张图,
                beta=[0.005,0.01,0.02],分别进行转换可以得到3个foggy_cityscapes数据集。

(2)gtFine格式如下所示:


文件夹gtFine_trainvaltes/gtFine:先分train/val/test三个文件夹,每个文件夹下又按城市分子文件夹,每个城市文件夹下针对每张源图png文件对应了4张标注文件:

注意:gtFine文件夹中只对train和val文件夹中的图片进行了标注,test中是没有标注的,所以test中的图片我们是不能使用的

 其中的json和txt文件包含了我们所需的标注信息

二、转换为VOC数据集格式

(1)生成xml标签

1.首先在CityScape目录下创建空的VOC数据集格式文件夹,用于存放我们生成的对应文件

  2.然后执行项目目录下的convert_to_xml.py代码生成xml标注文件

执行完后Annotations目录下就会生成Cityscapes也就是leftImg8bit图片对应的xml标注信息

 注意程序中根据选择选取了需要用到的类别标出信息,不用的就去除

我选取的类型

 (2)将leftImg8bit生成的xml标签转换为leftImg8bit_foggy版本的

首先新建一个文件夹annotations_foggy存放转换之后的xml文件,再执行代码to_voc_foggy.py

生成之后将原Annotations文件夹删除,annotations_foggy文件夹更名为Annotations

 因为foggy版本是在原版本的每一张图上扩充为三倍的,所以转换后的xml文件是原来的三倍,且xml文件名也转化为对应foggy图片的名字。

一开始生成的xml文件名是没有_foggy_beta_0.01/0.02/0.005的

(3)将leftImg8bit_foggy中的图片拷贝到JPEGImages中

执行create_foggy_JPEGimages.py完成图片拷贝

注意:因为test没有对应标签,我们只用到了原数据集中的train和val文件夹下的图片,所以我们只需要拷贝这两个文件夹下的图片即可

 拷贝完成

(4)执行Main.py文件划分数据集train/val/test

当然我们也可以跳过这步等到要训练时去直接执行根目录下的voc_annotation

 数据集的分配比例可以自己调节

"""
function: create train.txt and test.txt in ImageSets\Main
"""
import os
import random

trainval_percent = 0.8  # 可自行进行调节(这里设置训练:验证:测试的比例是6:2:2)
train_percent = 3/4
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
total_xml = os.listdir(xmlfilepath)

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)

ftrainval = open('ImageSets/Main/trainval.txt', 'w')
ftest = open('ImageSets/Main/test.txt', 'w')
ftrain = open('ImageSets/Main/train.txt', 'w')
fval = open('ImageSets/Main/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()

(5)训练时首先执行voc_annotation获得txt图片路径文件

代码中数据集的划分默认训练集占0.9*0.9=0.81,验证集0.9*0.1=0.09,测试集0.1,如果Main文件下已经划分好了,那么我们只需要修改annotation_mode = 2生成图片路径txt文件即可

import os
import random
import xml.etree.ElementTree as ET

import numpy as np

#from utils import get_classes


#--------------------------------------------------------------------------------------------------------------------------------#
#   annotation_mode用于指定该文件运行时计算的内容
#   annotation_mode为0代表整个标签处理过程,包括获得VOCdevkit/VOC2007/ImageSets里面的txt以及训练用的2007_train.txt、2007_val.txt
#   annotation_mode为1代表获得VOCdevkit/VOC2007/ImageSets里面的txt
#   annotation_mode为2代表获得训练用的2007_train.txt、2007_val.txt
#--------------------------------------------------------------------------------------------------------------------------------#
annotation_mode     = 0
#-------------------------------------------------------------------#
#   必须要修改,用于生成2007_train.txt、2007_val.txt的目标信息
#   与训练和预测所用的classes_path一致即可
#   如果生成的2007_train.txt里面没有目标信息
#   那么就是因为classes没有设定正确
#   仅在annotation_mode为0和2的时候有效
#-------------------------------------------------------------------#
classes_path        = 'model_data/foggy_classes.txt'
#--------------------------------------------------------------------------------------------------------------------------------#
#   trainval_percent用于指定(训练集+验证集)与测试集的比例,默认情况下 (训练集+验证集):测试集 = 9:1
#   train_percent用于指定(训练集+验证集)中训练集与验证集的比例,默认情况下 训练集:验证集 = 9:1
#   仅在annotation_mode为0和1的时候有效
#--------------------------------------------------------------------------------------------------------------------------------#
trainval_percent    = 0.9
train_percent       = 0.9
#-------------------------------------------------------#
#   指向VOC数据集所在的文件夹
#   默认指向根目录下的VOC数据集
#-------------------------------------------------------#
VOCdevkit_path  = 'VOCdevkit'

VOCdevkit_sets  = [('2007', 'train'), ('2007', 'val')]

#---------------------------------------------------#
#   获得类
#---------------------------------------------------#
def get_classes(classes_path):
    with open(classes_path, encoding='utf-8') as f:
        class_names = f.readlines()
    class_names = [c.strip() for c in class_names]
    return class_names, len(class_names)

classes, _      = get_classes(classes_path)

#-------------------------------------------------------#
#   统计目标数量
#-------------------------------------------------------#
photo_nums  = np.zeros(len(VOCdevkit_sets))
nums        = np.zeros(len(classes))

def convert_annotation(year, image_id, list_file):
    in_file = open(os.path.join(VOCdevkit_path, 'VOC%s/Annotations/%s.xml'%(year, image_id)), encoding='utf-8')
    tree=ET.parse(in_file)
    root = tree.getroot()

    for obj in root.iter('object'):
        difficult = 0 
        if obj.find('difficult')!=None:
            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 = (int(float(xmlbox.find('xmin').text)), int(float(xmlbox.find('ymin').text)), int(float(xmlbox.find('xmax').text)), int(float(xmlbox.find('ymax').text)))
        list_file.write(" " + ",".join([str(a) for a in b]) + ',' + str(cls_id))
        
        nums[classes.index(cls)] = nums[classes.index(cls)] + 1
        
if __name__ == "__main__":
    random.seed(0)
    if " " in os.path.abspath(VOCdevkit_path):
        raise ValueError("数据集存放的文件夹路径与图片名称中不可以存在空格,否则会影响正常的模型训练,请注意修改。")

    if annotation_mode == 0 or annotation_mode == 1:
        print("Generate txt in ImageSets.")
        xmlfilepath     = os.path.join(VOCdevkit_path, 'VOC2007/Annotations')
        saveBasePath    = os.path.join(VOCdevkit_path, 'VOC2007/ImageSets/Main')
        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("train size",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()
        print("Generate txt in ImageSets done.")

    if annotation_mode == 0 or annotation_mode == 2:
        print("Generate 2007_train.txt and 2007_val.txt for train.")
        type_index = 0
        for year, image_set in VOCdevkit_sets:
            image_ids = open(os.path.join(VOCdevkit_path, 'VOC%s/ImageSets/Main/%s.txt'%(year, image_set)), encoding='utf-8').read().strip().split()
            list_file = open('%s_%s.txt'%(year, image_set), 'w', encoding='utf-8')
            for image_id in image_ids:
                list_file.write('%s/VOC%s/JPEGImages/%s.png'%(os.path.abspath(VOCdevkit_path), year, image_id))

                convert_annotation(year, image_id, list_file)
                list_file.write('\n')
            photo_nums[type_index] = len(image_ids)
            type_index += 1
            list_file.close()
        print("Generate 2007_train.txt and 2007_val.txt for train done.")
        
        def printTable(List1, List2):
            for i in range(len(List1[0])):
                print("|", end=' ')
                for j in range(len(List1)):
                    print(List1[j][i].rjust(int(List2[j])), end=' ')
                    print("|", end=' ')
                print()

        str_nums = [str(int(x)) for x in nums]
        tableData = [
            classes, str_nums
        ]
        colWidths = [0]*len(tableData)
        len1 = 0
        for i in range(len(tableData)):
            for j in range(len(tableData[i])):
                if len(tableData[i][j]) > colWidths[i]:
                    colWidths[i] = len(tableData[i][j])
        printTable(tableData, colWidths)

        if photo_nums[0] <= 500:
            print("训练集数量小于500,属于较小的数据量,请注意设置较大的训练世代(Epoch)以满足足够的梯度下降次数(Step)。")

        if np.sum(nums) == 0:
            print("在数据集中并未获得任何目标,请注意修改classes_path对应自己的数据集,并且保证标签名字正确,否则训练将会没有任何效果!")
            print("在数据集中并未获得任何目标,请注意修改classes_path对应自己的数据集,并且保证标签名字正确,否则训练将会没有任何效果!")
            print("在数据集中并未获得任何目标,请注意修改classes_path对应自己的数据集,并且保证标签名字正确,否则训练将会没有任何效果!")
            print("(重要的事情说三遍)。")

三、转换为yolo数据集格式

方法一:将已经转换好的voc数据集转化为yolo,参考我之前发布的yolov7训练本地VOC数据集,这里就不讲了

方法二:直接转换为yolo格式,但是这个方法的测试集的label标签信息是为空的,因为它没有标注信息

(1)将原版Cityscapes数据集leftImg8bit转换为yolo格式

执行代码convert_to_yolo将数据集转换为yolo格式

执行完代码后会在根目录生成如下文件,images中存放的是leftImg8bit中的图片,后面我们需要将其删除,替换为leftImg8bit_foggy的图片。label中存放leftImg8bit中图片标签信息,下一步我们要将其转换为foggy版的。classes.txt存放的我们需要用到的种类。下面三个txt文件存放数据集图片路径。

(2)转换为foggy版yolo

在父目录下新建一个foggyimage文件夹,存放foggy版本的图片

执行代码to_yolo_foggy.py完成foggy图片的复制以及foggy标签的转换 ,完成复制图片以及label转换为foggy版本之后将原来image文件夹删除,将foggyimage文件夹改名为image

猜你喜欢

转载自blog.csdn.net/Sciws/article/details/126528724
今日推荐