Kitti数据集的下载只需要一个图片集(12G)和标注文件即可(data_object_image_2.zip、data_object_label_2.zip)。
下载地址:http://dataset.f3322.net:666/share/kitti/
1、VOC格式数据集介绍
由于faster-rcnn使用的是VOC格式的数据集,所以我们要将kitti数据集的格式改成VOC的格式。这里我先简单说明一下VOC数据集的格式,便于大家对于转换程序的理解。
以VOC2007为例,其中包含了3个文件夹:
- JPEGImages是用来存放所有的训练图片的
- ImageSets中有多个子文件夹(Main,Layout,Segmentation),由于我只关心detection的任务(VOC数据集还可以用来做其他任务),所以我只需要考虑其中的Main文件夹,Main文件夹中的内容是一些txt文件,是用来标明训练的时候的train数据集和val数据集。
- Annotation是用来存放xml文件的,其中xml文件中包含了相对应的bounding box的位置信息,以及种类。xml文件的内容如下:
2、kitti数据集的格式
下载的kitti数据集分为两个压缩文件,其中一个是image里面全是交通场景图,另一个是label里面是关于标注信息的txt文件。txt文件内容如下:
每一行就是一个object,最前方是类别信息,后面是bounding box信息。
3、将kitti数据集转化为VOC数据集格式
(1)转换图片格式png->jpg
由于kitti使用的是png图片,而VOC使用的是jpg文件,使用格式工厂将png图片转化为jpg格式,之后将jpg图片放入JPEGImages文件夹(自己创建)。由于我只需要汽车类car和行人类pedesreian,于是我将kitti中的卡车等其他类别进行了合并代码modify_annotations_txt.py,将本程序和kitti的Labels放在同一目录下执行,可以将Labels中的类别合并为只剩下car类和pedestrian类。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # modify_annotations_txt.py import glob import string """ 将本程序和kitti的Labels放在同一目录下执行,可以将Labels中的类别合并为只剩下car类和pedestrian类(这里我使用小写是防止faster-rcnn训练报错)。 之后要把txt文件转化为xml文件,在相同目录下创建文件夹Annotations """ txt_list = glob.glob('./label_2/*.txt') # 存储Labels文件夹所有txt文件路径 def show_category(txt_list): category_list = [] for item in txt_list: try: with open(item) as tdf: for each_line in tdf: labeldata = each_line.strip().split(' ') # 去掉前后多余的字符并把其分开 category_list.append(labeldata[0]) # 只要第一个字段,即类别 except IOError as ioerr: print('File error:' + str(ioerr)) print(set(category_list)) # 输出集合 def merge(line): each_line = '' for i in range(len(line)): if i != (len(line) - 1): each_line = each_line + line[i] + ' ' else: each_line = each_line + line[i] # 最后一条字段后面不加空格 each_line = each_line + '\n' return (each_line) print('before modify categories are:\n') show_category(txt_list) for item in txt_list: new_txt = [] try: with open(item, 'r') as r_tdf: for each_line in r_tdf: labeldata = each_line.strip().split(' ') if labeldata[0] in ['Truck', 'Van', 'Tram', 'Car']: # 合并汽车类 labeldata[0] = labeldata[0].replace(labeldata[0], 'car') if labeldata[0] in ['Person_sitting', 'Cyclist', 'Pedestrian']: # 合并行人类 labeldata[0] = labeldata[0].replace(labeldata[0], 'pedestrian') if labeldata[0] == 'DontCare': # 忽略Dontcare类 continue if labeldata[0] == 'Misc': # 忽略Misc类 continue new_txt.append(merge(labeldata)) # 重新写入新的txt文件 with open(item, 'w+') as w_tdf: # w+是打开原文件将内容删除,另写新内容进去 for temp in new_txt: w_tdf.write(temp) except IOError as ioerr: print('File error:' + str(ioerr)) print('\nafter modify categories are:\n') show_category(txt_list)
(2)把txt文件转化为xml文件
要把txt文件转化为xml文件,在相同目录下创建文件夹Annotations。执行文件代码txt_to_xml.py,将程序放在Labels同一级目录下执行,则可以在Annotations文件夹下生成xml文件。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # txt_to_xml.py # 根据一个给定的XML Schema,使用DOM树的形式从空白文件生成一个XML from xml.dom.minidom import Document import cv2 import os """把txt文件转化为xml文件,在相同目录下创建文件夹Annotations, 执行此文件代码""" def generate_xml(name, split_lines, img_size, class_ind): doc = Document() # 创建DOM文档对象 annotation = doc.createElement('annotation') doc.appendChild(annotation) title = doc.createElement('folder') title_text = doc.createTextNode('VOC2007') # 这里修改了文件夹名 title.appendChild(title_text) annotation.appendChild(title) img_name = name + '.jpg' # 要用jpg格式 title = doc.createElement('filename') title_text = doc.createTextNode(img_name) title.appendChild(title_text) annotation.appendChild(title) source = doc.createElement('source') annotation.appendChild(source) title = doc.createElement('database') title_text = doc.createTextNode('The VOC2007 Database') # 修改为VOC title.appendChild(title_text) source.appendChild(title) title = doc.createElement('annotation') title_text = doc.createTextNode('PASCAL VOC2007') # 修改为VOC title.appendChild(title_text) source.appendChild(title) size = doc.createElement('size') annotation.appendChild(size) title = doc.createElement('width') title_text = doc.createTextNode(str(img_size[1])) title.appendChild(title_text) size.appendChild(title) title = doc.createElement('height') title_text = doc.createTextNode(str(img_size[0])) title.appendChild(title_text) size.appendChild(title) title = doc.createElement('depth') title_text = doc.createTextNode(str(img_size[2])) title.appendChild(title_text) size.appendChild(title) for split_line in split_lines: line = split_line.strip().split() if line[0] in class_ind: object = doc.createElement('object') annotation.appendChild(object) title = doc.createElement('name') title_text = doc.createTextNode(line[0]) title.appendChild(title_text) object.appendChild(title) title = doc.createElement('difficult') title_text = doc.createTextNode('0') title.appendChild(title_text) object.appendChild(title) bndbox = doc.createElement('bndbox') object.appendChild(bndbox) title = doc.createElement('xmin') title_text = doc.createTextNode(str(int(float(line[4])))) title.appendChild(title_text) bndbox.appendChild(title) title = doc.createElement('ymin') title_text = doc.createTextNode(str(int(float(line[5])))) title.appendChild(title_text) bndbox.appendChild(title) title = doc.createElement('xmax') title_text = doc.createTextNode(str(int(float(line[6])))) title.appendChild(title_text) bndbox.appendChild(title) title = doc.createElement('ymax') title_text = doc.createTextNode(str(int(float(line[7])))) title.appendChild(title_text) bndbox.appendChild(title) # 将DOM对象doc写入文件 f = open('Annotations/' + name + '.xml', 'w') f.write(doc.toprettyxml(indent='')) f.close() if __name__ == '__main__': class_ind = ('pedestrian', 'car') # 修改为了两类 cur_dir = os.getcwd() labels_dir = os.path.join(cur_dir, 'label_2') for parent, dirnames, filenames in os.walk(labels_dir): # 分别得到根目录,子目录和根目录下文件 for file_name in filenames: full_path = os.path.join(parent, file_name) # 获取文件全路径 # print full_path f = open(full_path) split_lines = f.readlines() name = file_name[:-4] # 后四位是扩展名.txt,只取前面的文件名 # print name img_name = name + '.jpg' img_path = os.path.join('/home/xuy/桌面/training/JPEGImages', img_name) # 路径需要自行修改 # print img_path img_size = cv2.imread(img_path).shape generate_xml(name, split_lines, img_size, class_ind) print('all txts has converted into xmls') print('all txts has converted into xmls')
(3)生成Main中的txt文件
在同级目录下创建Imagesets文件夹,在文件夹中创建Main,Layout,Segmentation子文件夹。在Labels同级目录下执行文件,生成Main中的txt文件。至此,数据集的准备结束。将准备好的Annotations,JPEGImages,ImageSets文件夹放到如下目录下python-faster-rcnn/data/VOCdevkit2007/VOC2007
from __future__ import print_function # -*- coding:utf-8 -*- __author__ = 'xuy' """ 在同级目录下创建Imagesets文件夹,在文件夹中创建Main,Layout,Segmentation子文件夹。在Labels同级目录下执行文件, 生成Main中的txt文件。数据集的准备结束,我们将准备好的Annotations,JPEGImages,ImageSets文件夹放到如下目录下python-faster-rcnn/data/VOCdevkit2007/VOC2007 """ import pdb import glob import os import random import math def get_sample_value(txt_name, category_name): label_path = './label_2/' txt_path = label_path + txt_name + '.txt' try: with open(txt_path) as r_tdf: if category_name in r_tdf.read(): return ' 1' else: return '-1' except IOError as ioerr: print('File error:' + str(ioerr)) txt_list_path = glob.glob('./label_2/*.txt') txt_list = [] for item in txt_list_path: # temp1返回文件名,temp2返回后缀名 temp1, temp2 = os.path.splitext(os.path.basename(item)) txt_list.append(temp1) txt_list.sort() print(txt_list, end='\n\n') # 有博客建议train:val:test=8:1:1,先尝试用一下 num_trainval = random.sample(txt_list, math.floor(len(txt_list) * 9 / 10.0)) # 可修改百分比 num_trainval.sort() print(num_trainval, end='\n\n') num_train = random.sample(num_trainval, math.floor(len(num_trainval) * 8 / 9.0)) # 可修改百分比 num_train.sort() print(num_train, end='\n\n') num_val = list(set(num_trainval).difference(set(num_train))) num_val.sort() print(num_val, end='\n\n') num_test = list(set(txt_list).difference(set(num_trainval))) num_test.sort() print(num_test, end='\n\n') pdb.set_trace() Main_path = './ImageSets/Main/' train_test_name = ['trainval', 'train', 'val', 'test'] category_name = ['Car', 'Pedestrian'] # 修改类别 # 循环写trainvl train val test for item_train_test_name in train_test_name: list_name = 'num_' list_name += item_train_test_name train_test_txt_name = Main_path + item_train_test_name + '.txt' try: # 写单个文件,train.txt,trainval.txt,val.txt,test.txt这四个文件 with open(train_test_txt_name, 'w') as w_tdf: # 一行一行写 for item in eval(list_name): w_tdf.write(item + '\n') # 循环写Car Pedestrian Cyclist for item_category_name in category_name: category_txt_name = Main_path + item_category_name + '_' + item_train_test_name + '.txt' with open(category_txt_name, 'w') as w_tdf: # 一行一行写 for item in eval(list_name): w_tdf.write(item + ' ' + get_sample_value(item, item_category_name) + '\n') except IOError as ioerr: print('File error:' + str(ioerr))
文件结构如下: