您的位置:首页 > 其它

基于MTCNN的人脸自动对齐技术原理及其Tensorflow实现测试

2018-02-02 14:30 751 查看
脸识别是计算机视觉研究领域的一个热点。而人脸识别包含了诸多步骤,其实现技术流程如下图所示(摘自http://www.techshino.com/upfiles/images/%E4%BA%BA%E8%84%B8%E8%AF%86%E5%88%AB%E6%8A%80%E6%9C%AF%E6%B5%81%E7%A8%8B(2).png):
https://github.com/AITTSMD/MTCNN-Tensorflow


       在上述过程中,人脸检测是非常关键的一步,特别是在大多数应用场景条件下,监控视频图像中问题包含了自然场景,而针对此类的应用,首要的是实现人脸检测。

      在人脸检测实现过程中,有个著名的MTCNN模型。该模型见论文:mtcnn:Joint
Face Detection and Alignment using Multi-task Cascaded Convolutional Neural Networks。其原理如下(图片摘自:http://img.blog.csdn.net/20160927151542441):



从上述原理图可以看出,该模型由三个步骤组成:

步骤一:P-NET,该步骤主要生成了一堆候选区域的边框,并采用NMS(非极大值)机制进行相应的合并。这与目标检测过程中的原理类似。

步骤二:R-NET,即对步骤一的结果再进一步细划,得到更精细的候选区域。

步骤三:O-NET,输出结果。(人脸边框和特征点位置)

上述三个模型的具体卷积细节原理如下图所示:



         下面基于Tensorflow进行实验,其中MTCNN相应的代码如下所示:

[python] view
plain copy

class PNet(Network):  

    def setup(self):  

        (self.feed('data') #pylint: disable=no-value-for-parameter, no-member  

             .conv(3, 3, 10, 1, 1, padding='VALID', relu=False, name='conv1')  

             .prelu(name='PReLU1')  

             .max_pool(2, 2, 2, 2, name='pool1')  

             .conv(3, 3, 16, 1, 1, padding='VALID', relu=False, name='conv2')  

             .prelu(name='PReLU2')  

             .conv(3, 3, 32, 1, 1, padding='VALID', relu=False, name='conv3')  

             .prelu(name='PReLU3')  

             .conv(1, 1, 2, 1, 1, relu=False, name='conv4-1')  

             .softmax(3,name='prob1'))  

  

        (self.feed('PReLU3') #pylint: disable=no-value-for-parameter  

             .conv(1, 1, 4, 1, 1, relu=False, name='conv4-2'))  

          

class RNet(Network):  

    def setup(self):  

        (self.feed('data') #pylint: disable=no-value-for-parameter, no-member  

             .conv(3, 3, 28, 1, 1, padding='VALID', relu=False, name='conv1')  

             .prelu(name='prelu1')  

             .max_pool(3, 3, 2, 2, name='pool1')  

             .conv(3, 3, 48, 1, 1, padding='VALID', relu=False, name='conv2')  

             .prelu(name='prelu2')  

             .max_pool(3, 3, 2, 2, padding='VALID', name='pool2')  

             .conv(2, 2, 64, 1, 1, padding='VALID', relu=False, name='conv3')  

             .prelu(name='prelu3')  

             .fc(128, relu=False, name='conv4')  

             .prelu(name='prelu4')  

             .fc(2, relu=False, name='conv5-1')  

             .softmax(1,name='prob1'))  

  

        (self.feed('prelu4') #pylint: disable=no-value-for-parameter  

             .fc(4, relu=False, name='conv5-2'))  

  

class ONet(Network):  

    def setup(self):  

        (self.feed('data') #pylint: disable=no-value-for-parameter, no-member  

             .conv(3, 3, 32, 1, 1, padding='VALID', relu=False, name='conv1')  

             .prelu(name='prelu1')  

             .max_pool(3, 3, 2, 2, name='pool1')  

             .conv(3, 3, 64, 1, 1, padding='VALID', relu=False, name='conv2')  

             .prelu(name='prelu2')  

             .max_pool(3, 3, 2, 2, padding='VALID', name='pool2')  

             .conv(3, 3, 64, 1, 1, padding='VALID', relu=False, name='conv3')  

             .prelu(name='prelu3')  

             .max_pool(2, 2, 2, 2, name='pool3')  

             .conv(2, 2, 128, 1, 1, padding='VALID', relu=False, name='conv4')  

             .prelu(name='prelu4')  

             .fc(256, relu=False, name='conv5')  

             .prelu(name='prelu5')  

             .fc(2, relu=False, name='conv6-1')  

             .softmax(1, name='prob1'))  

  

        (self.feed('prelu5') #pylint: disable=no-value-for-parameter  

             .fc(4, relu=False, name='conv6-2'))  

  

        (self.feed('prelu5') #pylint: disable=no-value-for-parameter  

             .fc(10, relu=False, name='conv6-3'))  

  

# 创建MTCNN模型  

def create_mtcnn(sess, model_path):  

    if not model_path:  

        model_path,_ = os.path.split(os.path.realpath(__file__))  

  

    with tf.variable_scope('pnet'):  

        data = tf.placeholder(tf.float32, (None,None,None,3), 'input')  

        pnet = PNet({'data':data})  

        pnet.load(os.path.join(model_path, 'det1.npy'), sess)  

    with tf.variable_scope('rnet'):  

        data = tf.placeholder(tf.float32, (None,24,24,3), 'input')  

        rnet = RNet({'data':data})  

        rnet.load(os.path.join(model_path, 'det2.npy'), sess)  

    with tf.variable_scope('onet'):  

        data = tf.placeholder(tf.float32, (None,48,48,3), 'input')  

        onet = ONet({'data':data})  

        onet.load(os.path.join(model_path, 'det3.npy'), sess)  

          

    pnet_fun = lambda img : sess.run(('pnet/conv4-2/BiasAdd:0', 'pnet/prob1:0'), feed_dict={'pnet/input:0':img})  

    rnet_fun = lambda img : sess.run(('rnet/conv5-2/conv5-2:0', 'rnet/prob1:0'), feed_dict={'rnet/input:0':img})  

    onet_fun = lambda img : sess.run(('onet/conv6-2/conv6-2:0', 'onet/conv6-3/conv6-3:0', 'onet/prob1:0'), feed_dict={'onet/input:0':img})  

    return pnet_fun, rnet_fun, onet_fun  

       在LFW数据集进行测试,发现结果还是相当的好。测试的结果如下:


 
   



 
   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: