查看原文
其他

人脸识别介绍及在vs2013下的编译测试(附代码)

区分不同的人是很多智能系统的必备能力。为实现此目的,一种可能的技术手段是通过对人脸的光学成像来感知人、识别人,即所谓的人脸识别技术。经过几十年的研发积累,特别是近年来深度学习技术的涌现,人脸识别取得了长足的进步,在安防、金融、教育、社保等领域得到了越来越多的应用,成为计算机视觉领域最为成功的分支领域之一。

然而,人脸识别并非完全成熟的技术,离公众期望的全面应用尚有距离,还需要学术界、工业界的共同努力。为此,整个人脸识别社区需要有基准(Baseline)系统,而且基准系统的水平显然会极大影响着该领域的发展水平。可是令人尴尬的是,这个领域迄今尚无一套包括所有技术模块的、完全开源的基准人脸识别系统!

我们希望改变现状,因此开源了SeetaFace人脸识别引擎。该引擎由中科院计算所山世光研究员带领的人脸识别研究组研发。代码基于C++实现,且不依赖于任何第三方的库函数,开源协议为BSD-2,可供学术界和工业界免费使用。

SeetaFace人脸识别引擎包括了搭建一套全自动人脸识别系统所需的三个核心模块,即:人脸检测模块SeetaFace Detection、面部特征点定位模块SeetaFace Alignment以及人脸特征提取与比对模块 SeetaFace Identification。其中,SeetaFace Detection采用了一种结合传统人造特征与多层感知机(MLP)的级联结构,在FDDB上达到了84.4%的召回率(100个误检时),并可在单个i7 CPU上实时处理VGA分辨率的图像。面部特征点定位模块SeetaFace Alignment通过级联多个深度模型(栈式自编码网络)来回归5个关键特征点(两眼中心、鼻尖和两个嘴角)的位置,在AFLW数据库上达到state-of-the-art的精度,定位速度在单个i7 CPU上超过200fps。
人脸识别模块SeetaFace Identification采用一个9层的卷积神经网络(CNN)来提取人脸特征,在LFW数据库上达到97.1%的精度(注:采用SeetaFace人脸检测和SeetaFace面部特征点定位作为前端进行全自动识别的情况下),特征提取速度为每图120ms(在单个i7 CPU上)。

下面对上述三个模块的情况做简要介绍,更详细的介绍请参考我们相应的学术论文。

人脸检测模块SeetaFace Detection
该模块基于我们提出的一种结合经典级联结构和多层神经网络的人脸检测方法[1]实现,其所采用的漏斗型级联结构(Funnel-Structured Cascade,FuSt)专门针对多姿态人脸检测而设计,其中引入了由粗到精的设计理念,兼顾了速度和精度的平衡。

如图1所示,FuSt级联结构在顶部由多个针对不同姿态的快速LAB级联分类器[2]构成,紧接着是若干个基于SURF特征的多层感知机(MLP)级联结构,最后由一个统一的MLP级联结构(同样基于SURF特征)来处理所有姿态的候选窗口,整体上呈现出上宽下窄的漏斗形状。从上往下,各个层次上的分类器及其所采用的特征逐步变得复杂,从而可以保留人脸窗口并排除越来越难与人脸区分的非人脸候选窗口。
图1. SeetaFace人脸检测模块所采用的FuSt漏斗型级联结构[1]
与SeetaFace Detection开源代码配套开放的是一个准正面人脸检测模型(使用了约20万人脸图像训练而来),可以实现准正面人脸的准确检测(旋转角度约45度以内,但对于姿态偏转较大的人脸也具备一定的检测能力),图2给出了一些检测结果的示例(注:测试时图像金字塔下采样比例设置为0.8,滑动步长设置为4和2,最小人脸设置为20x20)。
在人脸检测领域最重要的评测集FDDB上对SeetaFace Detector进行评测,在输出100个误检时(FPPI=0.035)召回率达到84.4%,输出1000个误检时召回率达到88.0%。图3则给出了SeetaFace Detector在FDDB上的离散型得分ROC曲线,并与其它已发表的学术界公开结果(从FDDB官网获得)进行了对比。不难看出,尽管SeetaFace人脸检测器并非目前精度最高的,但在学术界公开的结果中仍然具有很强的竞争力,而且可以完全满足多数人脸识别系统的需求。
图2. SeetaFace Detection人脸检测结果的示例
图3. SeetaFace Detector在FDDB上的ROC曲线
此外,与其他算法相比,SeetaFace Detector在速度上有一定优势。对于640x480大小的VGA图像,检测速度的对比情况如表1所示。其中,SeetaFace的速度在单个3.40GHz的i7-3770 CPU上测得,Cascade CNN[3]在CPU上的速度在2.0GHz的CPU上测得(引自原文)。而各方法在GPU上的速度在NVIDIA Titan Black GPU上测得。

特征点定位模块SeetaFace Alignment
面部特征点定位(人脸对齐)在人脸识别、表情识别、人脸动画合成等诸多人脸分析任务中扮演着非常重要的角色。由于姿态、表情、光照和遮挡等因素的影响,真实场景下的人脸对齐任务是一个非常困难的问题。形式上,该问题可以看作是从人脸表观到人脸形状的复杂非线性映射。
为此,SeetaFace Alignment采用的是我们提出的一种由粗到精的自编码器网络(Coarse-to-Fine Auto-encoder Networks, CFAN [8])来求解这个复杂的非线性映射过程。如图 4所示,CFAN级联了多级栈式自编码器网络,其中的每一级都刻画从人脸表观到人脸形状的部分非线性映射。
具体来说,输入一个人脸区域(由人脸检测模块得到),第一级自编码器网络直接从该人脸的低分辨率版本中快速估计大致的人脸形状S0。然后,提高输入人脸图像的分辨率,并抽取当前人脸形状S0(相应提升分辨率)各特征点位置的局部特征,输入到下一级自编码器网络来进一步优化人脸对齐结果。以此类推,通过级联多个栈式自编码器网络,在越来越高分辨率的人脸图像上逐步优化人脸对齐结果。
图4. 基于由粗到精自编码器网络(CFAN)的实时人脸对齐方法[8]
此次开源的SeetaFace Alignment基于上述CFAN方法实现了5个面部关键特征点(两眼中心,鼻尖和两个嘴角)的精确定位,训练集包括23,000余幅人脸图像(标注了5点)。需要注意的是,为加速之目的,在基本不损失精度的情况下,开源实现中将CFAN级联的数目减少到了2级,从而可在单颗Intel i7-3770 (3.4 GHz CPU)上达到每个人脸5ms的处理速度(不包括人脸检测时间)。
图5给出了一些用SeetaFace Alignment开源引擎定位面部5点的效果示例,可见其对表情、姿态、肤色等均具有较好的鲁棒性。在AFLW数据集上的量化评价和对比情况如图6所示,其中平均定位误差根据两眼中心距离做了归一化。不难看出,SeetaFace Alignment取得了state-of-the-art的定位结果。
图5. SeetaFace Alignment定位结果示例
图6. SeetaFace Alignment在AFLW数据集上的定位误差及对比情况
其中LE:左眼,RE:右眼,N:鼻尖,LM:左嘴角,RM:右嘴角

人脸特征提取与比对模块SeetaFace Identification
人脸识别本质上是要计算两幅图像中人脸的相似程度,其一为注册阶段(类比人的相识过程)输入系统的,另一幅为识别阶段(即再见时的辨认过程)的输入。
为此,如图7所示,一套全自动的人脸识别系统在完成前述的人脸检测与人脸对齐两个步骤之后,即进入第三个核心步骤:人脸特征提取和比对。这个阶段也是深度学习风起云涌之后进步最大的模块,目前大多数优秀的人脸识别算法均采用卷积神经网络(CNN)来学习特征提取器(即图7中的函数F)。

图7.人脸识别系统的核心流程
SeetaFace开源的人脸特征提取模块也是基于卷积神经网络的。具体地说,其实现的是[9]中所描述的深度卷积神经网络VIPLFaceNet:一个包含7个卷积层与2个全连接层的DCNN。其直接修改自Hinton教授的学生Alex Krizhevsky等于2012年设计的AlexNet(即引爆CNN在视觉中广泛应用的网络)。
如表2对比所示,与AlexNet相比,VIPLFaceNet将5x5的卷积核拆分为两层3x3的卷积核,从而增加了网络深度,而并没有增加计算量;VIPLFaceNet还减少了每个卷积层的kernel数目以及FC2层的节点数。同时,通过引入Fast Normalization Layer(FNL),加速了VIPLFaceNet的收敛速度,并在一定程度上提升了模型的泛化能力。
测试表明,在相同训练集情况下,VIPLFaceNet在LFW测试集上识别错误率比AlexNet降低了40%,而训练和测试时间分别为AlexNet的20%和60%。

与开源的SeetaFace Identification代码一起发布的人脸识别模型是使用140万人脸图像训练出来的,这些训练图像来自于约1.6万人,其中既有东方人也有西方人。人脸特征直接采用VIPLFaceNet FC2层的2048个结点的输出,特征比对可简单采用Cosine计算相似度,然后进行阈值比较(验证应用)或排序(识别应用)即可。


该引擎在多数人脸识别场景下均具有良好的性能,例如,在LFW standard Image-Restricted测试协议下,使用SeetaFace Detector与SeetaFace Alignment检测并对齐人脸,采用SeetaFace Identification进行特征提取和比对,可以达到97.1%的识别正确率(请注意:这是系统全自动运行的结果,对少量不能检到人脸的图像,截取中间区域输入人脸对齐模块即可)。速度方面,在单颗Intel i7-3770 CPU上,开源代码提取一张人脸之特征的时间约为120ms(不含人脸检测和特征点定位时间)。


人脸识别引擎SeetaFaceEngine简介及在windows7 vs2013下的编译

 --------作者:fengbingchun

链接:http://blog.csdn.net/fengbingchun/article/details/53164856

SeetaFaceEngine是开源的C++人脸识别引擎,无需第三方库,它是由中科院计算所山世光老师团队研发。它的License是BSD-2.


SeetaFaceEngine库包括三个模块:人脸检测(detection)、面部特征点定位(alignment)、人脸特征提取与比对(identification)。


人脸检测模块:基于一种结合经典级联结构和多层神经网络的人脸检测方法实现,其所采用的漏斗型级联结构(Funnel-Structured Cascade,FuSt)专门针对多姿态人脸检测而设计,其中引入了由粗到精的设计理念,兼顾了速度和精度的平衡。FuSt级联结构在顶部由多个针对不同姿态的快速LAB级联分类器构成,紧接着是若干个基于SURF特征的多层感知机(MLP)级联结构,最后由一个统一的MLP级联结构(同样基于SURF特征)来处理所有姿态的候选窗口,整体上呈现出上宽下窄的漏斗形状。


从上往下,各个层次上的分类器及其所采用的特征逐步变得复杂,从而可以保留人脸窗口并排除越来越难与人脸区分的非人脸候选窗口。


面部特征点定位:采用一种由粗到精的自编码器网络(Coarse-to-Fine Auto-encoder Networks, CFAN )方法实现。CFAN级联了多级栈式自编码器网络,其中的每一级都刻画从人脸表观到人脸形状的部分非线性映射。具体来说,输入一个人脸区域(由人脸检测模块得到),第一级自编码器网络直接从该人脸的低分辨率版本中快速估计大致的人脸形状S0。


然后,提高输入人脸图像的分辨率,并抽取当前人脸形状S0(相应提升分辨率)各特征点位置的局部特征,输入到下一级自编码器网络来进一步优化人脸对齐结果。以此类推,通过级联多个栈式自编码器网络,在越来越高分辨率的人脸图像上逐步优化人脸对齐结果。CFAN方法实现了5个面部关键特征点(两眼中心,鼻尖和两个嘴角)的精确定位。


人脸特征提取与比对:采用深度卷积神经网络VIPLFaceNet实现,一个包含7个卷积层与2个全连接层的DCNN。VIPLFaceNet将5x5的卷积核拆分为两层3x3的卷积核,从而增加了网络深度,而并没有增加计算量;VIPLFaceNet还减少了每个卷积层的kernel数目以及FC2层的节点数。同时,通过引入Fast Normalization Layer(FNL),加速了VIPLFaceNet的收敛速度,并在一定程度上提升了模型的泛化能力。特征比对可简单采用Cosine计算相似度,然后进行阈值比较(验证应用)或排序(识别应用)即可。


这三个模块,每个模块都可以单独生成一个动态库,在源码的每个模块的examples目录下给出了在windows vs2013下的工程,为了便于以后测试和调试,这里将3个工程全部放在了新建的Face_Test工程下,可以在x64 debug/release下直接生成相应的动态库,图如下:



GitHub:https://github.com/fengbingchun/Face_Test

   

 人脸识别引擎SeetaFaceEngine中Alignment模块使用的测试代码 

    --------作者:fengbingchun



人脸识别引擎SeetaFaceEngine中Alignment模块用于检测人脸关键点,包括5个点,两个眼的中心、鼻尖、两个嘴角,以下是测试代码(仅供参考):


[cpp] view plain copy

  1. int test_alignment()  

  2. {  

  3.     std::vector<std::string> images{ "1.jpg", "2.jpg", "3.jpg", "4.jpeg", "5.jpeg", "6.jpg", "7.jpg", "8.jpg", "9.jpg", "10.jpg",  

  4.         "11.jpeg", "12.jpg", "13.jpeg", "14.jpg", "15.jpeg", "16.jpg", "17.jpg", "18.jpg", "19.jpg", "20.jpg" };  

  5.     std::vector<int> count_faces{ 1, 2, 6, 0, 1, 1, 1, 2, 1, 1,  

  6.         1, 1, 1, 1, 1, 1, 1, 0, 8, 2 };  

  7.   

  8.     const std::string path_images{ "E:/GitCode/Face_Test/testdata/" };  

  9.   

  10.     seeta::FaceDetection detector("E:/GitCode/Face_Test/src/SeetaFaceEngine/FaceDetection/model/seeta_fd_frontal_v1.0.bin");  

  11.   

  12.     detector.SetMinFaceSize(20);  

  13.     detector.SetMaxFaceSize(200);  

  14.     detector.SetScoreThresh(2.f);  

  15.     detector.SetImagePyramidScaleFactor(0.8f);  

  16.     detector.SetWindowStep(4, 4);  

  17.   

  18.     seeta::FaceAlignment point_detector("E:/GitCode/Face_Test/src/SeetaFaceEngine/FaceAlignment/model/seeta_fa_v1.1.bin");  

  19.   

  20.     for (auto name : images) {  

  21.         fprintf(stderr, "start detect image: %s\n", name.c_str());  

  22.   

  23.         cv::Mat src_ = cv::imread(path_images + name, 1);  

  24.         if (src_.empty()) {  

  25.             fprintf(stderr, "read image error: %s\n", name.c_str());  

  26.             continue;  

  27.         }  

  28.   

  29.         cv::Mat src;  

  30.         cv::cvtColor(src_, src, CV_BGR2GRAY);  

  31.   

  32.         seeta::ImageData img_data;  

  33.         img_data.data = src.data;  

  34.         img_data.width = src.cols;  

  35.         img_data.height = src.rows;  

  36.         img_data.num_channels = 1;  

  37.   

  38.         std::vector<seeta::FaceInfo> faces = detector.Detect(img_data);  

  39.   

  40.         for (auto face : faces) {  

  41.             // Detect 5 facial landmarks: two eye centers, nose tip and two mouth corners  

  42.             seeta::FacialLandmark points[5];  

  43.             point_detector.PointDetectLandmarks(img_data, face, points);  

  44.   

  45.             cv::rectangle(src_, cv::Rect(face.bbox.x, face.bbox.y,  

  46.                 face.bbox.width, face.bbox.height), cv::Scalar(0, 255, 0), 2);  

  47.   

  48.             for (auto point : points) {  

  49.                 cv::circle(src_, cv::Point(point.x, point.y), 2, cv::Scalar(0, 0, 255), 2);  

  50.             }  

  51.         }  

  52.   

  53.         std::string save_result = path_images + "_" + name;  

  54.         cv::imwrite(save_result, src_);  

  55.     }  

  56.   

  57.     int width = 200;  

  58.     int height = 200;  

  59.     cv::Mat dst(height * 5, width * 4, CV_8UC3);  

  60.     for (int i = 0; i < images.size(); i++) {  

  61.         std::string input_image = path_images + "_" + images[i];  

  62.         cv::Mat src = cv::imread(input_image, 1);  

  63.         if (src.empty()) {  

  64.             fprintf(stderr, "read image error: %s\n", images[i].c_str());  

  65.             return -1;  

  66.         }  

  67.   

  68.         cv::resize(src, src, cv::Size(width, height), 0, 0, 4);  

  69.         int x = (i * width) % (width * 4);  

  70.         int y = (i / 4) * height;  

  71.         cv::Mat part = dst(cv::Rect(x, y, width, height));  

  72.         src.copyTo(part);  

  73.     }  

  74.     std::string output_image = path_images + "result.png";  

  75.     cv::imwrite(output_image, dst);  

  76.   

  77.     return 0;  

  78. }  

从网上找了20张图像,用于测试此模块,测试结果如下:


GitHub:https://github.com/fengbingchun/Face_Test



开源网址

目前,SeetaFace开源人脸识别引擎已全部发布在Github上供国内外同行和工业界使用,项目网址为:https://github.com/seetaface/SeetaFaceEngine(点击阅读原文查看)


关注后可免费获取更多精神内容,恭候您的加入

文章来源:机器视觉

免责声明:本文系网络转载,版权归原作者所有。但因转载众多,无法确认真正原始作者,故仅标明转载来源。本文所用视频、图片、文字如涉及作品版权问题,请第一时间告知,我们将根据您提供的证明材料确认版权并立即删除内容!本文内容为原作者观点,并不代表本公众号赞同其观点和对其真实性负责。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存