1. 概述

人脸识别技术(Automatic Face Recognition),简称AFR,是生物识别技术的一种,通过人的面部特征,进行身份鉴别。

本文档旨在讲解如何快速地集成灵云AFR功能到开发者应用中。关于各服务接口更详细的说明,请参考灵云SDK开发手册。在集成过程中如有疑问,可登录灵云开发者论坛,查找答案或与其他开发者交流。

1.1 概念解释

对指南中涉及的名词作简要描述,使开发者在阅读开发指南时,对此有一些大致的了解和预备知识的了解。

名称 说明
Session Session用来标记一个能力运行过程的上下文。一个应用最多可同时创建的Session数受到授权的限制
云端识别 由云端服务器提供识别结果的方式。使用云端能力需要加上hci_afr_cloud_recog模块
本地识别 通过本地运算来得到识别结果的方式。使用本地能力需要加上hci_afr_local_recog模块和本地资源文件
人脸检测 通过对会话图像进行检测,提取其中的人脸特征。通过hci_afr_detect函数实现
人脸注册 通过对人脸模型进行多次训练,达到提高识别速度和正确率的目的。通过hci_afr_enroll函数实现
人脸确认 使用人脸ID与已注册的用户ID的特征进行匹配性确认。通过hci_afr_verify函数实现
人脸辨识 在一组用户中进行指定人脸ID的用户辨识。通过hci_afr_identify函数实现

1.2 能力定义(capkey)

AFR 支持多种能力,通过 capkey 区分不同能力的调用和配置。其中常用 capkey 如下所示:

capkey 所需本地资源文件
afr.cloud.recog

1.3 识别流程

2. 能力使用说明

2.1 准备工作

在集成 AFR 之前,开发者需要在灵云开发者社区创建相关应用,并保存appkey,developerkey等信息。

2.2 ABI介绍

  • 必选模块

    • libhci_curl.so
    • libhci_sys.so
    • libhci_sys_jni.so
    • libstlport_shared.so
    • libhci_afr.so
    • libhci_afr_jni.so
  • 云端识别

    • libhci_afr_cloud_recog.so

特别注意

Modulebuild.gradle中,必须配置packagingOptions.doNotStrip参数,以保留灵云SDK中的签名信息,该信息在SDK内部使用,用来保护灵云SDK的知识版权。 若此参数未配置,或配置不正确,在进行本地能力调用时,将会返回本地引擎初始化失败的信息。

  • build.gradle示例

      apply plugin: 'com.android.application'
    
      android {
          compileSdkVersion 17
          buildToolsVersion "27.0.3"
    
          defaultConfig {
              applicationId "com.sinovoice.example"
              minSdkVersion 7
              targetSdkVersion 17
              packagingOptions {
                  doNotStrip "*/armeabi/*.so"
                  doNotStrip "*/armeabi-v7a/*.so"
                  doNotStrip "*/arm64-v8a/*.so"
                  // add other if needed
              }
          }
    
          buildTypes {
              release {
                  minifyEnabled false
                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
              }
          }
      }
    
      dependencies {
          compile files('libs/hcicloud-8.1.jar')
          compile files('libs/hcicloud_recorder-8.1.jar')
      }
    

2.3 用户权限

在工程 AndroidManifest.xml 文件中添加如下权限。

<!—通常需要设置一些sd卡路径(例如日志路径)为可写,因此需要能够写外部存储 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<!—以下访问网络的权限均需要打开-->
    <!--连接网络权限,用于执行云端能力 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <!--读取网络信息状态 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--获取当前wifi状态 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!--允许程序改变网络连接状态 -->
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <!--读取手机信息权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

<!—以下访问权限可选-->
    <!--手机定位信息-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

3. 能力集成说明

3.1 通用模块初始化

在调用AFR能力之前,需要初始化灵云SDK的通用模块。详见灵云SDK开发手册

  • Android示例代码

      // 创建初始化参数辅助类
      InitParam initparam = new InitParam();
      // 授权文件所在路径,此项必填
      String authDirPath = context.getFilesDir()  .getAbsolutePath();;
      initparam.addParam  (InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath)    ;
      // 灵云云服务的接口地址,此项必填
      initparam.addParam  (InitParam.AuthParam.PARAM_KEY_CLOUD_URL,     "http://api.hcicloud.com:8888");
      // 开发者密钥,此项必填,由捷通华声提供
      initparam.addParam  (InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY,     "01234567890");
      // 应用程序序号,此项必填,由捷通华声提供
      initparam.addParam  (InitParam.AuthParam.PARAM_KEY_APP_KEY, "1234abcd");
      // 日志的路径,可选,如果不传或者为空则不生成日志
      String logDirPath =     "/storage/emulated/0/sinovoice/com.sinovoice.   example/log";
      initparam.addParam  (InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH,  logDirPath);
      //日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试
      //SDK将输出小于等于logLevel的日志信息
      initparam.addParam  (InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
      // 灵云系统初始化
      // 第二个参数在Android平台下,必须为当前的Context
      int errCode = HciCloudSys.hciInit   (initparam.getStringConfig(), this);
      if(errCode != HciErrorCode.HCI_ERR_NONE) {
          // "系统初始化失败"
          return;
      }
    

3.2 授权检测

在初始化灵云SDK的通用模块后,还需要调用授权检测函数获取云端授权。

  • Android示例代码

      // 获取授权
      private int checkAuthAndUpdateAuth() {
          // 获取系统授权到期时间
          int initResult;
          AuthExpireTime objExpireTime = new AuthExpireTime   ();
          initResult = HciCloudSys.hciGetAuthExpireTime   (objExpireTime);
          if (initResult == HciErrorCode.HCI_ERR_NONE) {
              // 显示授权日期,如用户不需要关注该值,此处代码可忽   略
              Date date = new Date    (objExpireTime.getExpireTime() * 1000);
              SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd",Locale.CHINA);
              Log.i(TAG, "expire time: " + sdf.format(date))  ;
    
              if (objExpireTime.getExpireTime() * 1000 >  System.currentTimeMillis()) {
                  Log.i(TAG, "checkAuth success");
                  return initResult;
              }
          }
    
          // 获取过期时间失败或者已经过期
          initResult = HciCloudSys.hciCheckAuth();
          if (initResult == HciErrorCode.HCI_ERR_NONE) {
              Log.i(TAG, "checkAuth success");
              return initResult;
          } else {
              Log.e(TAG, "checkAuth failed: " + initResult);
              return initResult;
          }
      }
    

3.3 AFR初始化

  • Android示例代码

    
      AfrInitParam initParam = new AfrInitParam();
      // 获取App应用中的lib的路径,放置能力所需资源文件。
      String dataPath = Environment.getExternalStorageDirectory().getAbsolutePath()+ 
                      File.separator + "sinovoice" + 
                      File.separator + this.getPackageName() + 
                      File.separator + "data";
    
      initParam.addParam(AfrInitParam.PARAM_KEY_DATA_PATH, dataPath);
      initParam.addParam(AfrInitParam.PARAM_KEY_INIT_CAP_KEYS, capkey);
      int errCode = HciCloudAfr.hciAfrInit(initParam.getStringConfig());
      if (errCode != HciErrorCode.HCI_ERR_NONE) {
          ShowMessage("HciAfrInit error:"+ HciCloudSys.hciGetErrorInfo(errCode));
          return;
      }else{
          ShowMessage("HciAfrInit Success");
      }
    

3.4 开启会话(session)

AFR 是通过会话(session)来管理识别过程的。在AFR能力初始化成功之后,需要通过开启识别会话来完成识别。

  • Android示例代码

    
      // 开始会话
      AfrConfig sessionConfig = new AfrConfig();
      sessionConfig.addParam(AfrConfig.SessionConfig.PARAM_KEY_CAP_KEY, capkey);
      ShowMessage("hciAfrSessionStart config: " + sessionConfig.getStringConfig());
      Session session = new Session();
      int errCode = HciCloudAfr.hciAfrSessionStart(sessionConfig.getStringConfig(), 
                                                   session);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          ShowMessage("hciAfrSessionStart return " + errCode);
          return false;
      }
      ShowMessage("hciAfrSessionStart Success");
    

3.5 人脸注册

在启动会话(session)成功后,即可可以进行 AFR的人脸注册。

  • Android示例代码

      //设置检测图像
      //buffer中为图像数据
      errCode = HciCloudAfr.hciAfrSetImageBuffer(session, buffer);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          HciCloudAfr.hciAfrSessionStop(session);
          ShowMessage("hciAfrSetImageBuffer error.");
          return false;
      }
      // AFR检测
      String detectConfig = "";
      ArrayList<String> faceIds = new ArrayList<String>();
      AfrDetectResult detectResult = new AfrDetectResult();
      errCode = HciCloudAfr.hciAfrDetect(session, detectConfig, detectResult);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          ShowMessage("face detect error");
          return false;
      }
      for (AfrDetectFace face : detectResult.getFaceList()) {
          faceIds.add(face.getFaceId());
      }
    
      if (faceIds.size() > 0)
      {
          //选择注册的faceid
          enrollConfig.addParam("faceid", faceIds.get(0));
          ShowMessage("faceid = "+faceIds.get(0));
      }
      //AFR注册
      AfrEnrollResult result = new AfrEnrollResult();
      errCode = HciCloudAfr.hciAfrEnroll(session,
              enrollConfig.getStringConfig(), result);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          HciCloudAfr.hciAfrSessionStop(session);
          ShowMessage("hciAfrEnroll return " + errCode);
          return false;
      }
    
      //释放检测结果
      HciCloudAfr.hciAfrFreeDetectResult(detectResult);
    

3.6 人脸确认

  • Android示例代码

    
      ArrayList<String> faceIds = new ArrayList<String>();
      //加载人脸图片
      byte[] buffer = HciCloudHelper.getAssetFileData(filename);
      if (buffer.length == 0) {
          ShowMessage("Open input iamge file" + filename + "error!");
          return false;
      }
      //设置检测图像
      errCode = HciCloudAfr.hciAfrSetImageBuffer(session, buffer);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          HciCloudAfr.hciAfrSessionStop(session);
          ShowMessage("hciAfrSetImageBuffer error.");
          return false;
      }
      //AFR检测
      String detectConfig = "";
      AfrDetectResult detectResult = new AfrDetectResult();
      errCode = HciCloudAfr.hciAfrDetect(session, detectConfig, detectResult);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          ShowMessage("face detect error");
          return false;
      }
      printDetectResult(detectConfig,detectResult);
      for (AfrDetectFace face : detectResult.getFaceList()) {
          faceIds.add(face.getFaceId());
      }
    
      if (faceIds.size() > 0)
      {
          //选择验证的faceid
          verifyConfig.addParam("faceid", faceIds.get(0));
      }
      // 开始确认
      ShowMessage("hciAfrVerify config:" + verifyConfig.getStringConfig());
      errCode = HciCloudAfr.hciAfrVerify(session,
              verifyConfig.getStringConfig(), result);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          ShowMessage("Hciafr hciAfrVerify return " + errCode);
          HciCloudAfr.hciAfrSessionStop(session);
          return false;
      }
      ShowMessage("hciAfrVerify Success");
      if (result.getStatus() == AfrVerifyResult.AFR_VERIFY_STATUS_MATCH) {
          ShowMessage("face data matches with user_id !");
      } else {
          ShowMessage("face data doesn't match with user_id !");
      }
    
      // 释放检测结果。
      HciCloudAfr.hciAfrFreeDetectResult(detectResult);
    

    3.7 人脸辨识

    Android示例代码

    
      ArrayList<String> faceIds = new ArrayList<String>();
    
      //加载人脸图片
      byte[] buffer = HciCloudHelper.getAssetFileData(filename);
      if (buffer.length == 0) {
          ShowMessage("Open input iamge file" + filename + "error!");
          return false;
      }
      //设置检测图像
      errCode = HciCloudAfr.hciAfrSetImageBuffer(session, buffer);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          HciCloudAfr.hciAfrSessionStop(session);
          ShowMessage("hciAfrSetImageBuffer error.");
          return false;
      }
      //AFR检测
      String detectConfig = "";
      AfrDetectResult detectResult = new AfrDetectResult();
      errCode = HciCloudAfr.hciAfrDetect(session, detectConfig, detectResult);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          ShowMessage("face detect error");
          return false;
      }
      printDetectResult(detectConfig,detectResult);
      for (AfrDetectFace face : detectResult.getFaceList()) {
          faceIds.add(face.getFaceId());
      }
    
      if (faceIds.size() > 0)
      {
          //选择识辨的faceid
          identifyConfig.addParam(AfrConfig.SessionConfig.PARAM_KEY_FACE_ID, 
                                  faceIds.get(0));
      }
      //辨识
      errCode = HciCloudAfr.hciAfrIdentify(session,
              identifyConfig.getStringConfig(), result);
      if (HciErrorCode.HCI_ERR_NONE != errCode) {
          ShowMessage("Hciafr hciAfrIdentify return " + errCode);
          HciCloudAfr.hciAfrSessionStop(session);
          return false;
      } else {
          //显示辨识结果
          for (AfrIdentifyResultItem item : result.getIdentifyResultItemList()) {
              String identifyInfo = String.format("identify user(%s,%d) in group(%s)  \n",
                                item.getUserId(),
                                item.getScore(),
                                identifyConfig.getParam(AfrConfig
                                                       .UserConfig.PARAM_KEY_GROUP_ID))   ;
              ShowMessage(identifyInfo);
          }
      }
    
      //释放检测结果。
      HciCloudAfr.hciAfrFreeDetectResult(detectResult);
    

3.7 结束识别

最后我们需要反初始化,依次关闭会话,终止AFR能力,关闭灵云系统。

  • Android示例代码

    
      //关闭AFR识别会话
      errCode = HciCloudAfr.hciAfrSessionStop(session);
      //终止AFR能力
      errCode = HciCloudAfr.hciAfrRelease();
      //终止灵云系统
      errCode = HciCloudSys.hciRelease();
    

4. FAQ

Q: 我运行你们的 SDK 报 19 号错误:START LOG FAILED, 应该如何解决? A: 出现此问题,一般由两种原因造成。

工程文件里引入了中文路径,导致SDK启动时,读写对应的日志路径报错。 日志文件定义的路径由于权限问题不可读写,比如在 Android 平台上运行时,没有 WRITE_EXTERNAL_STORAGE的权限。

Q: 我运行你们的 SDK 报 23 号错误:LOAD_FUNCTION_FROM_DLL FAILED,应该如何解决? A: 这种情况,通常是由于缺库。最常见的场景是使用本地能力的 capkey,如 afr.loacl.recog,没有将库文件对应组入(我们 SDK 示例程序,与 example 同层有全套库文件,示例程序内默认只组入了云端库),将相关库补齐即可使用。此外,由于 AFR能力引用了第三方的 MKL 库,因此如果第三方库没有拷入,也会导致此问题。

Q: 我运行你们的 SDK 报 14 号错误:LOCAL_RES_MISSING,应该如何解决? A: 本地能力常会遇到此问题,此问题是由于没有组入对应的本地资源文件。请在我们开发者社区下载需求的本地资源(VPR本地模型)等,并将资源文件组入代码 datapath 指定路径,然后再次尝试运行程序。

Q: 我运行你们的 SDK 报 11 号错误:SERVICE_RESPONSE_FAILED ,应该如何解决? A: 此问题原因较为复杂,可能是传入的参数问题与服务器不匹配,如调用私有云时,没有传入 property 等配置项。也可能是服务端内部的返回原因,请联系技术支持排查。

Q: 我运行你们的SDK报 7 号错误:CONFIG_UNSUPPORT ,应该如何解决? A: 与 11号错误类似,还是配置串问题,7 号错误原因为传入了不支持的配置串。请仔细检查各接口传入的所有配置串,并联系技术支持排查。

Q: 我运行你们的SDK报 9 号错误: SERVICE_TIMEOUT ,应该如何解决? A: 这个是因为您请求我们服务器到返回结果的时间,超过了上限。请检查网络环境相关的原因,并协助提供日志。

Q: 我运行你们的 SDK 报 16 号错误: SESSION_INVALID ,应该如何解决? A: 这个需要检查详细的代码调用过程,调用每个能力核心接口时,都是需要传入 sessionid 的,如果在 sessionstart 的时候,已经发生了错误,或者使用的id,并不是 sessionstart 时候创建的,就会返回此错误,请联系技术支持排查。

Q: 我运行你们的 SDK 报 0 号错误: ERROR NONE,应该如何解决? A: SDK 报 0 号错误, ERROR NONE,代表执行成功,请您继续后续的集成。

results matching ""

    No results matching ""