Android 实例开发基于ArcSoft实现人脸识别

作者:FranzLiszt1847 时间:2022-01-01 16:34:06 

效果图

Android 实例开发基于ArcSoft实现人脸识别

Android 实例开发基于ArcSoft实现人脸识别

Android 实例开发基于ArcSoft实现人脸识别

Android 实例开发基于ArcSoft实现人脸识别

激活引擎

第一步配置APP_ID和SDK_KEY


int activeCode = FaceEngine.activeOnline( ChooseFunctionActivity.this, Param.APP_ID, Param.SDK_KEY);

public static final String APP_ID = "AwY6okHQHxtM92YRYSEqJQwb8cED5huPvYyMhK1w7BSo";
  public static final String SDK_KEY = "AF8SaLYtP3ALsmaTR55y9UXaykBZjTtMt5gwCBkUGugh";

第二步:判断是否添加动态链接库(so文件与jar包)


private boolean checkSoFile(String[] libraries) {
       File dir = new File(getApplicationInfo().nativeLibraryDir);
       File[] files = dir.listFiles();
       if (files == null || files.length == 0) {
           return false;
       }
       List<String> libraryNameList = new ArrayList<>();
       for (File file : files) {
           libraryNameList.add(file.getName());
       }
       boolean exists = true;
       for (String library : libraries) {
           exists &= libraryNameList.contains(library);
       }
       return exists;
   }

第三步:判断是否申明所有权限


protected boolean CheckPermissions(String[] neededPermissions) {
       if (neededPermissions == null || neededPermissions.length == 0) {
           return true;
       }
       boolean allGranted = true;
       for (String neededPermission : neededPermissions) {
           allGranted &= ContextCompat.checkSelfPermission(this, neededPermission) == PackageManager.PERMISSION_GRANTED;
       }
       return allGranted;
   }

激活引擎代码如下


public void ActivationDevice(final View view) {
       if (!libraryExists) {
           ShowToast(getString(R.string.library_not_found));
           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>() {
           @Override
           public void subscribe(ObservableEmitter<Integer> emitter) {
               RuntimeABI runtimeABI = FaceEngine.getRuntimeABI();
               Log.i(TAG, "subscribe: getRuntimeABI() " + runtimeABI);

long start = System.currentTimeMillis();
               int activeCode = FaceEngine.activeOnline( ChooseFunctionActivity.this, Param.APP_ID, Param.SDK_KEY);
               Log.i(TAG, "subscribe cost: " + (System.currentTimeMillis() - start));
               emitter.onNext(activeCode);
           }
       })
               .subscribeOn( Schedulers.io())
               .observeOn( AndroidSchedulers.mainThread())
               .subscribe(new Observer<Integer>() {
                   @Override
                   public void onSubscribe(Disposable d) {

}

@Override
                   public void onNext(Integer activeCode) {
                       if (activeCode == ErrorInfo.MOK) {
                           ShowToast(getString(R.string.activation_succeeded));
                       } else if (activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED) {
                           ShowToast(getString(R.string.already_activated));
                       } else {
                           ShowToast(getString(R.string.active_failed, activeCode));
                       }

if (view != null) {
                           view.setClickable(true);
                       }
                       ActiveFileInfo activeFileInfo = new ActiveFileInfo();
                       int res = FaceEngine.getActiveFileInfo(ChooseFunctionActivity.this, activeFileInfo);
                       if (res == ErrorInfo.MOK) {
                           Log.i(TAG, activeFileInfo.toString());
                       }

}

@Override
                   public void onError(Throwable e) {
                       ShowToast(e.getMessage());
                       if (view != null) {
                           view.setClickable(true);
                       }
                   }

@Override
                   public void onComplete() {

}
               });

}

人脸比对 1:N

第一步:初始化本地人脸库


FaceServer.getInstance().init(this);

第二步:初始化引擎和相机


public void onGlobalLayout() {
       previewView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
       if (!CheckPermissions(NEEDED_PERMISSIONS)) {
           ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS);
       } else {
           initEngine();
           initCamera();
       }
   }

第三步:初始化引擎


private void initEngine() {
       ftEngine = new FaceEngine();
       ftInitCode = ftEngine.init(this, DetectMode.ASF_DETECT_MODE_VIDEO, ConfigUtil.getFtOrient(this),
               16, MAX_DETECT_NUM, FaceEngine.ASF_FACE_DETECT);

frEngine = new FaceEngine();
       frInitCode = frEngine.init(this, DetectMode.ASF_DETECT_MODE_IMAGE, DetectFaceOrientPriority.ASF_OP_0_ONLY,
               16, MAX_DETECT_NUM, FaceEngine.ASF_FACE_RECOGNITION);

flEngine = new FaceEngine();
       flInitCode = flEngine.init(this, DetectMode.ASF_DETECT_MODE_IMAGE, DetectFaceOrientPriority.ASF_OP_0_ONLY,
               16, MAX_DETECT_NUM, FaceEngine.ASF_LIVENESS);

Log.i(TAG, "initEngine:  init: " + ftInitCode);

if (ftInitCode != ErrorInfo.MOK) {
           String error = getString(R.string.specific_engine_init_failed, "ftEngine", ftInitCode);
           Log.i(TAG, "initEngine: " + error);
           ShowToast(error);
       }
       if (frInitCode != ErrorInfo.MOK) {
           String error = getString(R.string.specific_engine_init_failed, "frEngine", frInitCode);
           Log.i(TAG, "initEngine: " + error);
           ShowToast(error);
       }
       if (flInitCode != ErrorInfo.MOK) {
           String error = getString(R.string.specific_engine_init_failed, "flEngine", flInitCode);
           Log.i(TAG, "initEngine: " + error);
           ShowToast(error);
       }
   }

第四步: * 检测


private void initCamera() {
       DisplayMetrics metrics = new DisplayMetrics();
       getWindowManager().getDefaultDisplay().getMetrics(metrics);

final FaceListener faceListener = new FaceListener() {
           @Override
           public void onFail(Exception e) {
               Log.e(TAG, "onFail: " + e.getMessage());
           }

//请求FR的回调
           @Override
           public 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;

@Override
                                       public void onSubscribe(Disposable d) {
                                           disposable = d;
                                           getFeatureDelayedDisposables.add(disposable);
                                       }

@Override
                                       public void onNext(Long aLong) {
                                           onFaceFeatureInfoGet(faceFeature, requestId, errorCode);
                                       }

@Override
                                       public void onError(Throwable e) {

}

@Override
                                       public 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 = getString(R.string.low_confidence_level);
                       } else {
                           msg = "ExtractCode:" + errorCode;
                       }
                       faceHelper.setName(requestId, getString(R.string.recognize_failed_notice, msg));
                       // 在尝试最大次数后,特征提取仍然失败,则认为识别未通过
                       requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);
                       retryRecognizeDelayed(requestId);
                   } else {
                       requestFeatureStatusMap.put(requestId, RequestFeatureStatus.TO_RETRY);
                   }
               }
           }

@Override
           public 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, getString(R.string.recognize_failed_notice, "NOT_ALIVE"));
                       // 延迟 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 = getString(R.string.low_confidence_level);
                       } else {
                           msg = "ProcessCode:" + errorCode;
                       }
                       faceHelper.setName(requestId, getString(R.string.recognize_failed_notice, msg));
                       retryLivenessDetectDelayed(requestId);
                   } else {
                       livenessMap.put(requestId, LivenessInfo.UNKNOWN);
                   }
               }
           }

};

CameraListener cameraListener = new CameraListener() {
           @Override
           public 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(FaceComparison_RGB.this.getApplicationContext()) : trackedFaceCount)
                           .build();
               }
           }

@Override
           public 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());
                       }
                   }
               }
           }

@Override
           public void onCameraClosed() {
               Log.i(TAG, "onCameraClosed: ");
           }

@Override
           public void onCameraError(Exception e) {
               Log.i(TAG, "onCameraError: " + e.getMessage());
           }

@Override
           public 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>() {
               @Override
               public void subscribe(ObservableEmitter<Boolean> emitter) {

boolean success = FaceServer.getInstance().registerNv21(FaceComparison_RGB.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>() {
                       @Override
                       public void onSubscribe(Disposable d) {

}
                       /**判断是否注册成功*/
                       @Override
                       public void onNext(Boolean success) {
                           //String result = success ? "register success!" : "register failed!";
                           //ShowToast(result);
//                            AlertDialog.Builder builder = new AlertDialog.Builder( FaceComparison_RGB.this );
//                            AlertDialog dialog = builder.create();
//                            View AlertDialog_View = View.inflate( FaceComparison_RGB.this,R.layout.register_result,null );
//                            dialog.setView( AlertDialog_View );
//                            dialog.show();
                           ShowPopWindows(success);
                           registerStatus = REGISTER_STATUS_DONE;
                       }

@Override
                       public void onError(Throwable e) {
                           e.printStackTrace();
                           ShowToast("register failed!");
                           ShowFailPopWindows();
                           registerStatus = REGISTER_STATUS_DONE;
                       }
                       @Override
                       public void onComplete() {

}
                   });
       }
   }

切换前置、后置摄像头


public void switchCamera(View view) {
       if (cameraHelper != null) {
           boolean success = cameraHelper.switchCamera();
           if (!success) {
               ShowToast(getString(R.string.switch_camera_failed));
           } else {
               ShowToast(getString(R.string.notice_change_detect_degree));
           }
       }
   }

尾言

本示例工程基于虹软(ArcSoft)官方Demo改编而成,若有唐突之处,望君海涵

来源:https://blog.csdn.net/News53231323/article/details/120216233

标签:Android,人脸识别,ArcSoft
0
投稿

猜你喜欢

  • Android 自定义view和属性动画实现充电进度条效果

    2023-08-24 00:18:37
  • 深入探讨linux下进程的最大线程数、进程最大数、进程打开的文件数

    2021-07-06 00:49:15
  • 在C#中调用VBScript、javascript等脚本的实现代码

    2022-09-25 13:52:56
  • C# 泛型集合类List<T>使用总结

    2021-08-30 02:04:01
  • Spring Boot实现文件上传下载

    2021-11-22 21:19:36
  • Android控件CardView实现卡片效果

    2023-09-05 17:01:16
  • Java 实现常见的非对称加密算法

    2023-11-27 18:51:03
  • 一文详解C++模板和泛型编程

    2022-12-28 09:40:46
  • FeignClient如何通过配置变量调用配置文件url

    2023-05-07 08:19:25
  • Java农夫过河问题的继承与多态实现详解

    2022-07-12 16:13:22
  • Android利用RecyclerView实现全选、置顶和拖拽功能示例

    2023-06-05 18:21:22
  • C#中OpenCVSharp实现轮廓检测

    2022-04-03 17:38:11
  • WPF+ASP.NET SignalR实现简易在线聊天功能的示例代码

    2023-01-09 09:34:07
  • SpringBoot 集成 Memcached的方法示例

    2021-11-30 18:29:20
  • Android实现画板、写字板功能(附源码下载)

    2021-11-01 17:40:56
  • 在Android中使用WebSocket实现消息通信的方法详解

    2022-06-10 06:26:18
  • 代码详解Java猴子选王问题(约瑟夫环)

    2023-09-16 07:33:43
  • JAVA中实现链式操作(方法链)的简单例子

    2022-12-16 00:54:50
  • Minio与SpringBoot使用okhttp3问题解决

    2021-06-25 19:17:08
  • Java实现学生成绩输出到磁盘文件的方法详解

    2021-11-08 05:24:51
  • asp之家 软件编程 m.aspxhome.com