基于Mxnet实现MTCNN人脸识别【附部分源码】


前言

本文基于MxNet实现人脸识别,使用算法MTCNN


一、MTCNN

论文地址:https://arxiv.org/ftp/arxiv/papers/1604/1604.02878.pdf
网络结构:
在这里插入图片描述

  首先将图像重新缩放为不同大小的范围(称为图像金字塔),然后第一个模型(Proposal Network 或 P-Net)提出候选面部区域;第二个模型(Refine Network 或 R-Net)过滤边界框;第三个模型(Output Network或 O-Net)输出边界框和面部特征点位置。
  上图表示 CNN 三个阶段。在第一阶段,它通过浅层 CNN 快速生成候选窗口。然后,它通过更复杂的 CNN 对窗口进行细化以拒绝大量非人脸窗口。最后,它使用更强大的 CNN 来细化结果并输出面部标志位置。
  模型被称为多任务网络,因为级联中的三个模型(P-Net、R-Net 和 O-Net)中的每一个都在三个任务上进行训练,例如进行三种类型的预测:人脸分类、边界框回归和人脸 landmark 定位。
  三个模型不直接连接,相反,前一阶段的输出作为输入送到下一阶段。这允许在阶段之间执行额外的处理;例如,非极大值抑制 (NMS) 用于在将第一阶段 P-Net 提出的候选边界框提供给第二阶段 R-Net 模型之前对其进行过滤。

  • 候选网络 (P-Net):该网络结构主要获得了人脸区域的候选窗口和边界框的回归向量,并用该边界框做回归,对候选窗口进行校准,然后通过非极大值抑制 (NMS) 来合并高度重叠的候选框。
  • 细化网络 (R-Net):该网络结构还是通过边界框的回归和 NMS 来去掉那些假正例的区域。只是由于该网络结构和P-Net网络结构有差异,多了一个全连接层,所以会取得更好的抑制假正例的作用。
  • 输出网络 (O-Net):该层比 R-Net 层又多了一层卷积层,所以处理的结果会更精细。作用和 R-Net 层作用一样。但是该层对人脸区域进行了更多的监督,同时还会输出 人脸的5 个 Landmark(界标)。

二、代码实现

1.引入库

import os,time,math,cv2
import numpy as np
from multiprocessing import Pool
from itertools import repeat
import mxnet as mx

2.函数定义

nms

def nms(boxes, overlap_threshold, mode='Union'):
    if len(boxes) == 0:
        return []
    if boxes.dtype.kind == "i":
        boxes = boxes.astype("float")
    pick = []
    x1, y1, x2, y2, score = [boxes[:, i] for i in range(5)]
    area = (x2 - x1 + 1) * (y2 - y1 + 1)
    idxs = np.argsort(score)
    while len(idxs) > 0:
        last = len(idxs) - 1
        i = idxs[last]
        pick.append(i)
        xx1 = np.maximum(x1[i], x1[idxs[:last]])
        yy1 = np.maximum(y1[i], y1[idxs[:last]])
        xx2 = np.minimum(x2[i], x2[idxs[:last]])
        yy2 = np.minimum(y2[i], y2[idxs[:last]])
        w = np.maximum(0, xx2 - xx1 + 1)
        h = np.maximum(0, yy2 - yy1 + 1)
        inter = w * h
        if mode == 'Min':
            overlap = inter / np.minimum(area[i], area[idxs[:last]])
        else:
            overlap = inter / (area[i] + area[idxs[:last]] - inter)
        idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlap_threshold)[0])))
    return pick

PNet处理代码

total_boxes = []
for batch in sliced_index:
      local_boxes = self.Pool.map(detect_first_stage_warpper,zip(repeat(img), self.PNets[:len(batch)], [scales[i] for i in batch], repeat(self.threshold[0])))
      total_boxes.extend(local_boxes)

  total_boxes = [i for i in total_boxes if i is not None]

  if len(total_boxes) == 0:
      return None

RNet处理代码

input_buf = np.zeros((num_box, 3, 24, 24), dtype=np.float32)
for i in range(num_box):
    tmp = np.zeros((tmph[i], tmpw[i], 3), dtype=np.uint8)
    tmp[dy[i]:edy[i] + 1, dx[i]:edx[i] + 1, :] = img[y[i]:ey[i] + 1, x[i]:ex[i] + 1, :]
    input_buf[i, :, :, :] = adjust_input(cv2.resize(tmp, (24, 24)))

output = self.RNet.predict(input_buf)

passed = np.where(output[1][:, 1] > self.threshold[1])
total_boxes = total_boxes[passed]

if total_boxes.size == 0:
    return None

ONet处理代码

input_buf = np.zeros((num_box, 3, 48, 48), dtype=np.float32)

for i in range(num_box):
     tmp = np.zeros((tmph[i], tmpw[i], 3), dtype=np.float32)
     tmp[dy[i]:edy[i] + 1, dx[i]:edx[i] + 1, :] = img[y[i]:ey[i] + 1, x[i]:ex[i] + 1, :]
     input_buf[i, :, :, :] = adjust_input(cv2.resize(tmp, (48, 48)))

 output = self.ONet.predict(input_buf)

 passed = np.where(output[2][:, 1] > self.threshold[2])
 total_boxes = total_boxes[passed]

 if total_boxes.size == 0:
     return None

LNet处理代码

关键点代码

input_buf = np.zeros((num_box, 15, 24, 24), dtype=np.float32)
for i in range(5):
    x, y = points[:, i], points[:, i + 5]
    x, y = np.round(x - 0.5 * patchw), np.round(y - 0.5 * patchw)
    [dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph] = self.pad(np.vstack([x, y, x + patchw - 1, y + patchw - 1]).T,
                                                            width,
                                                            height)
    for j in range(num_box):
        tmpim = np.zeros((tmpw[j], tmpw[j], 3), dtype=np.float32)
        tmpim[dy[j]:edy[j] + 1, dx[j]:edx[j] + 1, :] = img[y[j]:ey[j] + 1, x[j]:ex[j] + 1, :]
        input_buf[j, i * 3:i * 3 + 3, :, :] = adjust_input(cv2.resize(tmpim, (24, 24)))

output = self.LNet.predict(input_buf)

pointx = np.zeros((num_box, 5))
pointy = np.zeros((num_box, 5))

效果

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习的广东仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值