虹软人脸识别 - Android平台调用动态库时的常见错误解析

最近我们发现很多用户在接入虹软ArcFace人脸识别SDK时,经常会遇到动态库加载失败的相关问题。本文详细介绍从编译动态库(.so)到程序调用so的整个流程,模拟在加载虹软人脸识别so文件时经常遇到的一些问题,帮助大家了解这些问题出现的原因以及解决方法。

一、 ArcFace库加载常见错误
1.1 找不到动态库
java.lang.UnsatisfiedLinkError: couldn't find "libarcsoft_face_engine.so"

原因:

在安装应用时,APK中指定的ABI目录下没有发现指定的动态库,寻找apk中动态库的规则详见

https://developer.android.google.cn/ndk/guides/abis?hl=en#aen

导致这个问题的间接原因很多,比如:

  • Android工程中没有指定的动态库

  • Android工程中动态库存放位置错误

  • 设备支持的最高ABI是armeabi-v7a,而apk只有arm64-v8a的动态库

解决方案:

确保被安装程序中包含的目标设备支持的ABI的动态库,可以解压APK检查动态库是否存在。

1.2 加载的动态库ABI不对
java.lang.UnsatisfiedLinkError: "libarcsoft_face_engine.so" is 32-bit instead of 64-bit

原因:

在64位库目录下存放的动态库文件是32位的。

例如将armeabi-v7a的动态库存放在arm64-v8a目录下,并安装在支持arm64-v8a的设备上,就会导致这样的错误。

解决方案:

确保动态库ABI正确,一般在拷贝文件时拷贝ABI文件夹即可。

1.3 动态库文件长度为0
java.lang.UnsatisfiedLinkError: dlopen failed: file offset for the library ".../libarcsoft_face_engine.so" >= file size: 0 >= 0

原因:

动态库存在,但是文件是空的。

解决方案:

重新将动态库引入工程。

1.4 执行函数时找不到XXXX函数
java.lang.UnsatisfiedLinkError: No implementation found for int b.a.a.b.b(android.content.Context, java.lang.String, java.lang.String) (tried Java_b_a_a_b_b and Java_b_a_a_b_b__Landroid_content_Context_2Ljava_lang_String_2Ljava_lang_String_2)
        at b.a.a.b.b(Native Method)
        at b.a.a.b.a(:182)

原因:

在Java函数确定后,按照固定的规则去寻找native函数找不到。一般情况下都是Java代码混淆导致的。

解决方案:

修改混淆配置文件,确保相关的Java代码不被混淆。

1.5 在加载动态库时出现crash
JNI DETECTED ERROR IN APPLICATION: JNI RegisterNatives called with pending exception java.lang.ClassNotFoundException: Didn't find class "com.arcsoft.face.FaceEngine"

原因:

在动态库中,以指定的Java签名无法找到对应的Java类、函数、变量。

解决方案:

修改混淆配置文件,确保相关的Java代码不被混淆。


以上是常见的crash与基本原因和解决方案的介绍,接下来,我们来自己编译动态库并使用,了解下这些问题是怎么出现的。

二、自己编译并使用动态库
2.1. 编译动态库
2.1.1 CMakeLists.txt

CMakeLists.txt里的内容比较简单,将hello.cpp编译成一个名为libhello-sdk.so的动态库

add_library(
          hello-sdk
          SHARED
          hello.cpp
)
2.1.2 hello.cpp

在这个文件中,使用JNI静态注册和动态注册的方式定义了两个函数,并在JNI_Onload中对需要动态注册的函数进行注册:

  • Java_com_arcsoft_functionregisterdemo_MainActivity_hello

    需要被静态注册的函数,在Java中定义的native函数首次被调用时,会由JVM按照固定的规则去寻找native函数并注册。这个规则一般是:Java_包名_类名_函数名。具体的实现,大家感兴趣的话,可参考这个地址中的JniShortName()JniLongName()http://androidxref.com/9.0.0_r3/xref/art/runtime/art_method.cc

  • dynamicRegisterFunction

    需要被动态注册的函数,一般在JNI_OnLoad中进行注册。

  • JNI_OnLoad

    动态库被加载时,会被执行的函数,在这里对dynamicRegisterFunction进行注册。对于JNI_OnLoad函数被调用的具体实现,大家感兴趣的话,可参考
    http://androidxref.com/9.0.0_r3/xref/art/runtime/java_vm_ext.cc 的第1009至1024行。

  #include <jni.h>
  #include <string>
  
  // 静态注册的函数,对应MainActivity类中的hello函数
  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio中使用人脸识别本地的人脸数据调用网络训练模型进行人脸识别的步骤如下: 1. 在项目的build.gradle文件中添加人脸识别的依赖: ``` implementation 'com.arcsoft:libarcsoft-face:2.1.1' ``` 2. 在代码中使用FaceEngine类的静态方法createHandle()创建人脸识别引擎的句柄: ``` FaceEngine faceEngine = new FaceEngine(); int faceEngineCode = faceEngine.createHandle(context, appId, sdkKey); ``` 其中,context为上下文对象,appId和sdkKey为在官网申请的应用ID和SDKKey。 3. 加载训练好的人脸识别模型文件: ``` faceEngineCode = faceEngine.setFaceRecognizeModelPath("assets/model/recognition"); ``` 4. 初始化人脸识别引擎: ``` faceEngineCode = faceEngine.init(context, DetectMode.ASF_DETECT_MODE_IMAGE, DetectFaceOrientPriority.ASF_OP_0_ONLY, 16, 1, FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_FACE_MODEL); faceEngineCode = faceEngine.setLivenessParam(0.5f, 0.7f); ``` 其中,setLivenessParam()方法用于设置活体检测的参数,0.5f和0.7f分别表示活体检测的阈值和活体检测的动作阈值。 5. 加载人脸数据: ``` List<FaceDB.FaceRegist> faceList = new ArrayList<>(); faceList.addAll(mFaceDB.getRegisterData()); faceEngineCode = faceEngine.registeredFaceList(faceList); ``` 其中,mFaceDB为人脸数据对象,getRegisterData()方法用于获取人脸数据中的注册数据。 6. 调用人脸识别引擎的相关方法进行人脸识别。 需要注意的是,在使用人脸识别本地的人脸数据调用网络训练模型进行人脸识别,需要对人脸数据进行充分的处理和优化,以提高识别的准确率和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值