本文基于VS2015平台,新建MFC项目工程,通过利用MFC建立可视化的人脸检测以及相似度检测程序。
首先放图,最终的结果界面如下图所示。
为了能够实现该效果,进行了如下的工作。认真看完,你会有很大的启发。
(一)首先需要在VS2015中新建MFC以及环境的配置
(二)建立完成MFC后,在工程中配置Dlib库
本文不需要对Dlib库进行编译,通过配置源码的方式进行Dlib库的配置,在我的电脑中,Dlib库的路径为:
(1)右键点击项目->属性
(2)设置包含目录
(3)设置预处理器定义
为了能够对JPG以及PNG图片格式进行支持,需要添加对JPG以及PNG图片格式的支持:
(3)设置库目录
(4)添加源文件
该源文件在下载的dlib源码的dlib\all\source.pp这个路径下的文件,通过添加现有项的方式进行文件的添加:
(5)关闭SDL检查
为了防止由于启动SDL检查编译器会严格检测缓冲区的溢出问题,导致某些文件编译失败,因此需要关闭SDL检查。
(6)取消预编译头
由于导入了第三方的库文件,对于第三方的库文件来说,不一定会包含有预编译的头文件stdaxf.h,此时将会报错,因此为了解决这个问题,将预编译头取消:
(7)添加命令行
如果不添加/bigobj命令行,此时将会出现编译问题,因此需要添加命令行。
(8)在以上都配置完成后,添加文件到资源文件中
添加如下的资源文件,将dlib\external\libjpeg,dlib\external\libpng,dlib\external\zlib下的所有文件全部添加到资源文件中,添加完成后,进行文件的编译。
编译成功。
(二)建立人脸识别项目
该项目包括两个显示原始图片的控件Picture Control,十个按钮,按钮的功能分别为:打开第一张图片,打开第二张图片,利用两dlib库对两张图片进行相似度比对,利用dlib库对人脸关键点进行检测,利用opencv对所有图片进行人脸检测。在对图片进行处理之后,进行实时的检测,实时检测包括利用dlib库对人脸进行检测,利用dlib库对人脸关键点进行检测,利用dlib库对人脸界相似度进行检测,最后利用opencv进行人脸实时检测与dlib库进行对比,最终的界面如下所示:
点击文件选择按钮,可以进行文件的选择,首先选择两张待识别的图像,选择后结果如下所示:
图片选择完成后,点击图像对比按钮,对比图像,在得到图像对比的结果之前,通过dlib库中的算法,首先要将图像中的人脸进行标定,标定完人脸后,进行人脸的特征点标定。结果如下所示:
(1)利用图片进行dlib人脸检测
(2)利用图片进行dlib人脸特征点标定
(3)利用图片进行opencv人脸检测
通过以上的测试,我们可以发现,通过dlib进行检测,检测的正确率很高,对于正脸以及偏转较小的图片进行测试,结果很高,但是对于偏转较大以及颜色与环境较相似的人脸来说,检测效果不是很理想,但是dlib耗时很长;而opencv进行人脸检测,检测的正确率,相比于dlib来说,正确率相对较低,但是检测的时间很短。
接下来进行实时的检测:
(1)利用dlib库,对人脸进行实时的检测。
(2)利用dlib库,对人脸关键点进行实时的检测
(3)利用opencv库,对人脸进行实时的检测
通过进行实时的检测,我们可以发现,利用dlib库,进行实时检测的准确率与opencv检测的准确率大体相同,但是对于检测的时间来说,利用opencv进行实时检测的速度更快,同时能够基本达到动态的检测,而对于dlib库来说,检测的实时性体验相当的差。
(三)遇到的问题:
在利用VS2015,dlib 19.17以及openCV 3.4.1进行开发的过程中,遇到了如下的问题:
(1)如何在子函数中更新显示界面:
为了程序更加的简介与修改方便,将具有相同功能的程序分别放置在不同的文件中,但是如果此时要对界面进行更新操作的话,将会出现问题,此时需要进行如下的操作:
AfxGetApp()->m_pMainWnd->GetDlgItem(你的控件的名字)->SetWindowText(要设置显示的文字);
(2)由于将所有的画图函数单独进行封装,因此为了能够返回集合,需要采用std::vector<数据类型> 来存储要进行处理的信息。如下是在我的程序中返回所有检测到的矩形框的信息。
注意在使用std::vector<>的时候,要利用push_back()的方式将变量进行添加到集合。
(3)在我们使用dlib库的时候,与opencv进行数据交换时,会有数据的转换问题,对于dlib库来说,使用的类型为array2d<dlib::rgb_pixel> img_rgb,通过load_image(img_rgb,"test_image.jpg")的方式来加载图像,但是对于opencv来说,不能够输入dlib::rgb_pixel的类型,对于opencv来说,cv::Mat才是可以读入的图像,通过cv::imread()函数来读取函数,为了将dlib::rgb_pixel类型转为cv::Mat类型,使用dlib::toMat(img_gray)来进行数据类型的转换。使用方法如下所示:
#include<dlib/opencv.h>
#include<opencv2/opencv.hpp>
cv::Mat img = dlib::toMat(image_gray);
这样img就可以利用opencv进行了处理。
将opencv的Mat类型转为dlib类型的数据:
cv::Mat I;
dlib::cv_image<uchar>(I);
(4)由于是进行人脸识别,所以在进行人脸识别的过程中,算法执行效率不是很高,为了能够更好的进行算法的加速,使用openmp进行并行计算。为了可以使用并行计算,需要进行VS2015的配置。但是,对于dubug模式来说,不能够进行配置,只能在release模式下进行配置。
(四)人脸相似度检测
接下来进行比较困难的人脸相似度检测。
对图片进行人脸相似度检测,检测的结果如下所示:
我们可以发现对于同一张图片检测结果为1,接下来利用不同的图片进行结果的检测,如下所示:
通过最后的结果我们可以看到,对于不同的人脸,检测的相似度很低,因此可以采用设定阈值的方式进行判定。
最后我们来进行最后的一个实验,也就是最重要的一个实验,进行实时的检测,在进行实时的检测时,首先需要建立检测图片库,对库的制作分别包括如下的几个步骤:(1)读入原始的图片;(2)对原始的图片进行人脸检测,并且检测到5个特征点;(3)对检测后的图片进行裁剪,将人脸部分裁剪出来,进行存储。之后点击dlib人脸相似度检测,进行实时的人脸检测通过摄像头检测到人脸,之后与库中的人脸进行比对,最后输出人脸检测的结果以及相似度最大的人脸。
图片库的制作:
其中database为存储的原始检测图片,经过第一次处理后,将处理得到的人脸以及标记了人脸关键点的图像存储到databaseFindFaceAndAlignment文件夹中,之后进行第二次处理,将databaseFindFaceAndAlignment中的标记了人脸的图片取出,进行裁剪,将裁剪下来的人脸存储在databaseCrop文件夹中,至此所有的文件处理完毕。
点击dlib人脸相似度检测按钮,进行实时的拍照,将得到的图像存储在originalPicture文件夹中,接下来对图片进行人脸的裁剪,将得到的裁剪后的图片存储到cameraCropPicture文件夹中。本文所做人脸检测,没有进行活体检测。最后得到的处理结果如下所示:
原始拍摄的图片
进行裁剪,裁剪后的结果如下所示:
对人脸进行比对,从库当中找到最终的处理结果,找到最终的结果如下所示:
可以发现对于图片来说,可以很好地找到,预测相似的概率为:
总结:
通过大约一个星期的探索,做出了一个简易的人脸检测系统,该人脸检测系统既可以对图片进行人脸的检测以及特征点的标定和人脸相似度的比对,也可以进行实时的人脸检测,实时的人脸检测,包括了特征点的标定,人脸的标定以及相似度检测,通过实践发下了如下的几个问题,希望可以跟大家进行相应的探讨:
(1)如何能够实现对于光照的鲁棒性,在不同光源下都可以很好地进行检测,想法是对图片进行亮度的提升。
(2)对于不同大小的图片,如何能够提高处理的速度问题,当图片过大,处理速度很慢,不能够达到实时的要求。
(3)通过实验发现了一个问题,原始测试数据与利用手机拍摄的数据大小不一样,当利用手机拍摄的图片进行检测时,不能很好地检测出来,因此有一个疑问,是否图像的像素是影响识别准确率的一个因素。
当然对于人脸检测,有许多的方面可做,对于复杂的环境,同时复杂的环境中有多个人脸如何进行比对以及检测,对于双胞胎能否进行检测,都是我们以后将要做的工作。在进行了传统的检测方法后,在接下来的文章中还要做基于深度学习的人脸检测,与普通的算法进行对比。