活体识别
最近项目需要做一个活体识别的功能,要求如下: 1.离线识别,本地识别活体。 2.免费,网上收费的项目不采用。 3.引入的新库足够小。 4.代码必须开源。
资源搜索
带着这么一堆的要求,开始一通搜索。
一、专业公司相关SDK
1.讯飞
在github上搜到的比较高的start的一个项目就是依赖讯飞sdk的。就是FaceRecognition这个库,但是这个库依赖的是一个旧版本的讯飞库,新版的讯飞库已经去掉了相关离线识别的代码。同时该库,识别率较低,同时对设备性能要求极高。
NOTE 关于这个库再补充两点, 1.这个库尝试了很多办法无法下载下来,所以采用了最土的办法,把文件一个个保存下来,同时在网上找到了一个将他的库二次打包静态库的骗子FBYFaceRecognitionDemo_iOS,这里可以将讯飞SDK下来下来,两个库组合到一起,就能跑起来了。 2.之后又找到了一个基于这个库进行二次开发的库FaceRecognition,这个库里面有原库的源码。
新版的讯飞库,讯飞SDK,SDK在集成开发测试阶段服务量限制为最高500次/每日,完成提额申请或商务合作后可以解除
,也就是说,这玩意也是收费的,旧版本收不收费已经无迹可寻。
在讯飞的开放平台上又找到了一个其他的sdk,静默活体检测,但是它是将一段实地拍摄的人脸视频进行云端检测,判断是否为真人活体并给出分值参考
,这个跟我们的要求又是背离的。
所以结果就是讯飞SDK只能放弃。
参考
iOS活体人脸识别的Demo和一些思路 人脸识别 -- 活体检测(张嘴摇头识别)
2.虹软
github上没有找到使用该库的开源库,官网注册了以后,可以在开发者中心中添加SDK,但是它的活体检测只有安卓版本,没有iOS版本,而且安卓的试了一下,只支持识别是不是活的,动作什么的并不能识别。同时因为该库未开源,所以ArcFace v2.0
这个SDK也未去验证是否符合。
3.百度
在百度AI开放平台上找到了一个SDK--iOS-有动作活体版,该SDK满足我们的,离线,免费的要求,但是它需要申请企业认证,需要上传营业执照等申请一个appkey。
so,这个也放弃了。其实这个SDK是目前找到的公司层面的最符合我们要求的一个SDK,建议小公司直接采用该sdk即可,有大厂维护,应该不太会出什么问题。
二、系统原生--AVFoundation--CIDetector
在网上一搜会发现有很多是采用系统原生进行人脸识别的。
下面这些库使用的都是该方法: FaceRecognition LMJFaceRecognition
CIDetector
只能进行静态图片的检测,也就是给一张图片,检测一下嘴巴眼睛什么的。只能检测当时的状态,无法检测动作。
参考
浅谈iOS中的人脸识别及活体检测 [iOS]CIDetector之CIDetectorTypeFace人脸识别 iOS图像处理(四)CIDetector特征识别(人脸识别)
三、网上开源项目 -- dlib
因为星星没有opencv高,所以这个库没有做过多的研究,有兴趣的可以去研究一下。
开源代码: face-landmarking-ios:该库是用swift所写。
四、网上开源项目 -- opencv
网上这方面的开源库最流行的,做的最好的应该就是opencv了。
相关资源
opencv官网 资源下载 开源地址 iOS相关代码--cap_ios_video_camera.mm iOS相关代码--cap_ios_abstract_camera.mm
开源库: OpenFaceIOS EyeBlickCheck:相关介绍 FaceDetectionDemo_iOS:其中用到的libOliveappCombineSDK2.a
貌似是同盾科技的。
识别SDK诞生
下面介绍的这个开源库就是我最终采用的识别库,该库是基于opencv
和HyperLandmark加入了SDM
算法。
其实HyperLandmark
是北京智云视图科技有限公司开源的,这也是目前找到的唯一一个公司进行开源的人脸识别库。为它点赞。
我最终采用的就是HyperLandmark-iOS。简单说一下该库的有点: 1.提供了68点的标记。 2.支持旋转矩阵的展示。
其实基于以上两点,已经满足我们的需求了。
实现思路
我们的需求大概就是,用户进来->打开摄像头进行活体识别->人脸摆正校准->拍照->开始人脸动作识别->进行录像->人脸动作完成->录像结束。
拍照的话就比较简单了,opencv本来提供的就有摄像头帧的回调,拿到照片就比较简单了。所以现在比较难的几个点就是:
- 相关动作的识别。
- 录像。
难点解析
1.相关动作的识别
目前所用的库只给出了68点的数据,并没有给出具体的动作识别,所以只能根据这些点来判断用户所作的动作。 我所参考的坐标点就是人脸姿态估计和人脸识别简介中所提供的图片,两张图其实是一致的。如下图所示:
张嘴闭嘴: 这个其实就是拿了3个点,分别是上嘴唇最下面一点62
,下嘴唇最上面一点66
,下嘴唇最下面一点57
。然后根据62
和66
的距离差与66
与57
的距离差来判断是否张嘴。目前的规则就是如果66
与62
的差大于57
与66
的差则即为张嘴,否则就是闭嘴。
摇头点头 其实这个最开的思路也是打算使用同一状态下点的差值来估算的,但是后来发现了该库做的有旋转矩阵相关数据,于是就打算使用该数据来实现摇头和点头的判断。 大概看了一下它的接口代码,是没有提供旋转矩阵的数据的,所以只能稍微改了下源代码。它绘制旋转矩阵的方法是void ldmarkmodel::drawPose(cv::Mat& img, const cv::Mat& current_shape, float lineL)
,这个方法返回值是void
,将其改成了cv::Vec3d
对象,这样就能在外面拿到绘制的数据。然后再根据绘制的数据去区分是点头还是摇头。
参考
2.录像
其实opencv提供的有录像的相关功能,但是里面有些坑。
最开始的时候我使用的是旧版的opencv库,具体是哪个版本我没有去看过。在根据网上的操作去配置了相关属性之后,后来突然发现,在开始录像之后,内存一直急速网上飚,大概十几秒的时间就飚到了1g的内存,app直接crash。当时就说完了,这还玩个毛线。
后来考虑了两个方案: 1.自己维护一套录制视频的代码,不使用opencv提供的视频录制功能。 2.更新一下opencv库。
第一个方案尝试了一下,发现很难实现,因为一半是opencv的逻辑一半又是自己的逻辑,两边很难将时机恰到好处的结合起来。所以此方案宣告失败。
第二个方案,更新了一下opencv,最新版是4.1的版本,二进制文件居然有300多兆,之前才70多兆,好在最后打包其实没变对少。更新了之后发现之前的内存问题解决了。但是因为新旧版本的兼容问题进行了代码的调整与适配。
里面有几个需要注意的点:
- opencv的录像功能提供的接口比较简单,不适合特别复杂的录像功能。
- 录像过程中一定要维护好
recordVideo
这个变量,维护不好极易导致崩溃,看了一下OpenCV的源码,崩溃的原因是在写入帧率数据的时候的判断不够安全。 - 想要通过压缩帧率来压缩视频的话要自己去重置相关对象。
- 前后台切换的时候一定要丢弃应录制的视频,并且重置摄像头数据,不然也极易导致崩溃。
- 遇到问题的时候一定要去看下opencv的源码,上面有提供源码的地址。