Android基于虹软(ArcSoft)实现从0到1的人脸识别demo

1、在虹软的开发者中心创建一个自己的应用,将APP_ID与SDK_KEY记录下来,后面会用到。创建完后就可以下载SDK了。

2、下载完后,就可以根据SDK包里的开发说明文档和代码进行参考和学习。以下是开发说明文档中的SDK包结构的截图。

3、创建一个空项目,将SDK包里的.jar文件和.so文件复制到该项目的如下包下。接下来的配置十分重要,稍微没处理一个,就是一个头大的bug。

4、“在app里的build.gradle” 第一个红框原本是androidx的,与support是不兼容的,所以要改,因此,整个项目用到androidx的地方都需要改。第二个红框是ndk,加了这个才能找到刚才复制进去的.so文件。第三个红框也要改成如下。下面的dependencies要注意把androidx的改掉。

5、“在整个项目里的build.gradle” 记得加上jcenter()。

6、在gradle.properties里可能会有androidx的东西,也要删掉。

7、在AndroidManifest.xml中的中添加权限申请,在中添加。

manifest:

<uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

provider:

<providerandroid:name="android.support.v4.content.FileProvider"android:authorities="${applicationId}.provider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/provider_paths" /></provider>

在添加后要在res下创建一个xml包,里面添加一个provider_paths.xml文件,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-path name="external_files" path="."/><root-pathname="root_path"path="." />
</paths>

8、从SDK包中引入如下功能包模块和BaseActivity,并将common包下的Constants中的APP_ID,SDK_KEY改成刚才所记录下来的内容。

9、创建3个acvitity,一个是主界面,一个是人脸库的管理界面,一个是人脸识别功能界面。

10、layout包下需要引入以下5个布局文件。

11、主界面主要的功能就是激活权限、连接动态库和激活引擎,我通过修改onCreate()和util包下的ConfigUtil.class的代码,让其能够自动激活和自动修改为全方向人脸检查(其他选择好像不能够实现人脸识别)。以下是激活引擎的代码。

public void activeEngine(final View view) {if (!libraryExists) {Toast.makeText(this, "未找到库文件!", Toast.LENGTH_SHORT).show();return;}if (!checkPermissions(NEEDED_PERMISSIONS)) {ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS);return;}if (view != null) {view.setClickable(false);}Observable.create(new ObservableOnSubscribe<Integer>() {@Overridepublic void subscribe(ObservableEmitter<Integer> emitter) {int activeCode = FaceEngine.activeOnline(MainActivity.this, Constants.APP_ID, Constants.SDK_KEY);emitter.onNext(activeCode);}}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Integer>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Integer activeCode) {if (activeCode == ErrorInfo.MOK) {Toast.makeText(MainActivity.this, "激活成功!", Toast.LENGTH_SHORT).show();} else if (activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED){Toast.makeText(MainActivity.this, "已激活!", Toast.LENGTH_SHORT).show();} else {Toast.makeText(MainActivity.this, "激活失败!", Toast.LENGTH_SHORT).show();}if (view != null) {view.setClickable(true);}ActiveFileInfo activeFileInfo = new ActiveFileInfo();}@Overridepublic void onError(Throwable e) {Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();if (view != null) {view.setClickable(true);}}@Overridepublic void onComplete() {}});}

12、人脸识别界面是最复杂的。其中不仅有人脸识别的功能,还有注册人脸和活体检测的功能。

通过手机自带的摄像头来实现人脸识别和活体检测的逻辑:

private void initCamera() {DisplayMetrics metrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(metrics);final FaceListener faceListener = new FaceListener() {@Overridepublic void onFail(Exception e) {Log.e(TAG, "onFail: " + e.getMessage());}//请求FR的回调@Overridepublic void onFaceFeatureInfoGet(@Nullable final FaceFeature faceFeature, final Integer requestId, final Integer errorCode) {//FR成功if (faceFeature != null) {//                    Log.i(TAG, "onPreview: fr end = " + System.currentTimeMillis() + " trackId = " + requestId);Integer liveness = livenessMap.get(requestId);//不做活体检测的情况,直接搜索if (!livenessDetect) {searchFace(faceFeature, requestId);}//活体检测通过,搜索特征else if (liveness != null && liveness == LivenessInfo.ALIVE) {searchFace(faceFeature, requestId);}//活体检测未出结果,或者非活体,延迟执行该函数else {if (requestFeatureStatusMap.containsKey(requestId)) {Observable.timer(WAIT_LIVENESS_INTERVAL, TimeUnit.MILLISECONDS).subscribe(new Observer<Long>() {Disposable disposable;@Overridepublic void onSubscribe(Disposable d) {disposable = d;getFeatureDelayedDisposables.add(disposable);}@Overridepublic void onNext(Long aLong) {onFaceFeatureInfoGet(faceFeature, requestId, errorCode);}@Overridepublic void onError(Throwable e) {}@Overridepublic void onComplete() {getFeatureDelayedDisposables.remove(disposable);}});}}}//特征提取失败else {if (increaseAndGetValue(extractErrorRetryMap, requestId) > MAX_RETRY_TIME) {extractErrorRetryMap.put(requestId, 0);String msg;// 传入的FaceInfo在指定的图像上无法解析人脸,此处使用的是RGB人脸数据,一般是人脸模糊if (errorCode != null && errorCode == ErrorInfo.MERR_FSDK_FACEFEATURE_LOW_CONFIDENCE_LEVEL) {msg = "人脸置信度低!";} else {msg = "ExtractCode:" + errorCode;}faceHelper.setName(requestId, "未通过!");// 在尝试最大次数后,特征提取仍然失败,则认为识别未通过requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);retryRecognizeDelayed(requestId);} else {requestFeatureStatusMap.put(requestId, RequestFeatureStatus.TO_RETRY);}}}@Overridepublic void onFaceLivenessInfoGet(@Nullable LivenessInfo livenessInfo, final Integer requestId, Integer errorCode) {if (livenessInfo != null) {int liveness = livenessInfo.getLiveness();livenessMap.put(requestId, liveness);// 非活体,重试if (liveness == LivenessInfo.NOT_ALIVE) {faceHelper.setName(requestId, "未通过!非活体!");// 延迟 FAIL_RETRY_INTERVAL 后,将该人脸状态置为UNKNOWN,帧回调处理时会重新进行活体检测retryLivenessDetectDelayed(requestId);}} else {if (increaseAndGetValue(livenessErrorRetryMap, requestId) > MAX_RETRY_TIME) {livenessErrorRetryMap.put(requestId, 0);String msg;// 传入的FaceInfo在指定的图像上无法解析人脸,此处使用的是RGB人脸数据,一般是人脸模糊if (errorCode != null && errorCode == ErrorInfo.MERR_FSDK_FACEFEATURE_LOW_CONFIDENCE_LEVEL) {msg = "人脸置信度低!";} else {msg = "ProcessCode:" + errorCode;}faceHelper.setName(requestId, "未通过!");retryLivenessDetectDelayed(requestId);} else {livenessMap.put(requestId, LivenessInfo.UNKNOWN);}}}};CameraListener cameraListener = new CameraListener() {@Overridepublic void onCameraOpened(Camera camera, int cameraId, int displayOrientation, boolean isMirror) {Camera.Size lastPreviewSize = previewSize;previewSize = camera.getParameters().getPreviewSize();drawHelper = new DrawHelper(previewSize.width, previewSize.height, previewView.getWidth(), previewView.getHeight(), displayOrientation, cameraId, isMirror, false, false);Log.i(TAG, "onCameraOpened: " + drawHelper.toString());// 切换相机的时候可能会导致预览尺寸发生变化if (faceHelper == null ||lastPreviewSize == null ||lastPreviewSize.width != previewSize.width || lastPreviewSize.height != previewSize.height) {Integer trackedFaceCount = null;// 记录切换时的人脸序号if (faceHelper != null) {trackedFaceCount = faceHelper.getTrackedFaceCount();faceHelper.release();}faceHelper = new FaceHelper.Builder().ftEngine(ftEngine).frEngine(frEngine).flEngine(flEngine).frQueueSize(MAX_DETECT_NUM).flQueueSize(MAX_DETECT_NUM).previewSize(previewSize).faceListener(faceListener).trackedFaceCount(trackedFaceCount == null ? ConfigUtil.getTrackedFaceCount(FaceRegisterAndRecognise.this.getApplicationContext()) : trackedFaceCount).build();}}@Overridepublic void onPreview(final byte[] nv21, Camera camera) {if (faceRectView != null) {faceRectView.clearFaceInfo();}List<FacePreviewInfo> facePreviewInfoList = faceHelper.onPreviewFrame(nv21);if (facePreviewInfoList != null && faceRectView != null && drawHelper != null) {drawPreviewInfo(facePreviewInfoList);}registerFace(nv21, facePreviewInfoList);clearLeftFace(facePreviewInfoList);if (facePreviewInfoList != null && facePreviewInfoList.size() > 0 && previewSize != null) {for (int i = 0; i < facePreviewInfoList.size(); i++) {Integer status = requestFeatureStatusMap.get(facePreviewInfoList.get(i).getTrackId());/*** 在活体检测开启,在人脸识别状态不为成功或人脸活体状态不为处理中(ANALYZING)且不为处理完成(ALIVE、NOT_ALIVE)时重新进行活体检测*/if (livenessDetect && (status == null || status != RequestFeatureStatus.SUCCEED)) {Integer liveness = livenessMap.get(facePreviewInfoList.get(i).getTrackId());if (liveness == null|| (liveness != LivenessInfo.ALIVE && liveness != LivenessInfo.NOT_ALIVE && liveness != RequestLivenessStatus.ANALYZING)) {livenessMap.put(facePreviewInfoList.get(i).getTrackId(), RequestLivenessStatus.ANALYZING);faceHelper.requestFaceLiveness(nv21, facePreviewInfoList.get(i).getFaceInfo(), previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, facePreviewInfoList.get(i).getTrackId(), LivenessType.RGB);}}/*** 对于每个人脸,若状态为空或者为失败,则请求特征提取(可根据需要添加其他判断以限制特征提取次数),* 特征提取回传的人脸特征结果在{@link FaceListener#onFaceFeatureInfoGet(FaceFeature, Integer, Integer)}中回传*/if (status == null|| status == RequestFeatureStatus.TO_RETRY) {requestFeatureStatusMap.put(facePreviewInfoList.get(i).getTrackId(), RequestFeatureStatus.SEARCHING);faceHelper.requestFaceFeature(nv21, facePreviewInfoList.get(i).getFaceInfo(), previewSize.width, previewSize.height, FaceEngine.CP_PAF_NV21, facePreviewInfoList.get(i).getTrackId());
//                            Log.i(TAG, "onPreview: fr start = " + System.currentTimeMillis() + " trackId = " + facePreviewInfoList.get(i).getTrackedFaceCount());}}}}@Overridepublic void onCameraClosed() {Log.i(TAG, "onCameraClosed: ");}@Overridepublic void onCameraError(Exception e) {Log.i(TAG, "onCameraError: " + e.getMessage());}@Overridepublic void onCameraConfigurationChanged(int cameraID, int displayOrientation) {if (drawHelper != null) {drawHelper.setCameraDisplayOrientation(displayOrientation);}Log.i(TAG, "onCameraConfigurationChanged: " + cameraID + "  " + displayOrientation);}};cameraHelper = new CameraHelper.Builder().previewViewSize(new Point(previewView.getMeasuredWidth(), previewView.getMeasuredHeight())).rotation(getWindowManager().getDefaultDisplay().getRotation()).specificCameraId(rgbCameraID != null ? rgbCameraID : Camera.CameraInfo.CAMERA_FACING_FRONT).isMirror(false).previewOn(previewView).cameraListener(cameraListener).build();cameraHelper.init();cameraHelper.start();}

注册人脸的逻辑:

private void registerFace(final byte[] nv21, final List<FacePreviewInfo> facePreviewInfoList) {if (registerStatus == REGISTER_STATUS_READY && facePreviewInfoList != null && facePreviewInfoList.size() > 0) {registerStatus = REGISTER_STATUS_PROCESSING;Observable.create(new ObservableOnSubscribe<Boolean>() {@Overridepublic void subscribe(ObservableEmitter<Boolean> emitter) {boolean success = FaceServer.getInstance().registerNv21(FaceRegisterAndRecognise.this, nv21.clone(), previewSize.width, previewSize.height,facePreviewInfoList.get(0).getFaceInfo(), "registered " + faceHelper.getTrackedFaceCount());emitter.onNext(success);}}).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Boolean>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Boolean success) {String result = success ? "register success!" : "register failed!";showToast(result);registerStatus = REGISTER_STATUS_DONE;}@Overridepublic void onError(Throwable e) {e.printStackTrace();showToast("register failed!");registerStatus = REGISTER_STATUS_DONE;}@Overridepublic void onComplete() {}});}}

13、人脸库的管理界面。

public class FaceLibs extends BaseActivity {private ExecutorService executorService;private TextView textView;private TextView tvNotificationRegisterResult;ProgressDialog progressDialog = null;private static final int ACTION_REQUEST_PERMISSIONS = 0x001;private static String[] NEEDED_PERMISSIONS = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_face_libs);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);executorService = Executors.newSingleThreadExecutor();tvNotificationRegisterResult = findViewById(R.id.notification_register_result);progressDialog = new ProgressDialog(this);int faceLibNum = FaceServer.getInstance().getFaceNumber(this);textView = findViewById(R.id.number);textView.setText(faceLibNum + "");FaceServer.getInstance().init(this);}@Overrideprotected void onDestroy() {if (executorService != null && !executorService.isShutdown()) {executorService.shutdownNow();}if (progressDialog != null && progressDialog.isShowing()) {progressDialog.dismiss();}FaceServer.getInstance().unInit();super.onDestroy();}@Overridevoid afterRequestPermission(int requestCode, boolean isAllGranted) {}public void clearFaces(View view) {int faceNum = FaceServer.getInstance().getFaceNumber(this);if (faceNum == 0) {showToast("人脸库已空!");} else {AlertDialog dialog = new AlertDialog.Builder(this).setTitle("通知").setMessage("确定要删除" + faceNum + "个人脸吗?").setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {int deleteCount = FaceServer.getInstance().clearAllFaces(FaceLibs.this);showToast(deleteCount + "个人脸已删除!");textView.setText("0");}}).setNegativeButton("取消", null).create();dialog.show();}}
}

14、以上就是大体的介绍,还有一些小的细枝末节需要同志们动手实操一下。下面就来看看实现的效果。

主界面:

注册成功并通过识别:

通过手机照片识别出不是活体:

清理人脸库:

Android基于虹软(ArcSoft)实现从0到1的人脸识别demo相关推荐

  1. 【Android】虹软、安卓、Uniapp、SpringBoot 实现人脸识别

    [Android]虹软.安卓.Uniapp.SpringBoot 实现人脸识别 简要概述 后台使用的是springboot,本地开发集成的是window是的版本,发布到线上需要改成Linux的版本 如 ...

  2. 基于虹软(ArcSoft)实现人脸识别——Android版

    基于虹软实现人脸识别 效果图 激活引擎 第一步配置APP_ID和SDK_KEY 第二步:判断是否添加动态链接库(so文件与jar包) 第三步:判断是否申明所有权限 人脸比对 1:N 第一步:初始化本地 ...

  3. Android基于虹软SDK实现离线人脸识别

    一.需求 Android端实现离线人脸识别功能,即对比两张人脸是否是同一个人. 二.解决方案 选用虹软人脸识别SDK来实现人脸特征数据比对. 三.步骤 1. 打开虹软开发者中心 开发者中心 2. 新建 ...

  4. 【javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄像头显示等 )(附源码)】

    javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄像头显示等 )(附源码) 文章目录 javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄 ...

  5. PHP虹软人脸识别,虹软人脸识别demo使用教程

    最近在研究虹软家的arcface 人脸识别 demo,现在就给大家分享一下官方的demo 工程如何使用? 1.下载代码: git clone https://github.com/asdfqwrasd ...

  6. Android人脸识别Demo竖屏YUV方向调整和图片保存

    2019独角兽企业重金招聘Python工程师标准>>> 本博客包含三个常用方法,用于盛开Android版人脸识别Demo中竖屏使用时送入yuv数据,但一直无法识别的情况. 1.首先可 ...

  7. android 人脸识别demo

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

  8. android 脸部识别之3D,Android Q新功能曝光了:原生支持3D人脸识别

    原标题:Android Q新功能曝光了:原生支持3D人脸识别 [PConline资讯]如今不少机型已经支持3D人脸识别,像iPhoneX.iPhoneXR.iPhoneXSMax.华为Mate20Pr ...

  9. 基于虹软人证核验 2.0 Android SDK开发集成入门

    一.功能介绍 虹软人证核验 2.0 SDK(以下简称SDK)包含人脸检测.人脸跟踪.人证核验等能力,主要实现人证的1:1比对. 其中暴露对外的功能方法有: active 引擎激活 init 引擎初始化 ...

最新文章

  1. caffe-cuda测试
  2. POJ 3358 Period of an Infinite Binary Expansion ★ (数论好题:欧拉函数)
  3. Cisco 交換機命名規則
  4. smartforms设置纸张打印格式
  5. CodeVS 1081 线段树练习 2
  6. 5186. 区间内查询数字的频率
  7. 大数据之_数据采集Flume_Flume介绍---Flume工作笔记001
  8. python抓取websocket_python--websocket数据解析
  9. Jquery实现定时器实例
  10. scala中命名参数函数_Scala中的命名参数和默认参数值
  11. 【解读】Http协议
  12. Java I/O系统之OutputStream
  13. 【房屋租赁管理模块的设计与实现】
  14. 小精灵无尽的长廊_绝顶高手的养成日常
  15. 开启文案或软文编辑的思考:60后大哥靠一篇软文年入500万案例解析
  16. 静坐常思己过,闲谈莫论人非。
  17. 期货交易中期货公司和柜台的基础知识
  18. QQ宠物客户端2005III新年新版新亮相(转)
  19. Freebsd7 Xorg7.3 KDE3.5 桌面系统安装及美化
  20. SD卡是如何通过“lock”键实现写保护的?SD卡lock键坏掉怎么才能用,插入笔记本老提示写保护?

热门文章

  1. AE插件安装教程——Optical Flares(镜头光晕插件)+Trapcode Suite套件插件
  2. Oracle gsd服务是什么,OracleRAC中的oc4j和gsd资源以及RAC相关的进程
  3. 疫情之下,我和公司都快熬不住了
  4. Office2010页码从第5页开始
  5. PCB电路板元器件布局的一般原则
  6. Go 常量之 iota
  7. Android热修复技术原理分析
  8. beego使用CROS允许跨域请求
  9. 科研|写论文|考研|40款必备软件
  10. fft重叠帧_PD雷达谱分析中的帧重叠ZoomFFT优化设计