将车辆数据集kitti转换为VOC格式(车辆检测)

Kitti数据集的下载只需要一个图片集(12G)和标注文件即可(data_object_image_2.zipdata_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))

文件结构如下:

 

 

 

  • 5
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值