【人脸检测】MTCNN 全流程详解 Pytorch代码

概述

MTCNN,Multi-task convolutional neural network(多任务卷积神经网络)。该模型利用级联思想,化繁为简,通过三个级联的网络:P-Net(Proposal Network)、R-Net(Refine Network)和O-Net(Output Network),逐层筛选。在每个网络都非常简单,易于训练的同时,实现了高精度的人脸检测。

思路

人脸检测属于单类多目标检测,相对于单类单目标,实现中有以下问题:

  1. 人脸数目
    因为不知道1张图中需要检测多少人脸,也就不能通过网络直接输出预测值。
    解决方法:像卷积操作中卷积核的滑动一样,以一定的大小和步长扫描整张图片,将扫描到的小图输入网络做检测。
  2. 人脸大小
    紧接着的问题是:如何确定“卷积核”大小?
    因为需要检测的人脸大小也不确定,所以考虑应该用不同大小的“卷积核”去扫描。
    反之,也可以保持“卷积核”不变,通过数次缩小原图(图像金字塔)来实现。
  3. 精度不高
    如果像普通单类单目标任务一样,直接回归真实人脸框,那么检测中一旦错过了合适的框,就错过该目标了。
    因此MTCNN中一个精妙的点在于:不直接学习真实框,而是学习偏移框,由偏移量反算回真实框。
    这样做的好处是:在人脸目标周围,会检测到多个偏移框,从而反算回多个预测框,大大增加了容错率。
  4. 一大堆框
    这样就可以将不同大小的扫描图片传入P-Net检测,在一大堆重叠的预测框中,我们需要的,只应该是其中最确定的那一个,这就依赖于NMS操作了 。

数据处理

选择CelebA人脸数据集,标签为人脸框左上角坐标:x1、y1,宽高:w、h,及5个人脸特征点坐标。

  1. 对真实框中心坐标做随机偏移,最大边长+随机量作为新边长,生成正方形框。可以选择将1张图片增样成数张。
  2. 将正方形框和原真实框做 IOU,通过设定 IOU 的阈值,将生成框划分为正样本负样本部分样本
  3. 裁下正方形框,resize成尺寸12、24、48,分别用于P、R、O网络训练。
  4. 计算生成框坐标、5个人脸特征点坐标的偏移量,负样本偏移量均设为0,因其不参与坐标回归训练。
    计算偏移量作用相当于归一化,加快收敛。
  5. 将置信度、2个生成框坐标偏移量、5个人脸特征点坐标偏移量,共15个值写入txt文件作为训练标签。

生成框坐标偏移量计算如下图,其余特征点坐标偏移量计算方法同 (_x1,_y1),对左上角点做偏移即可,也可以自己找一个点做偏移,如右下角点或矩形中点,测试时按对应点反算坐标。

我处理后的3种样本数据集,每种尺寸20万张,共60万张。

正样本:
在这里插入图片描述

部分样本:

负样本:

工具

非极大值抑制

交并比(Intersection-over-Union,IOU),两个图形交集与并集的比值,表示重叠程度。


需要注意的是:在最后的O网络输出时,将把 IOU 计算公式中分母改为A和B中的面积较小值,从而去除候选框大框套小框的情况。

在这里插入图片描述
非极大值抑制(Non-Maximum Suppression,NMS
作用:在同一个人脸的一堆候选框中,选出最可信的一个。
步骤1:将候选框按置信度降序排序
步骤2:第一个候选框依次与之后的框做 IOU, 大于设定阈值的框(认为同一个人脸)舍弃
步骤3:保留第一个候选框,剩余的候选框重复步骤1~步骤3,直至剩下一个框,保留。
最后保留下来的候选框就是 NMS 处理后的结果。

Soft-NMS 是对 NMS 的一种改进。

伪代码如图:
在这里插入图片描述

B: 初始检测框集合,S:对应检测框的分数, Nt :IOU的阈值,M :得分最高的检测框

NMS 的处理是将大于 IOU 阈值的框直接舍弃(分数置0),这样容易错过一些重合度较大的框。

Soft-NMS 的思路:根据 IOU 的值降低框的得分,最后根据分数阈值统一删除。
降低置信度的方法有两种:

  1. 线性加权(不连续)
  2. 高斯加权(连续)

这两种方法在实验中效果差别不大,因此代码中我选择第一种更简洁的形式。

def nms(boxes, thresh=0.3, is_min=False, softnms=False):
    if boxes.shape[0] == 0:
        return np.array([])
    _boxes = boxes[(-boxes[:, 14]).argsort()]    # 按置信度排序
    r_boxes = []

    while _boxes.shape[0] > 1:
        a_box = _boxes[0]
        b_boxes = _boxes[1:] 
        score = b_boxes[:, 14]
        r_boxes.append(a_box)

        if softnms:
            score_thresh = 0.5
            # IOU>阈值的框 置信度衰减
            t_idx = np.where(iou(a_box, b_boxes, is_min) > thresh)
            score[t_idx] *= (1 - iou(a_box, b_boxes, is_min))[t_idx]
            # 删除分数<阈值的框
            _boxes = np.delete(b_boxes, np.where(score < score_thresh), axis=0)
        else:
            # 筛选IOU<阈值的框
            index = np.where(iou(a_box, b_boxes, is_min) < thresh)
            _boxes = b_boxes[index]

    # 剩余最后1个框 保留
    if _boxes.shape[0] > 0:
        r_boxes.append(_boxes[0])

    # 把list组装成矩阵
    return np.stack(r_boxes<
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值