机器视觉及图像处理系列之二(C++,VS2015)——图像级的人脸识别(1)

      接上一篇,一切顺利的话,你从github上clone下来的整个工程应该已经成功编译并生成dll和exe文件了;同时,ImageMagic程序亦能够打开并编辑图像了,如此,证明接下来的操练你不会有任何障碍。开篇序文已经说过,工具库缘起人脸识别。我开博后的第一个系列讲了TensorFlow下的人脸识别,写完之后就觉得方向错了,那个系列采用的方案其实更适合物体检测、分类,而不是人脸识别。所以,基于历史原因,我决定这个系列还是从人脸识别开始,让诸君看看改进后的方案到底是怎样的。首先声明,改进后的方案参考了如下一篇博文:

https://blog.csdn.net/mr_curry/article/details/52443126

方案的基本原理及核心算法参照该博文实现,并不是本人原创,要感谢该篇博文的作者只不过有些遗憾的是,该作者并没有在blog上提供完整代码(少了一个函数),且提供的代码亦存在些许错误;同时,对同一张图片的多次预测结果并不一致,存在计算结果溢出的情形。虽如此,但还是要感谢博文作者,核心算法很明了,且有效,再次感谢!我在原文的核心算法基础上,按照我自己的设计原则做了重构和编码,除了算法原理,代码和结构与原文完全不同,请诸君注意

      我自己的学习习惯是——先看效果,然后再决定是否跟进研究此项技术,我想诸君大抵以如此。故,我们先运行一下程序看看效果如何。事先声明,如果你在接下来的操作中出现任何问题,请回头阅读该系列第一篇文章,确定完全达成第一篇的目标后再来这里。前文已经说过,EXE工程“WhoYouAre”即为图像级的人脸识别应用,因此,你应当在工程的输出目录“MachineVisionLib\x64\bin”下看到该应用程序的可执行文件:“WhoYouAre.exe”,如下图:

在该文件夹空白处,按住键盘“Shift”键不要松开,然后鼠标右键菜单选择“在此处打开命令窗口(W)”,如此,我们进入windows控制台:

为了将来能够看到完整的控制台输出信息,建议你鼠标左键点击控制台窗口左上角的图标,在弹出的菜单中打开“属性”窗口,将控制台“布局”设置大一些,最好能够占满整个屏幕,这样你才能看到完整的程序输出信息。设置完毕后,请在控制台输入:

WhoYouAre

控制台会输出该程序的Usage信息:

看着有很多选择,其实就人脸注册和人脸识别两项功能而已。这么多的选择只是为了编码方便,因为视频文件、视频流和图像(照片)在实际处理上均有些许不同,需要单独处理,所以选择看起来就比较多了:

                                    WhoYouAre.exe add 使用照片注册人脸

                               WhoYouAre.exe predict 使用照片进行预测,控制台输出预测结果(人名和概率)

                       WhoYouAre.exe ocvcamera 通过捕获USB/WEB摄像头的实时视频进行人脸识别,参数值为摄像头序号,播放器为OCV自带播放器——ffmpeg

                           WhoYouAre.exe ocvvideo 通过视频流进行预测,参数值为视频地址,可以是本地的视频文件或rtsp地址,播放器依然是OCV自带播放器

    WhoYouAre.exe vlcvideo_rtsp_predict 通过捕获rtsp实时视频进行人脸识别,参数值为rtsp地址,播放器为libvlc播放器

              WhoYouAre.exe vlcvideo_predict 通过本地视频文件进行人脸识别,参数值为本地视频文件名

WhoYouAre.exe vlcvideo_rtsp_catchface 通过rtsp视频流检测人脸并注册到人脸库,参数值为rtsp视频流地址

         WhoYouAre.exe vlcvideo_catchface 通过本地视频文件检测人脸并注册到人脸库,参数值为本地视频文件名

这些选项中,几个视频预测选项在CPU模式下存在卡顿、掉帧的问题,主要是因为人脸检测与识别处理花费了太长的时间;GPU模式下,GTX 1050Ti显卡加速测试,帧率(FPS)高于15帧时视频播放开始呈现太空漫步状态,动作明显变慢,识别性能同样表现不佳。至于时间到底耗费在了哪些处理上,我会在后面的篇幅中详细讲解,让我们先看看图片预测的效果。

      在第一篇clone的工程中,“x64\bin\FACE-PICS”文件夹下是我做测试的图片,除了两个国外的电影明星,其他三人均是牛人,特别是黄老和袁老,更是民族的脊梁,吾辈之楷模。我们第一步要做的工作就是要先将他们注册到我们的系统中。首先,在“x64\bin”文件夹下建立“PERSONS”文件夹,保存人脸特征数据:

然后,控制台输入如下指令:

WhoYouAre add .\FACE-PICS\HuangXuHua.jpg "Huang Xu Hua"

回车执行,我们会看到控制台输出了一大串信息,这些信息包括DNN网络结构以及预训练模型被加载时的调试输出信息。一切顺利的话,我们会在这一大串信息的尾部看到黄老被成功添加到系统中的提示信息:

 

此时,“PERSONS”文件夹下面会出现“Huang Xu Hua.xml”文件,这个文件保存的就是黄老脸部的特征数据:

该文件的主要内容就是2622个脸部特征值,浮点数:

而在“x64\bin”下面则多了一个“FACEDB_STATISTIC.xml”文件,它是系统的统计文件,用于记录系统已注册的人脸数量以及人名长度。它存在的意义就是为了简化算法实现,节省系统资源。关于它的使用方法,我会在讲解算法实现时再说。至此,第一个人脸已注册完毕。当然,只注册一个人脸是远远不够的,要想测试算法的可靠性,接下来我们还需要将其余几人注册到系统中,最终的注册结果如下:

统计文件“FACEDB_STATISTIC.xml”的内容变成了这样:

统计文件的内容很直观,我们总共添加了5个人,人名总长度67个字节。

      人脸注册完毕,接下来该是试试效果了。控制台输入如下指令:

WhoYouAre predict .\FACE-PICS\YuanLongPing-1.jpg

回车执行,我们会看到和注册时类似的输出信息,稍等几秒, 我们同样会在控制台输出信息的尾部看到预测结果:

 

在已经存在5个人的人脸库中,程序还是顺利找到了袁老,相似度为0.869506,基本上相似度超过85%就可以确定是这个人了。上图中还有两个数据需要关注(红色箭头所指处),这两个数据统计的是本次人脸识别花费的时间,其中1009.4ms统计的是总时间,782.14ms统计的是DNN网络提取脸部特征数据花费的时间。从数据上看,时间花费很可观,基本上1秒识别一张。当然,必须告诉你的是,这是CPU模式下的时间统计,那么GPU模式下会怎么样呢?很简单,将程序切换到GPU模式下(关于如何切换到GPU模式,请看上一篇),再执行一次看看效果:

时间明显变小,1秒至少能处理4张了。需要特别提醒的是,这个时间其实还可以再缩小,因为在这里我使用的人脸检测函数是ShiQi.Yu老师的libfacedetection,它在检测人脸时耗时很大,caffe的人脸检测预训练模型要比这小很多,因此视频检测我就使用了caffe预训练模型。如果你有时间,可以把这部分代码调整为预训练模型方式。不过,无论何种方式,CPU与GPU模式在识别性能上的差距均非常明显,特别是在视频识别上,两者差距异常明显。

      为了直观感受视频识别的性能问题,现在需要把自己注册到系统中了。有两种方式注册自己:一种是使用自己的照片,按照上面介绍的步骤注册人脸;第二种是通过摄像头录制一段视频或直接捕获摄像头视频流,然后在控制台输入如下指令:

WhoYouAre vlcvideo_catchface xx.avi

WhoYouAre.exe vlcvideo_rtsp_catchface rtsp://xx.xx.xx/h264/ch1

直接注册人脸。第一种方式不再赘述,关于第二种方式,操作其实很简单。首先,WhoYouAre不支持USB/WEB摄像头的直接注册,仅支持rtsp流的直接注册。如果你手头只有USB/WEB摄像头,那么需要先录制一段包含你的人脸的视频,然后输入第一条指令(xx.avi换成你的视频文件名)即可进行人脸注册。如果你有网络摄像头,则输入第二条指令即可。当然,别忘了将rtsp地址换成你自己的地址。无论你使用哪条指令,WhoYouAre程序都会弹出播放界面,并将检测到的人脸用矩形框框出。你可以根据框出的人脸清晰度来判定是否满足注册要求,如满足,则立即按键盘“回车”键。此时,框出的人脸会被截取到一个单独窗口中显示,继续“回车”则当前这张人脸将被注册到系统中:

其实整个人脸注册操作就是找到人脸后的两个“回车”,之后,我们会在控制台看到相应的输出信息:

提示“Face-0”已被添加到人脸库中。此时我们还需要将这个“Face-0”改为正确的名字,打开“x64\bin\PERSONS”文件夹,找到“Face-0.xml”,将其重新命名为你自己的名字即可,比如“Neo.xml”。然后,再回头修改“x64\bin”目录下的“FACEDB_STATISTIC.xml”文件,将“PERSONNAME_TOTAL_LENGTH”标签下的人名总长度改为修改后的长度。比如原来是74个字节,名字改为“Neo”后,比“Face-0”少了3个字节,那么人名总长度就要减去3个字节,变为71。这样,就完成了视频人脸注册的过程。

      接下来我们就测测视频识别的性能表现如何。先是CPU模式,控制台输入如下指令:

WhoYouAre ocvvideo xx.avi

回车,程序执行后我们注意观察控制台输出,会发DNN网络的特征提取时间比较长,大约在600-700毫秒之间:

也就是说,只要视频帧中检测到人脸,那么这一帧的画面就要在人眼中存留600-700毫秒,然后才能切换到下一帧,这样的延时会带来怎样的播放效果呢:

果然,视频中的美女变成了“树懒”,表情变化过程看得那叫一个真呐!同样,我们使用libvlc播放器(指令:WhoYouAre vlcvideo_predict xx.avi)耗费的时间与OCV自带播放器差不多,也是在600-700毫秒之间。只不过当我们使用rtsp流进行人脸识别时,OCV播放器就表现很差了(指令:WhoYouAre ocvvideo rtsp地址),基本上会出现连续掉帧的情形,同时,控制台输出也惨不忍睹:

此时不仅播放都成问题,别说实时识别人脸了,所以实时视频流识别我们需要采用libvlc播放器(指令:WhoYouAre vlcvideo_predict rtsp地址),本地视频文件识别两种播放器均可。那么,GPU模式下视频识别的效果如何呢?首先将程序切换到GPU模式,然后再次输入“WhoYouAre.exe ocvvideo xx.avi”,程序执行结果如下图所示:

动作依然明显变缓,只不过比CPU模式要好很多,至少不是“树懒”了。那么问题来了,GPU模式都这样的话,时间到底去哪儿了呢?我们来看一下播放上述视频时控制台的输出:

程序在两个地方计时,一个是总的预测时间(Time spent of predict),另一个是DNN网络提取特征的时间(Execution time of caffe net Forward())。每一帧的总预测时间包含了特征提取时间,很明显特征提取时间在其中占比很小,甚至可以忽略不计。但总时间始终维持在在60-80毫秒之间,而我播放的这个视频的帧率为24,也就是每帧间隔40毫秒多一点,超过这个时间就会使得视频呈慢动作状态。显然,我们看到的播放效果与计算结果一致——预测时间太长了,使得正常的视频播放都变慢了。那么这个时间到底花费在了哪里呢?其实,时间花费在了人脸检测、Dlib库68个人脸特征点提取上,至于这两个地方具体花费了多少时间需要我们在源文件的相应位置添加性能监测代码才可。关于这一点,我将在后面讲解人脸识别模块的编码实现时详细描述,本文不再细究。

posted @ 2018-09-17 22:04  Neo-T  阅读(4668)  评论(0编辑  收藏  举报