前言:
由于作者最近在做行人目标检测这方面的研究,需要用到Caltech Pedestrian数据集,但该数据集存在的一些问题使我不得不对其进行一些适配性的处理。趁着炼丹的功夫来记录一下处理过程。
正文:
Caltech Pedestrian dataset 下载链接:Caltech—USA 下载原数据可能需要爬墙,若需要的话也可在文末获取本文处理后的数据。 言归正传,原数据的标签和图片格式分是.vbb和.seq,我希望对其进行一个xml和jpg的转换,在Caltech数据集目录同级处创建两个python文件,复制以下代码并运行即可。代码如下: 1.标签处理:
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 = defaultdict(dict)
vbb = loadmat(vbb_file)
objLists = vbb['A'][0][0][1][0]
objLbl = [str(v[0]) for v in vbb['A'][0][0][4][0]]
person_index_list = np.where(np.array(objLbl) == "person")[0]
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
if not id in person_index_list:
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):
assert os.path.exists(vbb_inputdir)
sub_dirs = os.listdir(vbb_inputdir)
for sub_dir in sub_dirs:
print("Parsing annotations of camera: ", sub_dir)
cam_id = sub_dir
vbb_files = glob.glob(os.path.join(vbb_inputdir, sub_dir, "*.vbb"))
for vbb_file in vbb_files:
annos = vbb_anno2dict(vbb_file, cam_id)
if annos:
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)
etree.ElementTree(anno_tree).write(outfile, pretty_print=True)
def visualize_bbox(xml_file, img_file):
import cv2
tree = etree.parse(xml_file)
image = cv2.imread(img_file)
origin = cv2.imread(img_file)
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)
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:
"""
f = open(file, 'rb+')
string = f.read().decode('latin-1')
splitstring = "\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46"
"""
>>> a = ".12121.3223.4343"
>>> a.split('.')
['', '12121', '3223', '4343']
"""
strlist = string.split(splitstring)
f.close()
count = 0
if os.path.exists(savepath):
shutil.rmtree(savepath)
if not os.path.exists(savepath):
os.makedirs(savepath)
for img in strlist:
filename = str(count) + '.jpg'
filenamewithpath = os.path.join(savepath, filename)
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"
for parent, dirnames, filenames in os.walk(rootdir):
for filename in filenames:
if fnmatch.fnmatch(filename, '*.seq'):
thefilename = os.path.join(parent, 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 = []
for j in total_xml:
second_dir=os.listdir(os.path.join(path1,j))
nw.append(second_dir)
txz = 0
for i in total_xml:
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
xmlfilepath = "./Caltech/Annotations_voc"
image_train_path="./Caltech/VOC_process"
def del_files(path,path2):
total_xml = os.listdir(path)
nw = []
total_image=os.listdir(path2)
for j in total_image:
second_dir=os.listdir(os.path.join(path2,j))
nw.append(second_dir)
txz = 0
sx1 = []
for i in total_image:
s_dir = os.path.join(path2, 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('_')[2].split('.')[0]))
for x in sx:
x1,x2=x.split(".")
sx1.append(x1)
txz += 1
sx2=[]
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
|