Caltech Pedestrian数据集

前言:

由于作者最近在做行人目标检测这方面的研究,需要用到Caltech Pedestrian数据集,但该数据集存在的一些问题使我不得不对其进行一些适配性的处理。趁着炼丹的功夫来记录一下处理过程。

正文:

Caltech Pedestrian dataset 下载链接:Caltech—USA
下载原数据可能需要爬墙,若需要的话也可在文末获取本文处理后的数据。
言归正传,原数据的标签和图片格式分是.vbb和.seq,我希望对其进行一个xml和jpg的转换,在Caltech数据集目录同级处创建两个python文件,复制以下代码并运行即可。代码如下:
1.标签处理:

# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
import os, glob
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):
    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 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(int(xmin)),
                    E.ymin(int(ymin)),
                    E.xmax(int(xmax)),
                    E.ymax(int(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
        # 获取某一个子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

                # 如果不存在 vbb_outdir
                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 = "./Caltech/annotations/annotations"
    vbb_outputdir = "./Caltech/Annotations_voc"
    parse_anno_file(vbb_inputdir, vbb_outputdir)


if __name__ == "__main__":
    main()
    print("Success!")


2.图片处理

import os.path
import fnmatch
import shutil


def open_save(file, savepath):
    """
    read .seq file, and save the images into the savepath

    :param file: .seq文件路径
    :param savepath: 保存的图像路径
    :return:
    """

    # 读入一个seq文件,然后拆分成image存入savepath当中
    f = open(file, 'rb+')
    # 将seq文件的内容转化成str类型
    string = f.read().decode('latin-1')

    # 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']
    """
    # split .seq file into segment with the image prefix
    strlist = string.split(splitstring)
    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)
    # deal with file segment, every segment is an image except the first one
    for img in strlist:
        filename = str(count) + '.jpg'
        filenamewithpath = os.path.join(savepath, filename)
        # abandon the first one, which is filled with .seq header
        if count > 0:
            i = open(filenamewithpath, 'wb+')
            i.write(splitstring.encode('latin-1'))
            i.write(img.encode('latin-1'))
            i.close()
        count += 1


if __name__ == "__main__":
    rootdir = "./Caltech"
    saveroot = "./Caltech/VOC_process"

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



经过上述处理后,实际上图片名和标签名并没有一一对应,标签名是:set00_V000_id.xml样式的,而图片名则是1,2,3,4…样式的,我想让它们一一对应起来,就先要修改图片名为set00_V000_id.jpg:
3.图片重命名:

import os
image_train_path="./train_images"

def renamfile(path1):
    total_xml = os.listdir(path1)
    nw = []  # V000,V0001
    for j in total_xml:#set00
        second_dir=os.listdir(os.path.join(path1,j))
        nw.append(second_dir)
    txz = 0
    for i in total_xml:#i:set00 set01 set02
        s_dir = os.path.join(path1, i)
        for j in nw[txz]:

            v_dir = os.path.join(s_dir, j)
            sx = os.listdir(v_dir)
            sx.sort(key=lambda x: int(x.split('.')[0]))
            
            for tt in sx:
                final_dir=os.path.join(v_dir,tt)
                houzhui=i+'_'+j+'_'+tt
                
                re_dir=os.path.join(v_dir, houzhui)
                
                try:
                    os.rename(final_dir, re_dir)

                except Exception as e:
                    print(e)
                    print('rename file fail\r\n')
                else:
                    print('rename file success\r\n')
        txz += 1


renamfile(image_train_path)

实际上,由于该数据集是由车载摄像头的视频切帧得到的,并不是每一帧上都有person目标物,所以某些图片是没有annotations的(作者采用的annotation是旧版的,不是新版),所以在这里对一些多余的图片进行删除:
4.图片删除:

import os#首先导入os模块,进行文件的查找,修改,删除等操作一般都要事先导入os模块
xmlfilepath = "./Caltech/Annotations_voc"
image_train_path="./Caltech/VOC_process"

def del_files(path,path2):
    total_xml = os.listdir(path)#遍历xml标签目录,获得所有标签名,存在total_xml中
    nw = []  # V000,V0001
    total_image=os.listdir(path2)#遍历第一级目录,获得set00,set01...set10

    for j in total_image:#set00
        second_dir=os.listdir(os.path.join(path2,j))#遍历第二级目录,获得V000,V001...
        nw.append(second_dir)#

    txz = 0
    sx1 = []#保存图片的文件名,如set00_V000_1
    for i in total_image:#i:set00 set01 set02
        s_dir = os.path.join(path2, i)#./Caltech/VOC_process/set00
        for j in nw[txz]:#j:V000
            v_dir = os.path.join(s_dir, j)#./Caltech/VOC_process/set00/V000
            sx = os.listdir(v_dir)#69.xml 70.xml
            sx.sort(key=lambda x: int(x.split('_')[2].split('.')[0]))

            for x in sx:
                x1,x2=x.split(".")
                sx1.append(x1)
        txz += 1
    sx2=[]#保存xml的文件名,如set00_V000_69
    for j in total_xml:
        name=j.split(".")[0]
        sx2.append(name)
    for a in sx1:
        if a not in sx2:
            p1,p2,p3=a.split('_')
            del_path=p1+'/'+p2+'/'+a+'.jpg'
            print('图片不存在',a)

            os.remove(os.path.join(path2, del_path))
    print('del success!')



del_files(xmlfilepath,image_train_path)

     

然后再将annotation像图片一样放到如set00/V000等的文件夹中就可以了,最后再对所有图片和标签进行0,1,2,3…这样的重命名,在此不再赘述。
处理后的数据集:链接:https://pan.baidu.com/s/1jLt1MwoWo7hd3bMZ7MvYMQ
提取码:lhvw

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值