Caltech 数据集转换成VOC格式

注意本人用pycharm 运行环境是python2.7.14 

如果是python3 可能会存在错误

1. Seq文件转化成JEPG图像文件()

运行seq2jpg.py文件,输入.seq文件夹,输出到JPEG文件夹中,

将Caltech原始数据集解压到Caltech文件夹  并把Caltech文件夹放在F:/Caltech文件夹下

并在F:/Caltech文件夹下新建一个Caltech_VOC文件夹

输入seq文件路径是F:\Caltech\Caltech

输出图片的存储路径是F:\Caltech\Caltech_VOC\JPEG

seq2jpg.py(可以修改自己的文件路径 对于最好还是按我的路径来 即跟我一样的文件目录 )

#-*- coding:utf-8 -*-
import os.path
import fnmatch #模块的主要作用是文件名称的匹配
import shutil

def open_save(file,savepath):
    # 读入一个seq文件,然后拆分成image存入savepath当中
    f = open(file,'rb')#以二进制的形式读取图片
    #将seq文件的内容转化成str类型
    string = str(f.read())
    ####关键所在
    #splitstring是图片的前缀,可以理解成seq是以splitstring为分隔的多个jpg合成的文件
    splitstring = "\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46"
    #split函数做一个测试,因此返回结果的第一个是在seq文件中是空,因此后面省略掉第一个
    """
    >>> a = ".12121.3223.4343"
    >>> a.split('.')
    ['', '12121', '3223', '4343']
    """
    strlist=string.split(splitstring)
    #print(strlist)
    #print('######################################')
    f.close()
    count = 0
    # delete the image folder path if it exists
    if os.path.exists(savepath):
        shutil.rmtree(savepath)
    # create the image folder path
    if not os.path.exists(savepath):
        os.makedirs(savepath)
    #遍历每一个jpg文件内容,然后加上前缀合成图片
    for img in strlist:
        filename = str(count)+'.jpg'
        filenamewithpath=os.path.join(savepath, filename)
        if count > 0:
            i=open(filenamewithpath,'wb+')
            i.write(splitstring)
            i.write(img)
            i.close()
        count = count + 1
if __name__=="__main__":
    rootdir = "F:\Caltech\Caltech"
    saveroot = "F:\Caltech\Caltech_VOC\JPEG"

    for parent, dirnames, filenames in os.walk(rootdir):
        for filename in filenames:
            #fnmatch 全称是 filename match,主要是用来匹配文件名是否符合规则的
            if fnmatch.fnmatch(filename,'*.seq'):#找到.seq文件
                thefilename = os.path.join(parent, filename) #读取的文件路径
                # create the image folder by combining .seq file path with .seq filename
                thesavepath = saveroot +'\\'+ parent.split('\\')[-1] + '\\' + filename.split('.')[0]+'\\'
                print ("Filename=" + thefilename)
                print ("Savepath=" + thesavepath)
                open_save(thefilename,thesavepath)

转换成图片后,JPEG文件夹对应的目录如下:

Caltech 数据集转换成VOC格式_第1张图片

其中set00中文件夹V000中的图片如下图所示:

Caltech 数据集转换成VOC格式_第2张图片

2. VBB标注文件转化为XML文件

运行vbb2voc.py文件,输入annotations文件夹,输出到xmlresult文件夹中。

输入路径F:/Caltech/Caltech/annotations/

输出路径F:/Caltech/Caltech_VOC/xmlresult/

vbb2voc.py(同样只需修改成自己文件输入输出路径即可  对于小白最好还是按我的路径来)

#-*- coding:utf-8 -*-
import os, glob
import cv2
from scipy.io import loadmat
from collections import defaultdict
import numpy as np
from lxml import etree, objectify

def vbb_anno2dict(vbb_file, cam_id):
    #通过os.path.basename获得路径的最后部分“文件名.扩展名”
    #通过os.path.splitext获得文件名
    filename = os.path.splitext(os.path.basename(vbb_file))[0]

    #定义字典对象annos
    annos = defaultdict(dict)
    vbb = loadmat(vbb_file)
    # object info in each frame: id, pos, occlusion, lock, posv
    objLists = vbb['A'][0][0][1][0]
    objLbl = [str(v[0]) for v in vbb['A'][0][0][4][0]]     #可查看所有类别        
    # person index
    person_index_list = np.where(np.array(objLbl) == "person")[0]   #只选取类别为‘person’的xml
    for frame_id, obj in enumerate(objLists):
        if len(obj) > 0:
            frame_name = str(cam_id) + "_" + str(filename) + "_" + str(frame_id+1) + ".jpg"
            annos[frame_name] = defaultdict(list)
            annos[frame_name]["id"] = frame_name
            annos[frame_name]["label"] = "person"
            for id, pos, occl in zip(obj['id'][0], obj['pos'][0], obj['occl'][0]):
                id = int(id[0][0]) - 1  # for matlab start from 1 not 0
                if not id in person_index_list:  # only use bbox whose label is person
                    continue
                pos = pos[0].tolist()
                occl = int(occl[0][0])
                annos[frame_name]["occlusion"].append(occl)
                annos[frame_name]["bbox"].append(pos)
            if not annos[frame_name]["bbox"]:
                del annos[frame_name]
    print (annos)
    return annos


def seq2img(annos, seq_file, outdir, cam_id):
    cap = cv2.VideoCapture(seq_file)
    index = 1
    # captured frame list
    v_id = os.path.splitext(os.path.basename(seq_file))[0]
    cap_frames_index = np.sort([int(os.path.splitext(id)[0].split("_")[2]) for id in annos.keys()])
    while True:
        ret, frame = cap.read()
        print (ret)
        if ret:
            if not index in cap_frames_index:
                index += 1
                continue
            if not os.path.exists(outdir):
                os.makedirs(outdir)
            outname = os.path.join(outdir, str(cam_id)+"_"+v_id+"_"+str(index)+".jpg")
            print ("Current frame: ", v_id, str(index))
            cv2.imwrite(outname, frame)
            height, width, _ = frame.shape
        else:
            break
        index += 1
    img_size = (width, height)
    return img_size


def instance2xml_base(anno, bbox_type='xyxy'):
    """bbox_type: xyxy (xmin, ymin, xmax, ymax); xywh (xmin, ymin, width, height)"""
    assert bbox_type in ['xyxy', 'xywh']
    E = objectify.ElementMaker(annotate=False)
    anno_tree = E.annotation(
        E.folder('VOC2014_instance/person'),
        E.filename(anno['id']),
        E.source(
            E.database('Caltech pedestrian'),
            E.annotation('Caltech pedestrian'),
            E.image('Caltech pedestrian'),
            E.url('None')
        ),
        E.size(
            E.width(640),
            E.height(480),
            E.depth(3)
        ),
        E.segmented(0),
    )
    for index, bbox in enumerate(anno['bbox']):
        bbox = [float(x) for x in bbox]
        if bbox_type == 'xyxy':
            xmin, ymin, w, h = bbox
            xmax = xmin+w
            ymax = ymin+h
        else:
            xmin, ymin, xmax, ymax = bbox
        E = objectify.ElementMaker(annotate=False)
        anno_tree.append(
            E.object(
            E.name(anno['label']),
            E.bndbox(
                E.xmin(xmin),
                E.ymin(ymin),
                E.xmax(xmax),
                E.ymax(ymax)
            ),
            E.difficult(0),
            E.occlusion(anno["occlusion"][index])
            )
        )
    return anno_tree


def parse_anno_file(vbb_inputdir,vbb_outputdir):
    # annotation sub-directories in hda annotation input directory
    assert os.path.exists(vbb_inputdir)
    sub_dirs = os.listdir(vbb_inputdir)     #对应set00,set01...
    for sub_dir in sub_dirs:
        print ("Parsing annotations of camera: ", sub_dir)
        cam_id = sub_dir #set00 set01等
        #获取某一个子set下面的所有vbb文件
        vbb_files = glob.glob(os.path.join(vbb_inputdir, sub_dir, "*.vbb")) 
        for vbb_file in vbb_files:
            #返回一个vbb文件中所有的帧的标注结果
            annos = vbb_anno2dict(vbb_file, cam_id)
            
            if annos:
                #组成xml文件的存储文件夹,形如“/Users/chenguanghao/Desktop/Caltech/xmlresult/”
                vbb_outdir = vbb_outputdir
                                              
                #如果不存在
                if not os.path.exists(vbb_outdir):
                    os.makedirs(vbb_outdir)

                for filename, anno in sorted(annos.items(), key=lambda x: x[0]):                  
                    if "bbox" in anno:
                        anno_tree = instance2xml_base(anno)
                        outfile = os.path.join(vbb_outdir, os.path.splitext(filename)[0]+".xml")
                        print ("Generating annotation xml file of picture: ", filename)
                        #生成最终的xml文件,对应一张图片
                        etree.ElementTree(anno_tree).write(outfile, pretty_print=True)            
def visualize_bbox(xml_file, img_file):
    import cv2
    tree = etree.parse(xml_file)
    # load image
    image = cv2.imread(img_file)
    origin =  cv2.imread(img_file)
    # 获取一张图片的所有bbox
    for bbox in tree.xpath('//bndbox'):
        coord = []
        for corner in bbox.getchildren():
            coord.append(int(float(corner.text)))
        print (coord)
        cv2.rectangle(image, (coord[0], coord[1]), (coord[2], coord[3]), (0, 0, 255), 2)
    # visualize image
    cv2.imshow("test", image)
    cv2.imshow('origin',origin)
    cv2.waitKey(0)


def main():
    vbb_inputdir = "F:/Caltech/Caltech/annotations/"
    vbb_outputdir = "F:/Caltech/Caltech_VOC/xmlresult/"
    parse_anno_file(vbb_inputdir,vbb_outputdir)
    

    """
    下面这段是测试代码
    """

    """
    xml_file = "F:/Caltech/Caltech_VOC/xmlresult/set00_V000_526.xml"
    img_file = "F:/Caltech/Caltech_VOC/JPEG/set00/V000/526.jpg"
    visualize_bbox(xml_file, img_file)
    """

if __name__ == "__main__":
    main()

在输出文件路径中输出xml文件 共122187个xml文件

文件名是 set00_V000_69.xml等等等 说明并不是每一帧图片中都有人 set00/V000中69.jpg中才有人出现

3.因为xml文件已经在一个统一的文件夹xmlresult中所以要将所有的JPEG文件分别放到统一的文件夹里并按set0_V000_1.jpg的方式,与xml文件格式对应

运行mergeimg.py文件。输入图片路径 F:/Caltech/Caltech_VOC/JPEG

输出图片路径:F:/Caltech/Caltech_VOC/JPEGImage

#-*- coding:utf-8 -*-
#-*- coding:utf-8 -*-
import os
import glob
import shutil
if __name__ == "__main__":
    imgpathin = 'F:/Caltech/Caltech_VOC/JPEG'
    imgout = 'F:/Caltech/Caltech_VOC/JPEGImage'
    for subdir in os.listdir(imgpathin):
        print subdir
        file_path = os.path.join(imgpathin,subdir)
        for subdir1 in os.listdir(file_path):
            print subdir1
            #jpg_files = glob.glob(os.path.join(file_path, subdir1, "*.jpg"))
            file_path1 = os.path.join(file_path, subdir1)
            for jpg_file in os.listdir(file_path1):
                #print jpg_file

                src = os.path.join(file_path1, jpg_file)
                new_name=str(subdir+"_"+subdir1+"_"+jpg_file)
                dst=os.path.join(imgout,new_name)
                os.rename(src,dst)

然后会在JPEGImage文件夹看到set0_V000_1.jpg格式的图片 共249884张

4.重命名图片和XML文件

按照“xxxxxx”这样的6位数字索引命名JPEG图片文件以及对应的XML文件。

有人的图片命名为xxxxxx.jpg 对应的xml文件命名为xxxxxx.xml 两个xxxxxx相同

没人的图片保持原名

输入和输出的xml文件路径 均为F:/Caltech/Caltech_VOC/xmlresult

输出的图片路径为F:/Caltech/Caltech_VOC/JPEGImage

运行renameindex.py

#-*- coding:utf-8 -*-
import os
xmlpath = 'F:/Caltech/Caltech_VOC/xmlresult'
imgpath = 'F:/Caltech/Caltech_VOC/JPEGImage'
index = 0
count = 0
emptyset = set()
xmlFiles = os.listdir(xmlpath)
imgFiles = os .listdir(imgpath)
print len(xmlFiles),len(imgFiles)

for xml in xmlFiles:
	xmlname  = os.path.splitext(xml)[0]
	imgname = os.path.join(imgpath,xmlname+'.jpg')

	if os.path.exists(imgname):
		newName = str(index).zfill(6)
		#重命名图像
		os.rename(imgname,os.path.join(imgpath,newName+'.jpg'))
		#重命名xml文件
		os.rename(os.path.join(xmlpath,xml),os.path.join(xmlpath,newName+'.xml'))
		print '============================================'
		print 'img',imgname,os.path.join(imgpath,newName+'.jpg')
		print '__________________________________________'
		print 'xml',os.path.join(xmlpath,xml),os.path.join(xmlpath,newName+'.xml')
		print '============================================'
		index = index + 1
	else:
		count += 1
		emptyset.add(xmlname.split('_')[0]+'_'+xmlname.split('_')[1])

sortedSet = sorted(emptyset,key= lambda x:(x.split('_')[0],x.split('_')[1]))
for i in sortedSet:
	print i
print count

结果为

Caltech 数据集转换成VOC格式_第3张图片

Caltech 数据集转换成VOC格式_第4张图片

5.生成4个txt文件指定训练集、验证集、数据集、训练验证集

调用generateTXT.py文件,输入xmlresult文件夹,输出到txt文件夹中。

trainval.txt 用来训练和验证的图片文件的文件名列表 包含train.txt(用来训练)和val.txt(用来验证)的文件名列表

test.txt 用来测试的图片文件的文件名列表 

 

运行 generateTXT.py

import os
import random
import time

xmlfilepath='F:/Caltech/Caltech_VOC/xmlresult'
saveBasePath='F:/Caltech/Caltech_VOC/txt'
if not os.path.exists(saveBasePath):
    os.makedirs(saveBasePath)
#设置训练集和测试集的百分比
trainval_percent=0.5
train_percent=0.5
total_xml = os.listdir(xmlfilepath)#所有的

num = len(total_xml)      #xml文件的数量
index_list = range(num)   #生成一个index列表
trainval_num = int(num*trainval_percent) 
train_num = int(trainval_num*train_percent)
trainval_index = random.sample(index_list,trainval_num)
train_index = random.sample(trainval_index,train_num)

print("train and val size", trainval_num)
print("train size", train_num)

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')

# Start time
start = time.time()
for i  in index_list:
    name = os.path.splitext(total_xml[i])[0] + '\n'    
    if i in trainval_index:
        ftrainval.write(name)
        if i in train_index:
            ftrain.write(name)
        else:
            fval.write(name)
    else:
        ftest.write(name)
# End time
end = time.time()
seconds = end - start
print( "Time taken : {0} seconds".format(seconds))
ftrainval.close()
ftrain.close()
fval.close()
ftest .close()

结果为

Caltech 数据集转换成VOC格式_第5张图片

Caltech 数据集转换成VOC格式_第6张图片

6. 替换标签(辅助)

Caltech的标注里有很多别的类别的行人,people,person,

运行findPeople.py是将people标签替换成person。这是一个辅助文件,不是必须用到的。

 

 

你可能感兴趣的:(Caltech 数据集转换成VOC格式)