前言
用深度学习做目标检测,经常会接触到pascal voc这个数据集。目前很多开源项目对数据的处理格式都采用和voc一样的格式,逐渐这成为了一种标准数据处理格式,这里记一次制作符合自己需求的VOC格式数据集。
VOC数据集简介
文件夹树结构
└── VOCdevkit #根目录
└── VOC2007 #不同年份的数据集,这里只下载了2007的,还有2012等其它年份的
├── Annotations #存放xml文件,与同级文件夹JPEGImages中的图片相对应,其中主要记录了图片包含内容,比如图片内含有目标对象的分类、坐标等
├── ImageSets #存放的是每一种类型的challenge对应的图像数据
│ ├── Action #存放的是人的动作
│ ├── Layout #存放的是具有人体部位的数据
│ ├── Main #存放的是目标物体识别的数据
│ └── Segmentation #存放的是可用于分割的数据
├── JPEGImages #存放源图片
├── SegmentationClass
└── SegmentationObject
SegmentationClass、SegmentationObject 这两个文件夹下保存了物体分割后的图片,在目标检测中没有用到,这里就不多做介绍
数据集制作
原始数据预览
原始数据目录结构
train_dataset文件夹内容
train_labels.csv标签数据
voc格式数据制作
JEPGImages
把训练图片数据放进文件夹JEPGImages
就行了
Annotations
- 同照片坐标数据合并
如:(311 707 472 842) ---> (311,707,472,842 311,707,472,842)
处理过后的train_labels.csv数据格式#合并相同图片的行,并规整数据格式 def obj_to_merge1(df,col1,col2): _line = str(list(df[str(col2)])) __line = _line.replace('[','').replace(']','').replace("'",'').replace(',','.').replace(' ',',').replace('.,',' ') df_ = pd.DataFrame({'id':[df[str(col1)].values[0]],'label':[__line]}) return df_ def obj_to_merge2(df,col1,col2): id_list = df[str(col1)].value_counts().keys() df_ = pd.DataFrame() for i in id_list[:]: _df = df[df[str(col1)] == i] __df = obj_to_merge1(_df,col1,col2) df_ = pd.concat([df_,__df]) df_.index = range(len(df_)) return df_
- 获取图片尺寸
获取尺寸之后数据格式img_path = '../JPEGImages/' img_size = [] for i in train.id: _ = cv2.imread(img_path + i) __ = str(_.shape).replace('(','').replace(')','') img_size.append(__)
- 生成xml文件
xml标准格式如下
生成代码
文件预览# 提取每张图片的名称,和对象坐标,图片尺寸 def obj_coordinate(img_label_line,col1,col2,col3): img_id = img_label_line[str(col1)] obj = img_label_line[str(col2)] obj_ = obj.split(' ') img_size = img_label_line[str(col3)] return img_id,obj_,img_size path_xml = '../Annotations/' new_ann = train.copy() for i in range(len(new_ann)): _ = new_ann.iloc[i,:] img_ann = obj_coordinate(_,'id', 'label','img_size') ob = '' img_name = img_ann[0] # 图像名称 classes = 'person' # 对象名称 size = img_ann[-1].replace(' ','').split(',') # 尺寸信息 objs = img_ann[1] # 对象坐标 # object个数为1时 if len(objs)==1: cdte = objs[0].split(',') test_xml = s2.format(img_name,size[1],size[0],size[2],classes,cdte[0],cdte[1],cdte[2],cdte[3],ob) f = open(path_xml+img_name[:-4]+'.xml','w') f.write(test_xml) f.close() # object个数大于1个时 if len(objs)>1: for i in range(1,len(objs)): cdte = objs[1].split(',') cdteB = objs[i].split(',') ob += '\n' + s1.format(classes,cdteB[0],cdteB[1],cdteB[2],cdteB[3]) test_xml = s2.format(img_name,size[1],size[0],size[2],classes,cdte[0],cdte[1],cdte[2],cdte[3],ob) f = open(path_xml+img_name[:-4]+'.xml','w') f.write(test_xml) f.close()
获取的xml文件格式如下
ImageSets
生成Main文件夹下四个文件
- test.txt:测试集
- train.txt:训练集
- val.txt:验证集
- trainval.txt:训练和验证集
代码文件
data_path = 'data/pro_data/'
trainval_percent = 0.5
train_percent = 0.5
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets/Main'
total_xml = os.listdir(data_path + xmlfilepath)
num=len(total_xml)
list_=range(num)
tv=int(num*trainval_percent)
tr=int(tv*train_percent)
trainval= random.sample(list_,tv)
train=random.sample(trainval,tr)
ftrainval = open(data_path+txtsavepath+'/trainval.txt', 'w')
ftest = open(data_path+txtsavepath+'/test.txt', 'w')
ftrain = open(data_path+txtsavepath+'/train.txt', 'w')
fval = open(data_path+txtsavepath+'/val.txt', 'w')
for i in list_:
name=total_xml[i][:-4]+'\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftrain.write(name)
else:
fval.write(name)
else:
ftest.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
生成文件夹预览
生成正负样本
person_trainval = open(data_path+txtsavepath+'/person_trainval.txt', 'w')
person_test = open(data_path+txtsavepath+'/person_test.txt', 'w')
person_train = open(data_path+txtsavepath+'/person_train.txt', 'w')
person_val = open(data_path+txtsavepath+'/person_val.txt', 'w')
for i in list_:
name=total_xml[i][:-4]
if name+'.jpg' in new_ann.id.values:
if i in trainval:
person_trainval.write(name+' 1\n')
if i in train:
person_train.write(name+' 1\n')
else:
person_val.write(name+' 1\n')
else:
person_test.write(name+' 1\n')
else:
if i in trainval:
person_trainval.write(name+' -1\n')
if i in train:
person_train.write(name+' -1\n')
else:
person_val.write(name+' -1\n')
else:
person_test.write(name+' -1\n')
person_trainval.close()
person_train.close()
person_val.close()
person_test.close()
生成文件夹预览
至此,就已经制作完成我们目标检测项目所需要的VOC格式数据集