多家公司的人证比对算法体验和开发感想

2018-07-13

多家公司的人证比对算法体验和开发感想

最近在开发一个声纹采集一体机系统,这个系统里用到了人证比对功能,即刷身份证后拍照,然后将身份证里面的照片跟拍照比对,验证是否是同一个人。我们不是做人脸识别的公司,所以人脸识别功能当然是接入别人的SDK,这里我们找了好多家的人脸算法,对接过程中也遇到很多问题。经过这次的开发,我了解到这个行业的一些现状。

我们的系统主要运行在Windows电脑上,而且需要无网络也能使用,所以人脸算法必须是用离线版的。人脸算法厂家一般对外提供两种方式:在线版和离线版。一般在线版都可以提供免费试用,离线版需要授权使用。

云端方案

在线版的人脸识别我试用过依图科技的和中科视拓的SDK。在我们的应用声临其境APP上有个声纹购物的场景,需要人脸验证。这两个厂家提供的API都差不多,依图的API安全性考虑更全面,错误码定义的比较详细。还有他们的API共同点是,图片传输都是将图片数据进行base64编码后传输的。至于准确率,感觉都差不多,没有特别明显的差距。

离线方案

离线版的人脸算法用得比对多。因为它是用在我们要卖的机器上,而在线版的我们只是做试验。离线版的集成和使用要比在线版麻烦很多。由于离线版要给出算法库,处于安全和容易被拷贝的原因,都是要先授权的。授权的方式一般有两种:在设备上接入加密狗USB key或者绑定设备机器码的方式。加密狗方式比较方便,我们一般采用这种方式。

我们接入了很多厂家,有阅面科技,中控,杰锐达,商汤,我还把开源的dlib人脸识别也接入了。总体来说,都没有很让人满意的方案,非要挑一个较好的,商汤算是可以,名气这么大也不是白来的。这里要专门说明我们是采用electron技术开发Windows软件,即界面都采用JS来写,一些底层模块采用node插件接入。所以我们专门做了一个人脸算法插件来接入所有的算法。对上层的接口都一样,根据参数来调用不同的算法模块。

这是一种比较新颖的接入方式,我猜那些算法厂家也没想到别人会已这样的方式接入他们的SDK。迄今为止,所有的厂家的算法接入都不太顺利,有些甚至一直有问题导致我们最终放弃。例如有一家的算法没有64位的SDK被我们放弃,因为我们的插件只支持64的。

阅面的算法性能还可以,人脸检测很快,比对也挺快,但是它跟使用了一些硬件的特性,导致在我们的一体机上跑不起来,闪退。我们在自己的电脑上测试一直没有问题,但是一旦装到我们的一体机上就不行。直接让他们的开发人员在我们的一体机上远程调试,也没有发现问题。后来我们发现一体机的CPU是i3的,而我们的普通电脑是i5的,把这个现象反馈给他们,他们才说有可能是这个问题。后来他们给了个新demo,确实可以在一体机上跑了。但是他们给的SDK,我们接入到node插件上,还是跑不起来,他们也解决不了。。。。后来我们就放弃他们了,他们实在浪费了我们太多时间。。。

中控算法接入也不顺利,他们的准确率一般,但是性能较差,人脸检测需要300毫秒,人脸比对则更多,不过他们API还算稳定,我们反馈给他们的问题也解决了,现在主要在用他们的算法。一般厂家提供的SDK demo都是基于c++的,他们把一些dll和bin文件,模型文件都放到跟dll同一目录,在代码里查找dll目录,顺便把模型文件也一起加载了。这种做法在c++工程里没有问题,但是在electron的开发方式会有问题。当electron打包之后,dll会被一起打包压缩,程序运行时再去加载bin文件,已经找不到了。然而他们并没有提供可以设置bin文件路径的地方。。。后来将这个问题反馈给他们,他们才加了个参数设置,可以指定bin文件路径来加载。

杰锐达的算法接入也不顺利,开始没有64位的,后来给了,但是对身份证小照片人脸检测的时候闪退了,反馈给他们解决。后来人脸比对得分异常,几乎不可用,又反馈给他们,修正后才可用。然后在一体机上又跑不起来,原来是缺少了python.dll。杰瑞达的人脸算法性能跟中控差不多。

我自己找了个开源的人脸检测和比对的算法:dlib,也把它接入了进来。dlib是一个开源的深度学习库,采用c++语言写的,依赖少,跨平台。然后有人采用它进行了人脸检测和比对的训练(人脸照片库是LFW),产出一个模型放到网上。它号称对这库的识别有99.13%的准确率。这个库有Python版本的,很容易安装使用。但是c++版本的,demo不是很详细,接入的话还是需要自己写不少代码。我查了很多资料,结合OpenCV,才在node插件里使用起来。不过我发现,现实的准确没有那么没有,我测试的准确率不是很高。网上它自称准确率那么高是因为它阈值比较低,是0.6.这个阈值的话或导致很高的误识别率。要至少调到0.48,误识别率才会降低,但是这样的识别效果就差了,跟中控的算法差不多。它的人脸检测时间耗时也挺多。

商汤是算法接入情况也差不多。但是它的API设计得比较简单和直接。它同样没有提供设置模型库文件的加载路径。这样是没办法在electron用起来的。性能和准确率比别的家要好一些。

所有对接这些商家的SDK中,他们的Demo发过来,基本上都是不能直接跑的。。。他们就不能搞完善一些吗?还有他们都是直接或者间接都用到了OpenCV这个库。OpenCV图像处理领域真是运用广泛,发挥了很大作用。我也是因为这次开发才了解到了一些OpenCV的知识。还有几乎所有的厂家的图片数据都是转为bgr格式的数据来使用。还有他们比对出来的分数的标准都不太一样,没有可比性。

优化过程

由于是采用electron来开发,跟传统的c++开发有很多不同,开始人脸识别性能很差,经过一个艰难的优化过程后,才有了基本可接受的效果。至于为什么用electron开发,当然是为了节省开发成本了,并且我们并没有专门开发Windows软件的开发人员。JS开发真的像想要一统天下的节奏。

一开始人脸识别node插件并不是我开发的。他们采用的做法是JS中每次传身份证照片和拍照的照片去比对,返回结果。前端是定时通过摄像头拍照,将拍的照片转为bmp格式的照片,连同身份证照片(也是bmp格式)一起传入node插件来比对。这个比对接口要耗费7,8百毫秒的时间。

这里明显有个可以优化的地方,因为身份证照片是不变的,不必每次都去生成人脸特征,只需生成一次即可,后台就只需处理拍照的照片就行。这样图片处理时间就可以减少接近一半的时间了。

另外采用electron开发不好的一个地方就是,你不好直接处理视频流。视频流要传给video标签来显示预览图,然后它却没有提供从视频流里截取一帧数据接口。我们JS开发的同事的做法是在在界面上放置一个canvas,然后把video放到这个画布上,然后画一帧图像出来,然后把这帧图像拿出来。这数据是RGBA格式的数据,他将这个数据转为bmp格式的数据后,再传给node插件。这一步转换很耗时,要花费300多毫秒。实际上这一步转换是没有必要的,直接把RGBA的数据传给node插件,由node插件来转成人脸算法需要的数据格式。在c++中,可以OpenCV的方法来转换,很方便快捷。这里说一个我犯过的错误。Mat里的rows对应的是图片的高,cols对应的是图片的宽,别搞错了,我就是因为弄反了调试了一晚上。。。做了这个优化之后,人脸识别就比之前快很多了,有了质的区别。不多话说回来,它的性能还是比纯c++写的要差。。。所以鱼和熊掌不可兼得。。。

通过这次开发体验,感觉国内的人脸算法,还是没有到很靠谱的地步。


如果你觉得这篇文章有用,请打赏小钱喝杯咖啡^_^ 打赏

Category: 技术 Tagged: 人脸检测 人证比对 dlib electron

Comments