在开始之前,先解决一个疑问,这个SDK可以识别多个人脸吗。答案当然是可以的。在上一章节中我们实现了识别单个人脸的功能。
你可以下面的地址下载 http://download.csdn.net/download/feishixin/9942684 本教程的相关Demo代码。
如果要识别多个人脸,需要进行下面的设置。
在上一章节中, 我们的方法是只取到识别到的第一个人脸,因此我们只需要一个显示人脸的地方就可以了。要识别多个人脸,首先就是修改视图。
然后,修改程序为循环。
先来看一下我们这节的效果
本节我们主要讲解如何根据识别到的人脸信息提取人脸数据特征,并在此基础上讲解一下如何做人脸识别
在人脸识别领域,首先是检测是否有人脸,人脸的区域是哪里,然后对这个区域进行特征点提取,在提取结束后,告诉计算机,这个人脸是谁。
计算机把这些特征信息和人脸的名称保存下来,就形成了人脸库,在识别人脸时,计算机通过一定的算法,检索库中是否有匹配到的人脸结果,给出相似度数据。当人脸的相似度数据达到一定的数值时,就可以认为同一张人脸。
相似度通常是一个0-1的小数。一般来说,数值越大,表示两个人越相近。
注:不同人脸引擎的人脸相似度不具有可比性,例如,我们从Face ++ 拿到的同一个人的人脸相似度可能会在0.8-0.9,虹软的只能在0.6-0.8之间,这并不能说明Face ++ ,它们只是算法的标准不同,例如,虹软在不同人脸0.1-0.2的时候,Face++达到了0.3-0.5 人脸检测并建立人脸库的过程如下
通过人脸检测或者人脸跟踪,获取到人脸信息并识别人脸的过程如下:
本次教程我们以目录结构作为人脸的存档方式,每张人脸对应一张人脸标识和一个人脸特征。人脸标识和特征使用同一个文件名称来关联,例如人脸a.jpg的特征用a.dat来表示。
好,我们开始我们的课程
我们本次使用到的虹软的SDK包中,提供了人脸识别的库,它的名字叫face_recongnition.dll,我们找到它的SDK文档。 来建立各个结构体和API的C#映射。
从本节开始,我们不再讲解原始SDK文档中的数据结构和C#数组结构如何映射的,也不再讲解P/Invoke的知识,如果需要了解相关知识,请参考我们上篇文档的相关内容。
这个结构体是FD识别的输出结构体,我们在上一章节标记人脸时使用了此结构体。
这个结构体是人脸模型数据,也就是我们说的人脸特征。人脸识别就基于这个结构。
其中pbFeature是人脸数据,虹软当前版本的人脸数据为一个20K大小的二进制数组,在使用时,我们把它保存为byte[]数组。
我们将SDK中的对应方法提取到C#类中,和上面的章节保持一致,我们称之为AFRFunction。
定义人脸库的位置
本次我们使用简单的基于目录存储人脸库
定义人脸识别引擎的变量
在构造函数中我们对人脸识别引擎进行初始化
注意:detectSize为人脸识别的内存大小,一般来说,你可以根据你的应用程序的规模来设置一个适当的数值,数值过小会报内存不足的ERROR。
这里需要注意FR Key,虹软这次开源了1:1和1:N的SDK,不同的SDK,其对应的KEY是不一样的。
我们来提取人脸特征值。打开我们的checkAndMarkFace方法。
人脸特征值是一个二进制的byte数组,其内容对虹软来说是属于技术机密,里面保存了人脸的特征。这里的特征可以在人脸相似度比较时用到,人脸的特征包含了人脸的关键点信息。可惜的是,虹软这方面并没有开源。同样的,人脸的相似度比较算法也没有开源。不过不开源也有不开源的好处,至少我们用起来不用担心这里面的细节。
首先,我们定义一个变量数组,用于保存图片名称的数组。 这里我们简单的对每个识别到的人脸,用GUID命名。
在我们上一节的,输出识别到的人脸数据之前,我们增加一下我们的业务逻辑。找到下面的代码
我们在后面增加定义
在识别到的每个人脸以后,我们把识别到的人脸保存下来
人脸特征值依赖于人脸识别的结果,其原理是利用识别到的人脸区域信息,在原图中对人脸部分进行运算,输出人脸的特征数据。 通过前面的定义,可以知道人脸特征提取函数的需要的参数信息如下 - recognizeEngine:人脸识别引擎 - offInputPtr:输入的图像信息,和FD的信息相同。同为ASVLOFFSCREEN结构体,我们可以直接使用上一步已经定义好的这个变量。 - faceInputPtr:人脸区域信息,包括人脸的角度信息,以及人脸的坐标范围,对应的参数类型为MRECT,也就是在FD中识别到的人脸的区域坐标, - 输出参数为faceModel结构体。包括长度信息和人脸特征数组
我们来一步步解决。
定义faceInput结构体并指定它的引用互操作类型
定义faceModel变量用于保存识别到的特征值信息
调用FR引擎进行特征信息提取
如果ret=0,则提取成功,我们再调用Marshal的方法将对应的信息取出来
保存获取到的结果,为了后面的匹配方便,和图片命名保持一致
现在我们要做的是人脸识别功能呢,我们想要的功能是,打开一张照片,如果里面有人脸,那么我们就识别这个人脸是否已经在我们的人脸库中出现过,如果已经出现 ,就显示人脸的图像编号。
依然打开项目,增加一个按钮。识别人脸,并增加一个pictureBox用于保存匹配到的人脸的对应的人脸信息。双击刚才新加的按钮进入事件处理代码编辑窗口。
为了不增加重新提取特征脸的工作量,我们将上一步获取到的特征脸重用。在上一步中,对识别到的人脸的第一个保存在了pictureBox中,并把相关的特征信息保存在对应命名的dat文件中。在保存时,使用
保存图像特征数据的文件名,因此在这里我们使用
获取图像文件名。
这里我们需要读文件,读取这个特征信息。
C# 读取二进制文件和写二进制文件都相当的方便,你可以使用C#的序列化操作把变量保为dat文件,然后使用反操作把文件重新读取以初始化对象。这里使用的是简单的二进制读取的方法,当然你也可以尝试序列化来完成这个操作。
接下来我们要使用人脸匹配的方法来进行匹配。这里使用的方法是AFR_FSDK_FacePairMatching 方法。再来看一下这个方法的定义
我们先来定义被比较的脸部信息。这里原来的参数名称有点拗口,我们使用localFaceModel来定义本地的
由于使用了文件保存人脸特征信息,因此我们的人脸遍历算法就变得很简单了。我们这里使用1:1的方法。
我们直接使用存储的人脸信息来进行搜索,方法自然是先遍历读取所有特征数据,提取特征值并进行比较
我们来完成TODO的部分 首先我们定义库Model和本地Model的结构体指针 定义库的指针
定义本地Model的指针
调用方法输出匹配结果
从这里可以看出,人脸识别并没有特别高深的地方,其基础理论依然是特征值匹配搜索的理论, 虽然这里面的难点是特征值的提取和匹配算法,但因为虹软已经免费给我们提供了对应的SDK,我们只需要调用相关的接口就可能了。如果要提高人脸匹配的速度,除了可以联系虹软寻找技术支持以外,也可以利用我们在其它算法方面的积累来尝试解决方案。
本次我们学习了人脸特征的提取和人脸特征的保存,实际上,在业务系统中,人脸通常是保存在数据库中的,并且在匹配的时候,为了性能考虑,更多的是把特征保存在内存中,20K的特征值如果在2GB的业务系统中,可以很轻松的保存10W+的特征信息。人脸检测和识别是CPU密集型和内存密集型的应用,保持良好的计算机配置有助于提高识别的性能,离线SDK的良好扩展性也为我们提高系统的性能提供了可行性。
本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕,E-mail:975644476@qq.com
本文链接:http://www.gawce.com/tnews/1395.html