在利用ssd训练人脸检测模型之前,我们要对数据进行处理。我们针对每张照片,要将这种照片的的名字以及这张照片的各个标签信息存储到xml文件里面,最后的xml文件形式如下所示:

机器学习人脸数据下载_python

注意一下,其实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这个数据集,这个数据集自带的文本文件如下:

机器学习人脸数据下载_ide_02

这一行带有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