mtcnn人脸识别(代码片段)

the-home-of-123 the-home-of-123     2023-01-12     279

关键词:

最近看了一些人脸识别的综述及几篇经典论文。这里简单记录下MTCNN论文及Tensorflow的复现过程。感觉人脸检测属于目标检测下的一个方向,不过由通用目标检测改为人脸检测,即多分类改为2分类,且为小目标检测。而且人脸检测还加上了关键点检测,可以依靠关键点增加召回率。主要思想还是依靠的通用目标检测,除了yolo和R-CNN系列,还多出的一个算法系列为级联网络结构,MTCNN为其中一个代表。以前讲过通用目标检测的两种方法,这次主要讲一下级联网络的MTCNN这一种方案。

附带一句我理解的阅读论文思路。首先看综述,梳理脉络。之后找到经典方法即有重大突破的几个节点,之后搜该方法的博客,明白大致意思。之后看论文,因为论文中细节更加丰富,之后结合论文,看源码,进行复现。源码是用的其他人的,非本人写的

主要参考博客https://blog.csdn.net/qq_41044525/article/details/80820255

https://zhuanlan.zhihu.com/p/31761796

MTCNN分为三个网络,P-net,R-Net,O-Net. 先来下预测部分总体流程图(我只复现了预测部分源码,不过会讲一下loss函数)。

 

技术分享图片

1. Stage 1  

技术分享图片

 

与训练时不同,单预测部分来说,输入图片非固定大小,而是将原图进行缩放,生成图像金字塔,即系列的图片,最小规格为12*12的。R-net网络结构如图,整体可看成将原图整图进行卷积(利用12*12,strides=2),之后生成预测的分类及位置偏移(无脸部关键点),网络输出中每一个1*1的方格映射到原图的感受野为12*12。由此生成系列的预测值,由此可认为输入为12*12大小。网络部分代码就不列出了,就一个网络结构,很好理解。预处理代码如下:

###作用是将原图整图输入,生成图像金字塔,输入网络中,以增加准确性。
    factor_count=0
    total_boxes=np.empty((0,9))
    points=[]
    h=img.shape[0]
    w=img.shape[1]
    minl=np.amin([h, w])
    m=12.0/minsize
    minl=minl*m
    # creat scale pyramid
    scales=[]
    while minl>=12:
        scales += [m*np.power(factor, factor_count)]
        minl = minl*factor
        factor_count += 1

    # first stage  ###将产生的最小为12*12系列的图片送入pnet网络中,获得输出的回归框。scale为缩放比例,可以用来推测在原图中的坐标
    for j in range(len(scales)):
        scale=scales[j]
        hs=int(np.ceil(h*scale))
        ws=int(np.ceil(w*scale))
        im_data = imresample(img, (hs, ws)) ###此时输入非12*12,而是每一个单元的感受野为12,这样每一块就生成了系列的预测框
        im_data = (im_data-127.5)*0.0078125
        img_x = np.expand_dims(im_data, 0)
        img_y = np.transpose(img_x, (0,2,1,3))
        out = pnet(img_y)  ###输入pnet网络中,获得输出
        out0 = np.transpose(out[0], (0,2,1,3))   ###二分类,即为人脸的概率
        out1 = np.transpose(out[1], (0,2,1,3))  ###预测框偏移回归  out0 size(1,H/12,W/12,2)
out1 size(1,H/12,W/12,4)
  ##输出为第一层的预测框坐标合集,如何产生系列的预测框。
boxes, _ = generateBoundingBox(out1[0,:,:,1].copy(), out0[0,:,:,:].copy(), scale, threshold[0]) 

  下面是genereteBoundingBox代码.函数最用为输出第一层每12*12大小的坐标,偏移,及预测得分

def generateBoundingBox(imap, reg, scale, t):   ###reg为偏移 imag为是否为正类 scal缩小的比例 t 为阈值
    # use heatmap to generate bounding boxes
    stride=2
    cellsize=12
    #### 转置计算很常见,目的只要为了方便比大小,做运算。通用目标检测中也常用,对位置坐标进行转置
    imap = np.transpose(imap)
    dx1 = np.transpose(reg[:,:,0])
    dy1 = np.transpose(reg[:,:,1])
    dx2 = np.transpose(reg[:,:,2])
    dy2 = np.transpose(reg[:,:,3])
    y, x = np.where(imap >= t)  ###筛选出大于阈值的坐标。因为每个小单元格有一个预测概率值,四个坐标偏移值 H/12,W/12,y,x可看成index
    if y.shape[0]==1:
        dx1 = np.flipud(dx1)
        dy1 = np.flipud(dy1)
        dx2 = np.flipud(dx2)
        dy2 = np.flipud(dy2)
    score = imap[(y,x)]  ###得分即为预测为人脸的概率,筛选大于阈值的预测框得分
    reg = np.transpose(np.vstack([ dx1[(y,x)], dy1[(y,x)], dx2[(y,x)], dy2[(y,x)] ])) ###预测为满足条件的人脸image预测框坐标偏移
    if reg.size==0:
        reg = np.empty((0,3))
    bb = np.transpose(np.vstack([y,x]))
    ###为何*2+1?应该为*2+4? q1,q2值应为在原图中每一个预测框的左上角,右下角坐标
    q1 = np.fix((stride*bb+1)/scale)
    q2 = np.fix((stride*bb+cellsize-1+1)/scale)
    boundingbox = np.hstack([q1, q2, np.expand_dims(score,1), reg])
    return boundingbox, reg  ##返回每一个12*12块大小的坐标及对应偏移及该块得分

  之后对预测值进行修正,预修剪,产生proposal的坐标,将预测出的回归框部分提取出来,以便输入到第二个网络中。代码如下

 1        # inter-scale nms  对预测出的预测框进行nms,筛选预测框
 2         pick = nms(boxes.copy(), 0.5, Union)
 3         if boxes.size>0 and pick.size>0:
 4             boxes = boxes[pick,:]
 5             total_boxes = np.append(total_boxes, boxes, axis=0)
 6 
 7     numbox = total_boxes.shape[0] ####筛选出的预测框个数
 8     if numbox>0:
 9         pick = nms(total_boxes.copy(), 0.7, Union) ###提高阈值,进一步进行nms
10         total_boxes = total_boxes[pick,:]
11         regw = total_boxes[:,2]-total_boxes[:,0]
12         regh = total_boxes[:,3]-total_boxes[:,1]
13         qq1 = total_boxes[:,0]+total_boxes[:,5]*regw
14         qq2 = total_boxes[:,1]+total_boxes[:,6]*regh
15         qq3 = total_boxes[:,2]+total_boxes[:,7]*regw
16         qq4 = total_boxes[:,3]+total_boxes[:,8]*regh
17         total_boxes = np.transpose(np.vstack([qq1, qq2, qq3, qq4, total_boxes[:,4]]))###依次为修正后的左上角,右下角坐标及该部分得分
18         total_boxes = rerec(total_boxes.copy())    ####使预测框变为正方形
19         total_boxes[:,0:4] = np.fix(total_boxes[:,0:4]).astype(np.int32) ##取整
20         dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph = pad(total_boxes.copy(), w, h)  #####对坐标进行修剪,使其不超出图片大小

2.  Stage 2

技术分享图片

网络结构如图所示。此时的输入必须为24*24大小,输入的图像为stage1产生的porposals,抠出来,输入到stage2中。此处很像Faster-RCNN的第一步,初步筛选出纯图像,将不相关部分过滤掉。这也是级联的意义。注,预测网络输出同样只有得分与预测框坐标修正,无关键点信息。以下为代码,与第一步很相似。

 1 numbox = total_boxes.shape[0]
 2     if numbox>0: ###由第一步得出的预测框,在原图进行裁剪,resize,输入到第R-Net中
 3         # second stage
 4         tempimg = np.zeros((24,24,3,numbox))
 5         for k in range(0,numbox):
 6             tmp = np.zeros((int(tmph[k]),int(tmpw[k]),3))
 7             tmp[dy[k]-1:edy[k],dx[k]-1:edx[k],:] = img[y[k]-1:ey[k],x[k]-1:ex[k],:]
 8             if tmp.shape[0]>0 and tmp.shape[1]>0 or tmp.shape[0]==0 and tmp.shape[1]==0:
 9                 tempimg[:,:,:,k] = imresample(tmp, (24, 24))  ####将porposalsresize成24*24大小。
10             else:
11                 return np.empty()
12         tempimg = (tempimg-127.5)*0.0078125
13         tempimg1 = np.transpose(tempimg, (3,1,0,2))
14         out = rnet(tempimg1) ###输入到R-Net中得到输出
15         out0 = np.transpose(out[0])  ####预测框坐标偏置
16         out1 = np.transpose(out[1])   ######预测得分
17         score = out1[1,:]
18         ##第一步中筛选出的预测框坐标。此时的坐标为原图中的坐标偏移,并非resize之后的坐标偏置。即直接将偏移加到原图中坐标即可
19         ipass = np.where(score>threshold[1])
20         total_boxes = np.hstack([total_boxes[ipass[0],0:4].copy(), np.expand_dims(score[ipass].copy(),1)]) 
21         mv = out0[:,ipass[0]] ###第二步得出的偏移值
22         if total_boxes.shape[0]>0:
23             pick = nms(total_boxes, 0.7, Union)
24             total_boxes = total_boxes[pick,:] ###先nms,第一步中调高阈值
25             total_boxes = bbreg(total_boxes.copy(), np.transpose(mv[:,pick])) ####加偏移后的坐标
26             total_boxes = rerec(total_boxes.copy())###变为正方形

3. Stage 3

技术分享图片

第三步网络没什么好说的,和第二步一样的流程。不过此时多了一个关键点预测。最后得到了结果。

 1 numbox = total_boxes.shape[0]
 2     if numbox>0:
 3         # third stage  ###仿照第二步,将第二步得出的预测图像输入到第三个网络中
 4         total_boxes = np.fix(total_boxes).astype(np.int32)
 5         dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph = pad(total_boxes.copy(), w, h)
 6         tempimg = np.zeros((48,48,3,numbox))
 7         for k in range(0,numbox):
 8             tmp = np.zeros((int(tmph[k]),int(tmpw[k]),3))
 9             tmp[dy[k]-1:edy[k],dx[k]-1:edx[k],:] = img[y[k]-1:ey[k],x[k]-1:ex[k],:]
10             if tmp.shape[0]>0 and tmp.shape[1]>0 or tmp.shape[0]==0 and tmp.shape[1]==0:
11                 tempimg[:,:,:,k] = imresample(tmp, (48, 48))
12             else:
13                 return np.empty()
14         tempimg = (tempimg-127.5)*0.0078125
15         tempimg1 = np.transpose(tempimg, (3,1,0,2))
16         out = onet(tempimg1)
17         out0 = np.transpose(out[0])
18         out1 = np.transpose(out[1])
19         out2 = np.transpose(out[2])
20         score = out2[1,:]
21         points = out1
22         ipass = np.where(score>threshold[2])
23         points = points[:,ipass[0]]
24         total_boxes = np.hstack([total_boxes[ipass[0],0:4].copy(), np.expand_dims(score[ipass].copy(),1)])
25         mv = out0[:,ipass[0]]
26 
27         w = total_boxes[:,2]-total_boxes[:,0]+1
28         h = total_boxes[:,3]-total_boxes[:,1]+1
29         points[0:5,:] = np.tile(w,(5, 1))*points[0:5,:] + np.tile(total_boxes[:,0],(5, 1))-1
30         points[5:10,:] = np.tile(h,(5, 1))*points[5:10,:] + np.tile(total_boxes[:,1],(5, 1))-1
31         if total_boxes.shape[0]>0:
32             total_boxes = bbreg(total_boxes.copy(), np.transpose(mv))
33             pick = nms(total_boxes.copy(), 0.7, Min)
34             total_boxes = total_boxes[pick,:]
35             points = points[:,pick]
36                 
37     return total_boxes, points  ####得出最终的预测值

此处只有预测部分的代码,在训练时,有一个与其他目标检测不同的地方在于,有5个人关键点检测,也计入了损失函数中,以此进行训练,可增加识别的准确性。

来勉强解读一下。。这部分看的很粗略。

1. 脸分类损失函数。交叉熵损失函数

技术分享图片

2. 预测框损失函数。 平方损失

技术分享图片

3. 关键点损失函数。同样为平方损失

技术分享图片

3. 综合训练,整体损失函数。每部分网络的权重不同。

技术分享图片

 



21个项目玩转深度学习:基于tensorflow的实践详解06—人脸检测和识别——mtcnn人脸检测(代码片段)

本篇主要讲述利用MTCNN的预训练模型得到原图中人脸的分割,代码如下:https://github.com/davidsandberg/facenet结合博客https://blog.csdn.net/FortiLZ/article/details/81396566?tdsourcetag=s_pctim_aiomsg看起来省力些要是对MTCNN的训练过程感兴趣的,可以看h... 查看详情

使用 MTCNN 进行人脸识别

】使用MTCNN进行人脸识别【英文标题】:FaceRecognitionusingMTCNN【发布时间】:2021-07-2711:28:44【问题描述】:我在尝试运行的代码中遇到错误。AttributeError:模块\'facedetector_m\'没有属性FaceDetectorClassfromfacenet_pytorchimportMTCNNimportfacedetector_... 查看详情

人脸识别基于mctnn人脸检测(pytorch)(代码片段)

...aster·faciallab/FaceDetector·GitHub中文翻译:从零开始搭建人脸识别系统(一)MTCNN-知乎1、网络结构mtcnn算法人脸检测过程分为三个独立的stage,每一个stage对应一个卷积网络,分别 查看详情

什么是mtcnn人脸识别能力?

】什么是mtcnn人脸识别能力?【英文标题】:Whatismtcnnfacerecognitionpower?【发布时间】:2021-07-2422:55:50【问题描述】:我正在研究人脸识别的oneshot学习首先我必须在帧中检测人脸,我将它与mtcnn一起使用,但它不能正常工作......我... 查看详情

人脸检测和对齐算法mtcnn(代码片段)

1.概述人脸识别在实际的生活中有着广泛的应用,得益于深度学习的发展,使得人脸识别的准确率得到大幅度提升。然而,为了做好人脸识别,第一步需要做的是对人脸检测,主要是通过对图片分析,定位... 查看详情

人脸检测和对齐算法mtcnn(代码片段)

1.概述人脸识别在实际的生活中有着广泛的应用,得益于深度学习的发展,使得人脸识别的准确率得到大幅度提升。然而,为了做好人脸识别,第一步需要做的是对人脸检测,主要是通过对图片分析,定位... 查看详情

mtcnn实时人脸检测网络详解与opencv+tensorflow代码演示(代码片段)

MTCNN模型概述多任务卷积神经网络(MTCNN)实现人脸检测与对齐是在一个网络里实现了人脸检测与五点标定的模型,主要是通过CNN模型级联实现了多任务学习网络。整个模型分为三个阶段,第一阶段通过一个浅层的CNN网络快速产生一... 查看详情

mtcnn移植安卓并检测视频中人脸(代码片段)

...xff0c;使用vlc播放了rtsp流媒体视频后,想检测视频中的人脸,之前采用了opencv但是遇到低头、抬头和侧脸时候,效果就不太好。所以本篇介绍如何使用mtcnn来检测视频中的人脸。在这里也免费发布了一个chat希望朋友能... 查看详情

使用tensorrt对人脸检测网络mtcnn进行加速(代码片段)

前言最近在做人脸比对的工作,需要用到人脸关键点检测的算法,比较成熟和通用的一种算法是MTCNN,可以同时进行人脸框选和关键点检测,对于每张脸输出5个关键点,可以用来进行人脸对齐。问题刚开始准备对齐人脸图片用于... 查看详情

人脸检测5种方法(代码片段)

众所周知,人脸识别是计算机视觉应用的一个重大领域,在学习人脸识别之前,我们先来简单学习下人脸检测的几种用法。常见的人脸检测方法大致有5种,Haar、Hog、CNN、SSD、MTCNN:注:本文章图片来源于... 查看详情

人脸检测——mtcnn

本次介绍一篇速度还不错的人脸检测文章:《2016JointFaceDetectionandAlignmentusingMulti-taskCascadedConvolutionalNetworks》.源代码作者刚刚公布,效果相当不错(只有测试代码):https://kpzhang93.github.io/MTCNN_face_d 查看详情

PyTorch resnet 坏张量维度

...2021-10-2305:23:16【问题描述】:我正在尝试使用Pytorch设置人脸检测/识别管道。我使用opencv加载图像image=cv2.imread(\'...\')我加载了mtcnn人脸检测和resnet人脸识别模型self.mtcnn=MTCNN(keep_all=True,device=se 查看详情

基于yolo的人脸检测与人脸对齐(代码片段)

...同时可以对对象的特征点进行回归,最常见的用例是人脸检测与人脸对齐同步完成。将人脸检测和人脸对齐同步完成,mtcnn已经做了类型的事情:由图可见,mtcnn使用了三个卷积神经网络实现了人脸检测和人脸对齐,... 查看详情

C ++中的Mtcnn人脸对齐

】C++中的Mtcnn人脸对齐【英文标题】:MtcnnfacealignmentinC++【发布时间】:2019-07-1802:21:28【问题描述】:我可以在mtcnn中检测人脸并拥有对齐所需的人脸点。我找不到一个很好的例子,如何将mtcnn中的面与c++对齐?如何在opencv中对齐... 查看详情

MTCNN 与 DLIB 相比如何进行人脸检测?

】MTCNN与DLIB相比如何进行人脸检测?【英文标题】:HowdoesMTCNNperformvsDLIBforfacedetection?【发布时间】:2018-06-0910:18:46【问题描述】:我看到MTCNN被推荐,但没有看到DLIB和MTCNN的直接比较。我认为既然MTCNN使用神经网络,它可能更适... 查看详情

csharp人脸识别(代码片段)

查看详情

tensorflow 2.0中是不是有mtcnn人脸检测的实现?

】tensorflow2.0中是不是有mtcnn人脸检测的实现?【英文标题】:Isthereanyimplementationofmtcnnfacedetectionintensorflow2.0?tensorflow2.0中是否有mtcnn人脸检测的实现?【发布时间】:2020-01-0512:35:34【问题描述】:最近我搬到了tensorflow==2.0.0-rc0,现... 查看详情

人脸识别《一》opencv人脸识别之人脸检测(代码片段)

opencv中已经有人脸识别的功能了,所以来看看整个流程以及具体实现吧。人脸识别:就是给一个已知人脸贴上一个标签。上面这句简单的话,其实包含的信息量好大啊,这说明首先你要知道这是一张脸,然后... 查看详情