天天看点

[基于tensorflow的人脸检测] 基于神经网络的人脸检测9——人脸检测

1.前言

2.预处理

3.后处理

4.项目总结

正文:

1.前言

总结一下,目前为止做了什么:在前面几篇博文中,对数据进行了处理、搭建了神经网络、训练了神经网络并进行了测试。在实际使用中,因为检测的图片可能是整个人的图像,所以需要从这些图像中框出人脸的位置,这也是这个项目的目的。由于神经网络只能对一张含有人脸或者非人脸的图片进行判断,所以在检测一张图片时,需要先进行预处理。一张图片进行预处理以及神经网络的判断输出后,可能会有很多个结果,所以还要进行后处理,找出最优解。

2.预处理

  • 滑动窗口

    由于一张图片可能有很多个部分组成(人脸、非人脸)。所以需要先对输入的图片进行每部分的截取。滑动金字塔是按照固定的窗口大小在图片中滑动,从而得到很多个窗口,每个窗口都作为神经网络的输入。

    [基于tensorflow的人脸检测] 基于神经网络的人脸检测9——人脸检测

    上图展示了滑动窗口将一张图片分为很多张子图片,除此之位,窗口还记录了子图片在图片中的位置,最后可用于人脸标记。每张图片都输入到训练好的模型,如果神经网络的输出概率(神经网络softmax输出)大于我们设置的阈值,就可以认为这张子图片是人脸部分,进行位置标记。

    下面是程序实现,函数返回子窗口图片和对应的位置。

    import math 
    
    def slid_win(input_img, win_size_h, win_size_w, slid_step,other):
        """滑动窗口函数"""
        #输入参数-输入、窗口w、窗口h和步长
        #输出滑动图片、滑动坐标(坐标格式:[y1,y2,x1,x2]
        sli_images = []
        locates = []
        image_h, image_w, _ = input_img.shape
        lim_w =  math.ceil((image_w-win_size_w)/ slid_step)
        lim_h = math.ceil((image_h-win_size_h)/slid_step)
        # print(lim_w, lim_h)
        for i in range(lim_h):
            strat_h = slid_step*i
            end_h = strat_h + win_size_h
            for j in range(lim_w):
                start_w = slid_step*j
                end_w = start_w + win_size_w
                # print(strat_h, end_h, start_w, end_w)
                if (end_h< image_h) or (end_w< image_w):
                    part_img = input_img[strat_h:end_h, start_w:end_w]
                    locate = [strat_h, end_h, start_w, end_w]
                    sli_images.append(part_img)
                    locates.append(locate)
                    # print(locate)
              
        #添加没有滑动到的区域
        if  not isinstance(((image_w-win_size_w)/ slid_step), int): #判断横方向是不是为整数 不是标志有余留的边缘
            for i in range(lim_h): #遍历纵轴
                strat_h = slid_step*i
                end_h = strat_h + win_size_h
                start_w = image_w-win_size_w
                end_w = image_w
                part_img = input_img[strat_h:end_h, start_w:end_w]
                locate = [int(strat_h), int(end_h), int(start_w), int(end_w)]
                sli_images.append(part_img)
                # print(locate)
                locates.append(locate)
            
        if  not isinstance(((image_h-win_size_h)/ slid_step), int):#判断纵方向是不是为整数 不是标志有余留的边缘
            for j in range(lim_w): #遍历横轴
                start_w = slid_step*j
                end_w = start_w + win_size_w
                strat_h = image_h-win_size_h
                end_h = image_h
                part_img = input_img[strat_h:end_h, start_w:end_w]
                locate = [strat_h, end_h, start_w, end_w]
                sli_images.append(part_img)
                # print(locate)
                locates.append(locate)
        condition1 = not isinstance(((image_w-win_size_w)/ slid_step), int)
        condition2 = not isinstance(((image_h-win_size_h)/ slid_step), int)
        if condition1 and  condition2: #添加最后一张
            start_w = image_w-win_size_w
            end_w = image_w
            strat_h = image_h-win_size_h
            end_h = image_h
            part_img = input_img[strat_h:end_h, start_w:end_w]
            locate = [strat_h, end_h, start_w, end_w]
            sli_images.append(part_img)
            # print(locate)
            locates.append(locate) #格式y1 y2 x1 x2
                
        return sli_images, locates
               
  • 图像金字塔

    虽然滑动窗口可以把一张图片中的人脸和非人脸分离出来,但是还会存在一个问题,因为滑动窗口的尺寸是固定的,所以会存在窗口大小和人脸大小不匹配的情况。所以需要先对输入的图片进行尺寸变换的操作,使得滑动窗口的大小总能和人脸大小相互匹配。

    [基于tensorflow的人脸检测] 基于神经网络的人脸检测9——人脸检测
    (图片来自于百度图片)

3.后处理

经过了预处理并输入到神经网络,且进行位置标记,得到的图片是这样的。

[基于tensorflow的人脸检测] 基于神经网络的人脸检测9——人脸检测

一点也不美观,也没有达到效果。这主要是由于阈值的设置(达到阈值就框出人脸)、滑动窗口步长和比例因子所造成的。所以这里需要进行非极大值抑制(NMS)处理,下面是NMS的算法思想。

[基于tensorflow的人脸检测] 基于神经网络的人脸检测9——人脸检测

NMS简单的说就是对框进行合并,合并的基准是概率最大对应的窗口。如果一个窗口和概率最大对应的窗口重叠面积足够大,就进行消除,只保留概率值最大所对应的窗口。根据这个思想进行程序编写如下。

def compuet_iou(rect1, rect2):
    """计算两个矩形的IOU"""
    #rect是矩形的四个坐标 左上角和右下角坐标 rect = [x1,y1,x2,y2]
    area1 = (rect1[3] - rect1[1]) * (rect1[2] - rect1[0])
    area2 = (rect2[3] - rect2[1]) * (rect2[2] - rect2[0])
    all_area = area1 + area2
    x1 = max(rect1[0], rect2[0])
    y1 = max(rect1[1], rect2[1])
    x2 = min(rect1[2], rect2[2])
    y2 = min(rect1[3], rect2[3])
    h = max(0, y2 - y1)
    w = max(0, x2 - x1)
    overlap = h * w
    #判断等于1情况
    try :
        iou = overlap/(all_area - overlap)
    except:
        iou = 1
    else : 
        iou = overlap/(all_area - overlap)

    return iou

def max_prop(locates, props):
    """取最大概率的nms"""
    #输入参数:所有超过阈值的滑动窗位置、滑动窗口对应阈值
    #输出 算法留下来的框位置
    temp_locates = []
    temp_prop = []
    final_locates = []
    return_locates = []
    second_locates = []
    second_prop = []
    for i in range(len(locates)): #遍历当前所有框
        
        temp_locate = [locates[i][2],locates[i][0],locates[i][3],locates[i][1]]
        temp_locates.append(temp_locate)
        temp_prop.append(props[i])
        
        for j in range(len(locates)):
            now_locate = [locates[j][2],locates[j][0],locates[j][3],locates[j][1]]
            iou = compuet_iou(temp_locate,now_locate) #计算iou
            if iou>0.3 and iou<1: #阈值设置
                temp_locates.append(now_locate)
                temp_prop.append(props[j])
                
        second_locates.append(temp_locates)
        second_prop.append(temp_prop)
        temp_locates = [] #清零 下一次储存
        temp_prop = []
    
    for k in range(len(second_locates)):
        area = []
        for l in range(len(second_locates[k])):
            area.append(second_prop[k][l]) #存储概率值
        max_index = area.index(max(area)) #取最大概率
        final_locates.append(second_locates[k][max_index])#取最大概率对应的框
    # #整理列表 删除相同元素
    for final_locate in final_locates:
        if not final_locate in return_locates:
            return_locates.append(final_locate)
            
    return return_locates #return_locates #格式[x1,y1,x2,y2]
           

4.项目总结

至此,整个人脸检测项目就完成了。从数据处理到神经网络搭建、训练与测试,再到一张人脸图片的测试以及一张图片的测试。下面是这个项目的步骤总结。

  1. 确定数据集 --> 处理得到训练、验证以及测试的图片
  2. 搭建神经网络 --> 用1中的图片进行训练 --> 得到分类器模型
  3. 图片输入 --> 图像金字塔 --> 滑动窗口 --> 送入2中得到的分类器模型分类 --> 输出概率值并标记窗口 --> 非极大值抑制 --> 框出人脸
步骤 备注
确定数据集 FDDB或WIDER FACE或其他
处理得到训练、验证以及测试的图片 该内容在FDDB数据集处理、WIDER FACE数据集处理、数据集的标签生成中,数据也在其中。
搭建神经网络 按照 神经网络的搭建的框架进行搭建
用1中的图片进行训练 设置学习率和训练次数等参数进行训练。训练神经网络中的训练框架为了加快速度设置了比较小的batch、图片和训练次数(实际使用时,并不是使用这么小的batch、图片和训练次数得到模型),可以自主进行选择调节
得到分类器模型 训练搭建好的神经网络得到的模型。我的模型在这里获取人脸检测模型密码:f3vzk8
图片输入 选择一张图片或者视频的一帧
图像金字塔 本篇博文
滑动窗口 本篇博文
送入分类器模型分类 用验证神经网络中的图片验证程序进行图片输入,其中的输出为经过softmax后的概率值。(用于本博文中滑动窗口输入,输出的概率值与阈值比较)
输出概率值并标记窗口 输出概率值指的是softmax输出,当这个值超出自己设定的阈值时就进行标记
非极大值抑制 本篇博文,经过非极大值抑制后的输出就是最终人脸检测结果