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

来源:互联网 发布:手机淘宝怎么交水电费 编辑:程序博客网 时间:2024/06/05 06:51

        人脸识别是计算机视觉研究领域的一个热点。而人脸识别包含了诸多步骤,其实现技术流程如下图所示(摘自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):



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


      在人脸检测实现过程中,有个著名的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相应的代码如下所示:

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数据集进行测试,发现结果还是相当的好。测试的结果如下:

     

     


阅读全文
1 0