转载请注明作者及出处:https://www.jianshu.com/p/ca3a12bc4911


引言

人脸识别这件事想来早已经不新鲜,在 Android 中的应用也并不广泛,所以网上相关资料乏善可陈。但是在面对特殊的应用场景时,人脸识别的功能还是有一定的用处的,比如在考勤领域。

网上能搜到的很多示例比较多的是基于科大讯飞或者face++实现的,其中有一个示例做的非常漂亮,推荐大家看一看,SwFace。该项目基于讯飞SDK实现的人脸检测,使用face++的webapi实现的人脸注册以及人脸识别。

这些示例都有一个缺点,就是不支持动态识别(可以通过一些巧妙的方法,使用户无法感知这一过程),无论讯飞的SDK还是face++的webapi都是通过拍摄上传一张图片来进行人脸识别,其中讯飞的SDK使用起来很麻烦,官方的接入文档语焉不详,但是用来做人脸检测还是不错的。

这些平台都有一个共同的缺点,就是依赖网络,所有操作都是调用云端接口,需要良好的网络环境才能实现人脸的注册与识别。这对于签到考勤这一场景(需要较快的识别速度、设备可能处于无网络状态)还是很不方便的,另外他们都是收费的。

所以本文将介绍另一个功能完备,性能还算不错的第三方开发工具,虹软中国,而且它是免费的。

鉴于本文实质是我理解人脸识别这一需求的一个思维过程,所谓文章整体会比较墨迹,干货部分我会加黑处理,大家可以选择性阅读。

该项目的地址为:https://github.com/asdfqwrasdf/ArcFaceDemo

我整理并加注释的项目地址为:https://github.com/junerver/ArcFaceDemo (clone 到本地后可以直接 import 后运行)

人脸识别的几个重要的概念

人脸识别,我们可以理解为从一个专门保存人脸特征值的数据集合中找到最匹配的一组特征值。所以在整个流程中应该包含以下几个步骤

  1. 人脸检测 (FD引擎)
    即从摄像头预览中检测到人脸的存在,并且使用一个矩形框出人脸的范围。
  2. 人脸注册
    即将一张图片中的人脸信息,提取出特征值,将该特征值与人员信息建立联系。
  3. 人脸识别 (FR引擎)
    当检测出人脸时,对人脸进行识别,如果人脸特征集合中存在该人脸信息,读取出该人脸信息及人员信息。

人脸注册

人脸注册可以说是整个识别流程的基础,原因不言而喻,来看看官方demo是如何处理的。

PS:demo非常简单,我们不做过于详细的解释,只介绍流程。

所有人脸注册的流程都在 RegsiterActivity 文件中处理的,该页面启动的时候接受 Intent 中传来的 imagePath 信息(图片地址);

第一步:
将拍照获得的图片转为 Bitmap,然后将其转化成 NV21 格式的 Byte 数组,因为我们使用的sdk只能处理 NV21 格式的数据,NV21 格式限制高度不能为奇数

mBitmap = Application.decodeImage(mFilePath);
//创建字节数组 大小由拍照传来的图片尺寸决定
byte[] data = new byte[mBitmap.getWidth() * mBitmap.getHeight() * 3 / 2];
try {//将bitmap转换成nv21,结果保存到data数组中ImageConverter convert = new ImageConverter();convert.initial(mBitmap.getWidth(), mBitmap.getHeight(), ImageConverter.CP_PAF_NV21);//此处高度不能为奇数if (convert.convert(mBitmap, data)) {Log.d(TAG, "convert ok!");}convert.destroy();
} catch (Exception e) {e.printStackTrace();
}

第二步:
获得 NV21 格式的图片信息数据后,我们使用sdk提供的 FD 人脸检测引擎,检测图片中的人脸信息(人脸 Rect、角度),此处的 Rect 是图片中人脸位置的矩形。

//创建FD人脸检测引擎
AFD_FSDKEngine engine = new AFD_FSDKEngine();
AFD_FSDKVersion version = new AFD_FSDKVersion();
List<AFD_FSDKFace> result = new ArrayList<AFD_FSDKFace>(); //人脸探测结果(探测引擎可以识别图片中的全部人联系信息,所以此处是一个List)
//初始化引擎
AFD_FSDKError err = engine.AFD_FSDK_InitialFaceEngine(FaceDB.appid, FaceDB.fd_key, AFD_FSDKEngine.AFD_OPF_0_HIGHER_EXT, 16, 300);
if (err.getCode() != AFD_FSDKError.MOK) {//引擎初始化失败Message reg = Message.obtain();reg.what = MSG_CODE;reg.arg1 = MSG_EVENT_FD_ERROR;reg.arg2 = err.getCode();mUIHandler.sendMessage(reg);
}
err = engine.AFD_FSDK_GetVersion(version);
//FD人脸探测,转化的nv21数据数组,传入图片的宽度、高度、NV21、探测结果
err  = engine.AFD_FSDK_StillImageFaceDetection(data, mBitmap.getWidth(), mBitmap.getHeight(), AFD_FSDKEngine.CP_PAF_NV21, result);

至此我们就获得了一张图片中的全部人脸数据了,他们都被保存在result这个List列表中了。
第三步:
经过上述的两部,我们已经成功的从图片中识别到了人脸,并且将该人脸在图片中的位置获取到了,接下来我们要做的就是使用 FR 人脸识别引擎识别该位置人脸中的特征信息

if (!result.isEmpty()) {//探测结果不为空-存在人脸,初始化FR人脸识别引擎AFR_FSDKVersion version1 = new AFR_FSDKVersion();AFR_FSDKEngine engine1 = new AFR_FSDKEngine();AFR_FSDKFace result1 = new AFR_FSDKFace(); //人脸特征实例AFR_FSDKError error1 = engine1.AFR_FSDK_InitialEngine(FaceDB.appid, FaceDB.fr_key);if (error1.getCode() != AFD_FSDKError.MOK) {//人脸识别引擎初始化失败Message reg = Message.obtain();reg.what = MSG_CODE;reg.arg1 = MSG_EVENT_FR_ERROR;reg.arg2 = error1.getCode();mUIHandler.sendMessage(reg);}error1 = engine1.AFR_FSDK_GetVersion(version1);//提取人脸识别特征 传入值为:传入的图片(NV21转换后)、图片的宽度、高度、格式、人脸检测结果列表中取出的人脸Rect、角度、提取出的人脸特征error1 = engine1.AFR_FSDK_ExtractFRFeature(data, mBitmap.getWidth(), mBitmap.getHeight(), AFR_FSDKEngine.CP_PAF_NV21, new Rect(result.get(0).getRect()), result.get(0).getDegree(), result1);if(error1.getCode() == error1.MOK) {//提取出了特征mAFR_FSDKFace = result1.clone(); //clone提取出的人脸特征int width = result.get(0).getRect().width();int height = result.get(0).getRect().height();Bitmap face_bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);//人脸位置Rect的bitmapCanvas face_canvas = new Canvas(face_bitmap);face_canvas.drawBitmap(mBitmap, result.get(0).getRect(), new Rect(0, 0, width, height), null); //将检测到的人脸位置图片提取到face_bitmap中Message reg = Message.obtain();reg.what = MSG_CODE;reg.arg1 = MSG_EVENT_REG;reg.obj = face_bitmap;mUIHandler.sendMessage(reg);} else {//没有提取出特征Message reg = Message.obtain();reg.what = MSG_CODE;reg.arg1 = MSG_EVENT_NO_FEATURE;mUIHandler.sendMessage(reg);}error1 = engine1.AFR_FSDK_UninitialEngine();//结束人脸识别FR引擎
} else {//人脸检测结果为空,图片中不存在人脸Message reg = Message.obtain();reg.what = MSG_CODE;reg.arg1 = MSG_EVENT_NO_FACE;mUIHandler.sendMessage(reg);
}
err = engine.AFD_FSDK_UninitialFaceEngine(); //结束人脸检测FD引擎

第四步:
到此我们已经获得了整个人脸注册流程中所需要的几个关键值了:

  1. 人脸位置 Rect 及该 Rect 的 Bitmap;
  2. 人脸特征信息实例 mAFR_FSDKFace;

接下来我们来将人脸特征信息与人员信息建立关联,并且将人脸特征信息保存到本地,这个数据将会用于人脸识别获取人员信息的流程。

我们先来看看官方的 Demo 是如何处理的:

if (msg.arg1 == MSG_EVENT_REG) {
    //人脸特征信息识别成功,弹出一个对话框,输入该特征的注册名字(关联的人员信息,此处根据业务需求处理)
//**********省略*********
//****关键代码****添加人脸结果 用名字作为key
((Application)RegisterActivity.this.getApplicationContext())
    .mFaceDB.addFace(mEditText.getText().toString(), mAFR_FSDKFace);
//**********省略*********
} 

获取 Application 中的 mFaceDB 对象,调用其中的 addFace 方法。FaceDb 类是 demo 中官方写的一个人脸特征管理类,其实现是文件方式实现的,当然我们可以采用其他方式来实现暂且按下不表。

//addface
public  void addFace(String name, AFR_FSDKFace face) {try {//检查全部已注册的人脸特征信息boolean add = true;//默认需要注册新增人员for (FaceRegist frface : mRegister) {if (frface.mName.equals(name)) {//存在该人员的信息,直接向其特征list中添加新的特征frface.mFaceList.add(face);add = false;break;}}if (add) { //该人员信息没有注册过FaceRegist frface = new FaceRegist(name); //创建一个人员人脸特征类frface.mFaceList.add(face);//添加一个人脸特征mRegister.add(frface);}//saveInfo()方法会清空原有txt文件,重新向其中添加sdk版本信息if (saveInfo()) {//update all names//把当前全部数据的人员名称重新添加到txt文件FileOutputStream fs = new FileOutputStream(mDBPath + "/face.txt", true);ExtOutputStream bos = new ExtOutputStream(fs);for (FaceRegist frface : mRegister) {bos.writeString(frface.mName);}bos.close();fs.close();//将人脸特征信息写入.data文件中fs = new FileOutputStream(mDBPath + "/" + name + ".data", true);bos = new ExtOutputStream(fs);bos.writeBytes(face.getFeatureData());bos.close();fs.close();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
}

至此人脸注册的整个流程就已经完毕了,其中有很多方法我们不必细究其实现细节,只要先了解其流程即可,毕竟我们第一步是把项目运行起来,并且能参照官方的 Demo 集成到自己项目中去。

在下一篇中,我们再来看看官方 Demo 中人脸识别是如何实现的。

Android 人脸识别了解一下 (上)相关推荐

  1. Android人脸识别技术

    Android人脸识别技术用到的底层库:android/external/neven/,framework 层:frameworks/base/media/java/android/media/Fac ...

  2. Android人脸识别和证件识别

    Android人脸识别和证件识别 程帅 由于疫情原因,最近的大数据和人脸识别检测就进入了大家的视线.对于技术的爱好,我也试着做了一下人脸识别和证件识别. 人脸识别用的是虹软的人脸识别SDK,目前是免费 ...

  3. android人脸识别门禁,安卓人脸识别门禁终端DM-A1

    1.产品介绍: 安卓(Android)人脸识别门禁终端DM-A1是定位为一款功能丰富,扩展性强,稳定性高,简单维护的人脸识别一体机.它集深数科技人脸比对算法及人脸识别活体检测算法,实现5000人脸库下 ...

  4. 基于android系统的人脸检测系统设计 论文,基于Android人脸识别系统设计与实现.doc...

    基于Android人脸识别系统设计与实现 基于Android人脸识别系统设计与实现 摘要:人脸识别是公共安全领域的研究重点.随着移动互联网的快速发展,移动式终端人脸识别应用日益广泛.探讨人脸识别在An ...

  5. 史上最简单的人脸识别项目登上GitHub趋势榜

    来源 | GitHub Trending整理 | Freesia译者 | TommyZihao出品 | AI科技大本营(ID: rgznai100) 导读:近日,一个名为 face_recogniti ...

  6. Android 人脸识别

    Android人脸识别技术,可以参考下面的网站. http://www.faceplusplus.com.cn/ 本项目使用的就是该网站的api. 项目具体使用的技术代码 /*** 用来压缩图片的方法 ...

  7. 神目 Android 人脸识别SDK编译说明

    1.介绍 该文章介绍了神目 AI开放平台Android SDK 基于Android Studio的编译方法 2.Android SDK下载 登录神目AI开放平台下载Android人脸识别SDK打包文件 ...

  8. Android人脸识别(已开源)

    Android人脸识别(已开源) 见链接

  9. android 人脸识别demo

    Android 人脸识别 demo 可以使用 Google 的 Mobile Vision API 来实现.这是一个免费的.开源的库,可以帮助开发人员在应用程序中检测人脸.识别人脸.扫描条形码和二维码 ...

最新文章

  1. 演硬汉才是布鲁斯威利斯的正事 --- 我看《虎胆追凶》
  2. python常用的开发环境包括_Python语言主要包括哪些集成开发环境?_学小易找答案...
  3. C++11 std::function, std::bind, std::ref, std::cref
  4. 互联网域名产业报告(2021年)
  5. linux 下批量压缩文件
  6. C#.NET学习笔记7--11---算术运算符,变量赋值,变量的交换,布尔表达式1,布尔表达式2
  7. 【每日一读】EMNLP2020:如何提高事件检测(ED)模型的鲁棒性和泛化能力?
  8. 服务器压缩文件夹,怎样在文件服务器的NTFS分区(卷)中,压缩文件夹D:\lists?...
  9. PassMark Software - PC Benchmark and Test Software - 软件和硬件基准测试
  10. 电子电路设计的基础知识
  11. ps污点修复画笔用法和案例:去除脸上痘痘
  12. 关于笔记本突然鼠标无法连接,电脑蓝牙消失的问题
  13. 数码计算机英语单词,数码相机的规格词汇中英对照
  14. ORACLE 如何获取uid
  15. idea 提示cannot find declaration to go to 解决方法
  16. mysql_fetch_array() expects parameter_求救!mysql_fetch_array() expects parameter 1 to be resource...
  17. Studio 3T 的Query Builder使用
  18. 基于单片机射频RFID卡公司考勤控制系统设计(毕设课设资料)
  19. Write-Ahead Log(WAL)的工作原理
  20. restapi是什么意思_简单理解什么是REST和RESTful

热门文章

  1. json学习笔记(圣思园视频学习笔记)
  2. 跟艾文学编程《零基础入门学Python》(4)Python 面向对象
  3. 为什么说SQL语句中使用IN性能不高?
  4. 平车调整刀片如何调整_最新电脑带刀平车基本故障与维修方法
  5. Zabbix批量增加节点方法(自动发现及Json API)
  6. 数据结构之数据、数据元素、数据项、数据对象之间的关系
  7. mojave时间机器文件服务器,在 Mac 上可以与时间机器配合使用的磁盘类型
  8. Android Framework:深入探索 AIDL 数据流动
  9. 小白兔—雪花-吕中琪
  10. java开源论坛学习(一)