由于个人兴趣和工程实践的要求,最近一直在学习人脸识别的相关知识,并且完成了一套完整的从人脸检测到人脸识别的程序,指导老师认为效果还不错可以应用于实际项目中。自己总结了一下在整个工程里遇到的问题,记为随笔与大家交流。个人水平十分有限,难免有纰漏,望谅解。

  本文只记录一些个人心得,具体的算法和技术不再赘述,如果展开讲绝不是一两篇博文随笔能够说清楚的。

       整个人脸识别流程分为三个部分(1)人脸检测;(2)人脸特征提取;(3)基于欧几里得距离的比较。

       人脸识别和图片分类不同,我们不能像在图片分类工程中一样针对每一个分类提供大量的训练集去训练我们的模型。在人脸识别的网络模型中,我们所需要的结果并不是最后全连接层输出的置信度结果,而是经过CNN网络提取的特征值。这些特征值的维度根据网络模型的选用和输入图片像素的不同而变化。

       由于需求不同,我们对于神经网络的训练方式自然不同。通常可以选择基于三元组损失的训练方式和基于中心损失的训练方式。但是基于三元组损失的训练方式难以定义且难以收敛,所以多选择基于中心损失的训练方法,简单来说中心损失就是为训练集的每一个分类设置一个中心,通过优化提取特征和这个中心之间的距离来达到优化的效果。在这里需要注意:尽管我们是基于中心损失去训练神经网络,但这样的效果并不会很好。所以我们的损失定义应该是中心损失和传统的分类损失的加权结合。

       我们应该在开始人脸识别之前,应该预先处理数据库中的图片。我认为比较好的方法是将提取的特征值(一个数组)记录在(.txt)文档里,在启动服务的时候统一读取进来。

       在从视频流中获取图像的时候有一个要注意的地方,通常可能会选择用opencv来获取图片,但是opencv的图片格式是bgr与我们的训练集rgb图片格式不同。可以通过数组方式交换图层或者选用更简单的VideoCapture来获取图片。

       不同的人提取的特征值自然有所差别,通常的做法是将特征值reshape为一个一维数组,然后对不同的人脸的特征值之间求欧几里得距离,同一个人的照片求得的欧氏距离会更小(建议为了放大不同人脸之间距离的差距,可以省略开方的步骤)。这里我们为距离设置一个阈值(THRESGOLD),当求得的欧氏距离小于这个阈值时认为两张照片出自同一个人。这里阈值的设置没有一个标准,毕竟准确率和识别成功率难以兼得,可以通过自己的测试选定一个合适的值。比如我选用的Res-net模型,求得的特征值长度为2048,当阈值小于17时基本不会出错,但同时也会难识别;如果让人脸很端正地靠近摄像头,测得的欧式距离基本在14以内。

       在实际应用中我们是在一个很大的数据库中比对人脸特征,最简单的做法当然是在一个for循环里将本次取得的特征值和数据库里的特征值逐一求得距离,这也是我一开始没有做好的地方。在这里个人建议:为了充分利用计算资源,首先将图片特征值转换为narray格式,然后扩展为一个与数据库特征值数量对应的矩阵,如[15000,2048]。然后将该矩阵和数据库特征值整体求欧几里得距离。这是因为numpy库是用C语言编写的,它可以绕过Python的GIL而实现真正的多线程运算。经过我的测试,利用矩阵整体运算的方法可以使搜索速度提升2至3倍。这在数据库数据较少时对整体速度的提升很有限,但一旦该当数据库的数据上升到以万为单位时,多线程的矩阵运算对整体识别速度的提升是十分有效的。

 

抛砖引玉,在这里附上我的完整的识别流程:

1.加载神经网络检测模型MTCNN和特征提取模型Res-Net,返回网络的输入和输出节点。

2.启动会话。

3.启动获取数据库的全体特征向量(在数据库中由.txt格式保存)。

4.启动摄像头:

  a) 从视频流里截取一帧图片,转为numpy三维数组格式。

  b) 将图片作为输入,由MTCNN模型计算,计算结果返回boundingbox回归框标定检测结果的四个点。裁剪图片,通过回归点计算目标面积(这里的目标面积可以用于目标距离的相对距离的表示),将裁减后的统一化像素为256x256。

  c) 将检测后的图片作为Res-Net的输入,返回(16x128=2048)的特征值。(Res-Net的返回值是(n*128)的形式,根据输入像素的不同返回不同的n。)

  d) 将2048长度的特征值与数据库加载的用户特征计算欧氏距离,取最小的欧式距离。

(为了充分利用计算资源这里首先将图片特征值转换为narray格式,然后扩展为一个与数据库特征值数量对应的矩阵,如[15000,2048]。然后将该矩阵和数据库特征值整体求欧几里得距离。注:在这里我为了放大差距并没有做开方运算,所以并不是一个标准的欧氏距离。)

  e) 标定一个阈值(或者转换为相似度),当最小的欧氏距离小于阈值时认为确定识别。(经过反复测试,准确率和识别成功率难以兼得。当阈值小于17时基本不会出错,但同时也会难识别;如果以人脸签到的标准让人脸很端正地靠近摄像头,测得的欧式距离基本在14以内;为了保证识别速度,暂时将阈值调高,并通过多次确认的方式提高准确率)

  f) 将识别结果和目标面积加入一个全局字典。在字典中查找,当发现同一个目标在一定时间内连续被识别出三次以上时(多次识别以保证正确率),认为正式识别。同时通过计算目标面积的变化可以判断目标是否有靠近的倾向。