在利用ssd训练人脸检测模型之前,我们要对数据进行处理。我们针对每张照片,要将这种照片的的名字以及这张照片的各个标签信息存储到xml文件里面,最后的xml文件形式如下所示:
注意一下,其实xml的格式是那种根节点子节点的形式,比如在这里,annotation就是根节点,folder和size这些就是子节点,然后xmin这些就是子节点的子节点,我们最后要创建一个这种xml文件,那么我们就需要创建上图所示的这种结构,我们先学一下如何创建节点,代码如下:
'''this code was desinged by nike hu'''
from xml.dom.minidom import Document
import cv2
def write_xml_1(filename, savimg, bboxes, xmlpath):
'''saving 参数其实是输入的照片,bboxes是输入的标签坐标,xmlpath是最后保存xml文件的路径'''
doc = Document() # 定义整个文件的对象
annotation = doc.createElement('annotation') # 定义一个根节点
doc.appendChild(annotation) # 将创建的根节点加进去
folder = doc.createElement('folder') # 再创建annotation的子节点
folder_name = doc.createTextNode('widerface') # createTextNode() 方法创建文本节点,该方法返回 Text 对象
folder.appendChild(folder_name) # 把子节点放到folder后面,相当于<folder>widerface</folder>
annotation.appendChild(folder) # 将folder放到跟节点后面
filenamenode = doc.createElement('filename') # 创建节点
filename_name = doc.createTextNode(filename) # 创建文本
filenamenode.appendChild(filename_name) # 将文本放进去
annotation.appendChild(filenamenode) # 跟根节点关联起来
我们学会如何闯将节点之后就可以任性的搭建我们想要的xml结构的文件,我这里提供一种搭建结构,这里得代码是用的他人的。大家看看,可以根据自己情况来改变。
def writexml(filename,saveimg,bboxes,xmlpath):
doc = Document()
annotation = doc.createElement('annotation')
doc.appendChild(annotation)
folder = doc.createElement('folder')
folder_name = doc.createTextNode('widerface')
folder.appendChild(folder_name)
annotation.appendChild(folder)
filenamenode = doc.createElement('filename')
filename_name = doc.createTextNode(filename)
filenamenode.appendChild(filename_name)
annotation.appendChild(filenamenode)
source = doc.createElement('source')
annotation.appendChild(source)
database = doc.createElement('database')
database.appendChild(doc.createTextNode('wider face Database'))
source.appendChild(database)
annotation_s = doc.createElement('annotation')
annotation_s.appendChild(doc.createTextNode('PASCAL VOC2007'))
source.appendChild(annotation_s)
image = doc.createElement('image')
image.appendChild(doc.createTextNode('flickr'))
source.appendChild(image)
flickrid = doc.createElement('flickrid')
flickrid.appendChild(doc.createTextNode('-1'))
source.appendChild(flickrid)
owner = doc.createElement('owner')
annotation.appendChild(owner)
flickrid_o = doc.createElement('flickrid')
flickrid_o.appendChild(doc.createTextNode('yanyu'))
owner.appendChild(flickrid_o)
name_o = doc.createElement('name')
name_o.appendChild(doc.createTextNode('yanyu'))
owner.appendChild(name_o)
size = doc.createElement('size')
annotation.appendChild(size)
width = doc.createElement('width')
width.appendChild(doc.createTextNode(str(saveimg.shape[1])))
height = doc.createElement('height')
height.appendChild(doc.createTextNode(str(saveimg.shape[0])))
depth = doc.createElement('depth')
depth.appendChild(doc.createTextNode(str(saveimg.shape[2])))
size.appendChild(width)
size.appendChild(height)
size.appendChild(depth)
segmented = doc.createElement('segmented')
segmented.appendChild(doc.createTextNode('0'))
annotation.appendChild(segmented)
for i in range(len(bboxes)):
bbox = bboxes[i]
objects = doc.createElement('object')
annotation.appendChild(objects)
object_name = doc.createElement('name')
object_name.appendChild(doc.createTextNode('face'))
objects.appendChild(object_name)
pose = doc.createElement('pose')
pose.appendChild(doc.createTextNode('Unspecified'))
objects.appendChild(pose)
truncated = doc.createElement('truncated')
truncated.appendChild(doc.createTextNode('1'))
objects.appendChild(truncated)
difficult = doc.createElement('difficult')
difficult.appendChild(doc.createTextNode('0'))
objects.appendChild(difficult)
bndbox = doc.createElement('bndbox')
objects.appendChild(bndbox)
xmin = doc.createElement('xmin')
xmin.appendChild(doc.createTextNode(str(bbox[0])))
bndbox.appendChild(xmin)
ymin = doc.createElement('ymin')
ymin.appendChild(doc.createTextNode(str(bbox[1])))
bndbox.appendChild(ymin)
xmax = doc.createElement('xmax')
xmax.appendChild(doc.createTextNode(str(bbox[0] + bbox[2])))
bndbox.appendChild(xmax)
ymax = doc.createElement('ymax')
ymax.appendChild(doc.createTextNode(str(bbox[1] + bbox[3])))
bndbox.appendChild(ymax)
f = open(xmlpath, "w")
f.write(doc.toprettyxml(indent=''))
f.close()
对于wider_face这个数据集,这个数据集自带的文本文件如下:
这一行带有jpg字母的,就代表图片的路径,这一行的下面代表有多少个标签,然后449这些数据就代表x,y,w,h,…,后面几个0有其他含义,我们暂时用不到,知道文本文件之后,我们将每张照片的数据存储为xml格式的代码如下:
'''this code was desinged by nike hu'''
# 接下来这个函数用来将所有训练的照片找出来并且对每张照片创建xml文件
def convert_xml(label): # 这里得lable代表是train或者test,val
root_path = 'E:/code/DataSet/wider_face/' # 这里是下载数据集后的根目录
imageData = root_path + 'WIDER_' + label + '/images/' # 这里就定位到图片存储的位置
face_split = root_path + 'wider_face_split/' + 'wider_face_' + label + '_bbx_gt.txt' # 定位到坐标标注信息文档
face_file = open(face_split, 'r')
index = 0
while True:
filename = face_file.readline().strip() # 读取每一行,读取的这一行代表图像的存储路径,注意去掉字符串两边空格,否则最后存照片的时候可能出错
if 'jpg' not in filename: # 如果不是读取的图片路径那一行,跳过
continue
if filename == '': # 跳出循环的条件,代表已经读完了
break
image_path = (imageData + filename).strip() # 图像路径,记得strip将字符串两边空格去掉,否则图片读取为None
image = cv2.imread(image_path) # 读取图像
if image is None:
continue # 如果照片没有读取出来,跳过
number_label = face_file.readline() # 在图像路径的下一行会出现这张照片里面有的标签个数
if number_label == '0':
continue # 如果标签为0,代表这张照片没有标签,跳过
bboxes = [] # 用来存储坐标
for i in range(int(number_label)): # 接着读取下面的数据,有多少行标签就读取多少行
bbox = face_file.readline().split(' ') # 类似[449 330 122 149 0 0 0 0 0 0]
bboxes.append(bbox[0:4]) # 将坐标保存
save_file_name = filename.replace('/', '_') # 用后面的符号替代前面的符号
with open('./Imagesets/Main/' + label + '.txt', 'a') as f:
f.write(save_file_name.split('.')[0] + '\n') # 只保存文件名,不保存jpg这些文件格式,注意结尾加一个\n
cv2.imwrite('./JPEGimges/' + save_file_name, image) # 将image保存在这个目录下
xmlpath = 'Annotations/' + save_file_name.split('.')[0] + '.xml' # 保存的xml文件的名字,前面的Annotations是保存的文件夹
writexml(save_file_name.split('.')[0], image, bboxes, xmlpath) # 传入参数就去,存储xml文件
index += 1
print('已经处理了' + str(index) + '张照片')
好了,对于数据集的处理就是这样了,希望对大家有用。
2020 4.16