赞
踩
MTCNN 是多任务级联 CNN 的人脸检测深度学习模型,该模型不仅考虑了人脸检测概率,还综合训练了人脸边框回归和面部关键点检测,多任务同时建立 loss function 并训练,因此为 MTCNN。级联 CNN 主要由三个子网络组成:P-Net、R-Net 和 O-Net。博主通过PyQt5开发一个可视化的MTCNN人脸检测器,深度学习框架采用PyTorch。
从网络结构上看,P-Net 接受大小为 (12,12,3) 的图片的输入,输出三种特征图,大小为 (1,1,C),也就是说最终得到的特征图每一点都对应着一个大小为 12×12 的感受野。三种输出如下:
建议:
由于 P-Net 是对输出特征图的每一个像素进行预测,因此结果十分冗杂,所以接下来使用 R-Net 进一步优化。R-Net 和 P-Net 类似,不过这一步的输入是前面 P-Net 生成的边界框,不管实际边界框的大小,在输入 R-Net 之前,都需要缩放到 (24,24,3)。网络的输出和 P-Net 是一样的。这一步的目的主要是为了去除大量的非人脸框。
进一步将 R-Net 的所得到的区域缩放到 (48,48,3),输入到最后的 O-Net,O-Net 的结构与 P-Net 类似,只不过在测试输出的时候多了关键点位置的输出。输入大小为 (48,48,3) 的图像,输出包含 n 个人脸概率、边界框的偏移量和关键点的偏移量。三个子网络流程如下:
进一步将 R-Net 的所得到的区域缩放到 (48,48,3),输入到最后的 O-Net,O-Net 的结构与 P-Net 类似,只不过在测试输出的时候多了关键点位置的输出。输入大小为 (48,48,3) 的图像,输出包含 n 个人脸概率、边界框的偏移量和关键点的偏移量。三个子网络流程如下:
MTCNN基于卷积神经网络,通常只适用于检测一定尺寸范围内的人脸,比如其中的 P-Net,用于判断 12 × 12 大小范围内是否含有人脸,但是输入图像中人脸的尺寸未知,需要构建图像金字塔获得不同尺寸的图像,缩放图像是为了将图像中的人脸缩放到网络能检测的适宜尺寸,只要某个人脸被放缩到12×12左右,就可以被检测出来,下图为MTCNN人脸检测流程。
在人脸检测中,通常要设置要原图中要检测的最小人脸尺寸,原图中小于这个尺寸的人脸不必关心,MTCNN 代码中为 minsize = 20
,MTCNN P-Net 用于检测 12 × 12 大小的人脸,这需要我们将不同的人脸大小都要缩放到 12 × 12。在 P-Net 中我们为什么可以对输出特征图中的每一个像素方格进行预测,正是因为原图中的人脸都被缩放到 12 × 12,而且输出特征图的感受野正是 12 × 12。
建议:
人脸检测中的图像金字塔构建,涉及如下数据:
(h, w)
;min_face_size
;max_face_size
,如果不设置,为图像高宽中较短的那个;net_face_size
;factor
;缩放图像是为了将图像中的人脸缩放到网络能检测的适宜尺寸,图像金字塔中:
max_scale = net_face_size / min_face_size
;min_scale = net_face_size / max_face_size
;scale_n = max_scale * (factor ^ n)
;(h_n, w_n) = (h * scale_n, w_n * scale_n)
;min(h_n, w_n) >net_face_size
。注: 缩小比例为缩放尺寸的倒数。
在 MTCNN 的实际测试中,如果输入图像为 (100,120),其中人脸最小为 (20,20),最大为 (20,20)——对应图像较短边长,为了将人脸放缩到 (12,12),同时保证相邻层间缩放比率 factor = 0.709
,依据上述公式则最大缩放尺度为 12 / 20,最小缩放尺度为 12 / 20,金字塔中图像尺寸依次为 (60,72)、(52,61)、(36,43)、(26,31)、(18,22)、(13,16),其中 (60,72) 对应把 (20,20) 的人脸缩放到 (12,12),(13,16)对应把 (100,100) 的人脸缩放到 (12,12),在保证缩放比率一致的情况下近似。
综上,构建图像金字塔有两个步骤:
给定输入图像,根据设置的最小人脸尺寸以及网络能检测的人脸尺寸,确定最大缩放图像和最小缩放图像;
根据设置的金字塔层间缩放比率,确定每层图像的尺寸。
如果新同学不知道如何配置环境,可以参考博主写的【Anaconda3与PyCharm安装配置保姆教程】
此外,cv2无法读取中文路径图像的解决方案,具体可以参考博主写的文章【opencv-python[cv2]读取中文路径图像】
代码如下(示例):
import numpy as np from mtcnn import FaceDetector from PIL import Image import cv2 # 人脸检测对象。优先使用GPU进行计算(会自动判断GPU是否可用) # 你也可以通过设置 FaceDetector("cpu") 或者 FaceDetector("cuda") 手动指定计算设备 detector = FaceDetector() image = Image.open("./images/image.jpg") # 检测人脸,返回人脸位置坐标 # 其中bboxes是一个n*5的列表、landmarks是一个n*10的列表,n表示检测出来的人脸个数,数据详细情况如下: # bbox:[左上角x坐标, 左上角y坐标, 右下角x坐标, 右下角y坐标, 检测评分] # landmark:[右眼x, 左眼x, 鼻子x, 右嘴角x, 左嘴角x, 右眼y, 左眼y, 鼻子y, 右嘴角y, 左嘴角y] bboxes, landmarks = detector.detect(image) # 绘制并保存标注图 drawed_image = detector.draw_bboxes(image) img_cv= cv2.cvtColor(np.asarray(drawed_image),cv2.COLOR_RGB2BGR) cv2.imshow('face', np.asarray(img_cv)) cv2.waitKey(0)
代码如下(示例):
import cv2 from mtcnn import FaceDetector from PIL import Image import numpy detector = FaceDetector() def camera_detect(): video = cv2.VideoCapture(0) while True: ret, frame = video.read() # 将 OpenCV 格式的图片转换为 PIL.Image pil_im = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # 绘制带人脸框的标注图 drawed_pil_im = detector.draw_bboxes(pil_im) # 再转回 OpenCV 格式用于视频显示 frame = cv2.cvtColor(numpy.asarray(drawed_pil_im), cv2.COLOR_RGB2BGR) cv2.imshow("Face Detection", frame) # 输入 q 的时候结束循环(退出检测程序) if cv2.waitKey(1) & 0xFF == ord("q"): break video.release() cv2.destroyAllWindows() if __name__ == "__main__": camera_detect()
由于博主能力有限,本篇文章中提及的方法,也难免会有疏漏之处,希望您能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。