视觉任务AndroidSDK集成文档
简介
1.1 Android SDK 硬件要求
Android 版本:支持 Android 5.0(API 21) 及以上
硬件:支持 arm64-v8a 和 armeabi-v7a,暂不支持模拟器
通常您下载的SDK只支持固定的某一类芯片。
- 通用ARM: 支持大部分ARM 架构的手机、平板及开发板。通常选择这个引擎进行推理。
- 通用ARM GPU:支持骁龙、麒麟、联发科等带GPU的手机、平板及开发板。
-
高端芯片AI加速模块:
- 高通骁龙引擎SNPE: 高通骁龙高端SOC,利用自带的DSP加速。其中 660 之后的型号可能含有 Hexagon DSP模块,具体列表见snpe 高通骁龙引擎官网。
- 华为NPU引擎DDK:华为麒麟980的arm-v8a的soc。 具体手机机型为mate10,mate10pro,P20,mate20,荣耀v20等。
- 华为达芬奇NPU引擎DAVINCI: 华为NPU的后续版本,华为麒麟810,820,990的arm-v8a的soc。具体手机机型为华为mate30,p40,nova6,荣耀v30等。
通用ARM有额外的加速版,但是有一定的精度损失。 因GPU硬件限制,通用ARM GPU物体检测模型输入尺寸较大时会运行失败,可以在训练的时候将输入尺寸设为300*300。 高端芯片AI加速模块, 一般情况下推理速度较快。 运行内存不能过小,一般大于demo的assets目录大小的3倍。
1.2 功能支持
引擎 | 图像分类 | 物体检测 | 图像分割 | 文字识别 只支持EasyEdge |
姿态估计 |
---|---|---|---|---|---|
通用ARM | √ | √ | √ | √ | √ |
通用ARM GPU | √ | √ | |||
高通骁龙引擎SNPE | √ | √ | |||
华为NPU引擎DDK | √ | √ | |||
华为达芬奇NPU引擎DAVINCI | √ | √ |
1.3 Release Notes
时间 | 版本 | 说明 |
---|---|---|
2022.09.15 | 0.10.6 | SNPE引擎升级;迭代优化 |
2022.07.28 | 0.10.5 | 迭代优化 |
2022.06.30 | 0.10.4 | 支持Android11;支持EasyEdge语义分割模型;迭代优化 |
2022.05.18 | 0.10.3 | ARM / ARM-GPU 引擎升级;支持更多加速版模型发布;迭代优化 |
2022.03.25 | 0.10.2 | ARM / ARM-GPU 引擎升级;支持更多检测模型;迭代优化 |
2021.12.22 | 0.10.1 | DDK不再支持Kirin 970;迭代优化 |
2021.10.20 | 0.10.0 | 更新鉴权;更新达芬奇NPU、SNPE、通用ARM及ARM-GPU引擎;新增达芬奇NPU对检测模型的支持;支持更多姿态估计模型 |
2021.07.29 | 0.9.17 | 迭代优化 |
2021.06.29 | 0.9.16 | 迭代优化 |
2021.05.13 | 0.9.15 | 更新鉴权,更新通用arm及通用arm gpu引擎 |
2021.04.02 | 0.9.14 | 修正bug |
2021.03.09 | 0.9.13 | 更新android arm的预处理加速 |
2020.12.18 | 0.9.12 | 通用ARM引擎升级;新增ARM GPU引擎 |
2020.10.29 | 0.9.10 | 迭代优化 |
2020.9.01 | 0.9.9 | 迭代优化 |
2020.8.11 | 0.9.8 | 更新ddk 达芬奇引擎 |
2020.7.14 | 0.9.7 | 支持arm版ocr模型,模型加载优化 |
2020.6.23 | 0.9.6 | 支持arm版fasterrcnn模型 |
2020.5.14 | 0.9.5 | 新增华为新的达芬奇架构npu的部分图像分类模型 |
2020.4.17 | 0.9.4 | 新增arm通用引擎量化模型支持 |
2020.1.17 | 0.9.3 | 新增arm通用引擎图像分割模型支持 |
2019.12.26 | 0.9.2 | 新增华为kirin麒麟芯片的物体检测支持 |
2019.12.04 | 0.9.1 | 使用paddleLite作为arm预测引擎 |
2019.08.30 | 0.9.0 | 支持EasyDL专业版 |
2019.08.30 | 0.8.2 | 支持华为麒麟980的物体检测模型 |
2019.08.29 | 0.8.1 | 修复相机在开发版调用奔溃的问题 |
2019.06.20 | 0.8.0 | 高通手机引擎优化 |
2019.05.24 | 0.7.0 | 升级引擎 |
2019.05.14 | 0.6.0 | 优化demo程序 |
2019.04.12 | 0.5.0 | 新增华为麒麟980支持 |
2019.03.29 | 0.4.0 | 引擎优化,支持sd卡模型读取 |
2019.02.28 | 0.3.0 | 引擎优化,性能与效果提升; |
2018.11.30 | 0.2.0 | 第一版! |
快速开始
2.1 安装软件及硬件准备
扫描模型下载SDK处的网页上的二维码,无需任何依赖,直接体验
如果需要源码方式测试:
打开AndroidStudio, 点击 "Import Project..."。在一台较新的手机上测试。
详细步骤如下:
- 准备一台较新的手机,如果不是通用arm版本,请参见本文的“硬件要求”,确认是否符合SDK的要求
- 安装较新版本的AndroidStudio ,下载地址
- 新建一个HelloWorld项目, Android Studio会自动下载依赖, 在这台较新的手机上测试通过这个helloworld项目。注意不支持模拟器。
- 解压下载的SDK。
- 打开AndroidStudio, 点击 "Import Project..."。 即:File->New-> "Import Project...", 选择解压后的目录。
- 此时点击运行按钮(同第3步),手机上会有新app安装完毕,运行效果和二维码扫描的一样。
- 手机上UI界面显示后,如果点击UI界面上的“开始使用”按钮,可能会报序列号错误。请参见下文修改
2.2 使用序列号激活
如果使用的是EasyEdge的开源模型,无需序列号,可以跳过本段直接测试。
建议申请包名为"com.baidu.ai.easyaimobile.demo"的序列号用于测试。
本文假设已经获取到序列号,并且这个序列号已经绑定包名。
2.2.1 填写序列号
打开Android Studio的项目,修改MainActivity类的开头SERIAL_NUM字段。 MainActivity 位于app\src\main\java\com\baidu\ai\edge\demo\MainActivity.java文件内。
// 请替换为您的序列号
private static final String SERIAL_NUM = "XXXX-XXXX-XXXX-XXXX"; //这里填您的序列号
2.2.2 修改包名
如果申请的包名为"com.baidu.ai.easyaimobile.demo",这个是demo的包名,可以不用修改
打开app/build.gradle文件,修改"com.baidu.ai.easyaimobile.demo"为申请的包名
defaultConfig {
applicationId "com.baidu.ai.easyaimobile.demo" // 修改为比如“com.xxx.xxx"
}
修改序列号和包名后,可以运行测试,效果同扫描二维码的一致
2.2.3 测试精简版
对于通用ARM、高通骁龙引擎SNPE、华为NPU引擎DDK和达芬奇NPU引擎Davinci的常见功能,项目内自带精简版,可以忽略开发板不兼容的摄像头。 此外,由于实时摄像开启,会导致接口的耗时变大,此时也可以使用精简版测试。
目前以下硬件环境有精简版测试:
- 通用ARM:图像分类(Classify),物体检测(Detection),文字识别(OCR),图像分割(Segmentation),姿态估计(Pose)
- 高通骁龙引擎SNPE:图像分类(Classify),物体检测(Detection)
- 华为NPU引擎DDK:图像分类(Classify),物体检测(Detection)
- 华为达芬奇NPU引擎Davinci:图像分类(Classify),物体检测(Detection)
具体代码分别在infertest、snpetest、ddktest和davincitest目录下。 修改方法为(以通用ARM为例):更改app/main/AndroidManifest.xml中的启动Activity。
<activity android:name=".infertest.MainActivity"> <!-- 原始的是".MainActivity" -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
开启后会自动选择图像分类(Classify),物体检测(Detection),文字识别(OCR),图像分割(Segmentation)或姿态估计(Pose)测试。
Demo APP 检测模型运行示例 | 精简版检测模型运行示例 |
---|---|
使用说明
3.1 代码目录结构
集成时需要“复制到自己的项目里”的目录或者文件:
- app/libs
- app/src/main/assets/xxxx-xxxxx 如app/src/main/assets/infer
+app 简单的设置,模拟用户的项目
|---+libs 实际使用时需要复制到自己的项目里
|----arm64-v8a v8a的so
|----armeabi-v7a v7a的so
|----easyedge-sdk.jar jar库文件
|---+src/main
|---+assets
|----demo demo项目的配置,实际集成不需要
|----infer 也可能是其它命名,infer表示通用arm。实际使用时可以复制到自己的项目里
|---+java/com.baidu.ai.edge/demo
|---+infertest 通用Arm精简版测试,里面有SDK的集成逻辑
|--- MainActivity 通用Arm精简版启动Activity,会根据assets目录判断当前的模型类型,并运行同目录的一个Task。使用时需要修改里面的序列号
|--- TestInferClassifyTask 通用Arm精简版分类
|--- TestInferDetectionTask 通用Arm精简版检测
|--- TestInferOcrTask 通用Arm精简版OCR
|--- TestInferPoseTask 通用Arm精简版姿态
|--- TestInferSegmentTask 通用Arm精简版分割
|---+snpetest SNPE精简版测试
|--- MainActivity SNPE精简版启动Activity,会根据assets目录判断当前的模型类型,并运行同目录的一个Task。使用时需要修改里面的序列号
|--- TestSnpeClassifyTask SNPE精简版分类
|--- TestSnpeDetectionTask SNPE精简版检测
|---+ddktest DDK精简版测试
|--- MainActivity DDK精简版启动Activity,会根据assets目录判断当前的模型类型,并运行同目录的一个Task。使用时需要修改里面的序列号
|--- TestDDKClassifyTask DDK精简版分类
|--- TestDDKDetectionTask DDK精简版检测
|---+davincitest Davinci精简版测试
|--- MainActivity Davinci精简版启动Activity,会根据assets目录判断当前的模型类型,并运行同目录的一个Task。使用时需要修改里面的序列号
|--- TestDavinciClassifyTask Davinci精简版分类
|--- TestDavinciDetectionTask Davinci精简版检测
|----CameraActivity 摄像头扫描示例,里面有SDK的集成逻辑
|----MainActivity 启动Activity,使用时需要修改里面的序列号
|---- build.gradle 这里修改包名
+camera_ui UI模块,集成时可以忽略
3.2 调用流程
以通用ARM的检测模型功能为例, 代码可以参考TestInferDetectionTask
- 准备配置类,如InferConfig,输入:通常为一个assets目录下的文件夹,如infer。
- 初始化Manager,比如InferManager。输入:第1步的配置类和序列号
- 推理图片,可以多次调用 3.1 准备图片,作为Bitmap输入 3.2 调用对应的推理方法,比如detect 3.3 解析结果,结果通常是一个List,调用结果类的Get方法,通常能获取想要的结果
- 直到长时间不再使用我们的SDK,调用Manger的destroy方法释放资源。
3.3 具体接口说明
下文的示例部分以通用ARM的检测模型功能为例 即接口为InferConfig, InferManager,InferManager.detect。 其它引擎和模型调用方法类似。
下文假设已有序列号及对应的包名
3.3.1 . 准备配置类
- INFER:通用ARM,
InferConfig
- ARM GPU:
ArmGpuConfig
- SNPE:高通骁龙DSP,
SnpeConfig
- SNPE GPU:高通骁龙GPU,
SnpeGpuConfig
- DDK:华为NPU,
DDKConfig
- DDKDAVINCI:华为达芬奇NPU,
DDKDaVinciConfig
InferConfig mInferConfig = new InferConfig(getAssets(),
"infer");
// assets 目录下的infer,infer表示通用arm
输入:assets下的配置
输出:具体的配置类
3.3.2. 初始化Manager类
- INFER:通用ARM,
InferManager
- ARM GPU:通用ARM GPU,
InferManager
- SNPE:高通骁龙DSP,
SnpeManager
- SNPE GPU:高通骁龙GPU,
SnpeManager
- DDK:华为NPU,
DDKManager
- DDKDAVINCI:华为达芬奇NPU,
DavinciManager
String SERIAL_NUM = "XXXX-XXXX-XXXX-XXXX";
// InferManager 为例:
new InferManager(this, config, SERIAL_NUM)); // config为上一步的InferConfig
注意要点
- 同一个时刻只能有唯一有效的InferManager。旧的InferManager必须调用destory后,才能新建一个new InferManager() 。
- InferManager的任何方法,都不能在UI线程中调用。
- new InferManager() 及InferManager成员方法由于线程同步数据可见性问题,都必须在一个线程中执行。如使用android自带的ThreadHandler类。
输入: 1.配置类 ; 2.序列号
输出: Manager类
3.3.3. 推理图片
- 接口可以多次调用,但是必须在一个线程里,不能并发
- confidence, 置信度[0-1],小于confidence的结果不返回。 填confidence=0,返回所有结果
- confidence可以不填,默认用模型推荐的。
准备图片, 作为Bitmap输入,
- 输入为Bitmap,其中Bitmap的options为默认。如果强制指定的话,必须使用Bitmap.Config.ARGB_8888
调用对应的推理方法及结果解析
见下文的各个模型方法
3.3.4 分类Classify
public interface ClassifyInterface {
List<ClassificationResultModel> classify(Bitmap bitmap, float confidence) throws BaseException;
// 如InferManger 继承 ClassifyInterface
输入 Bitmap 默认格式或者指定Bitmap.Config.ARGB_8888
输出 ClassificationResultModel
异常:一般首次出现。可以打印出异常错误码。
ClassificationResultModel
- label:分类标签,定义在label_list.txt中
- confidence:置信度,0-1
- lableIndex:标签对应的序号
3.3.5 检测Detect
对于EasyDL口罩检测模型请注意输入图片中人脸大小建议保持在88到9696像素,可根据场景远近程度缩放图片后传入
public interface DetectInterface {
List<DetectionResultModel> detect(Bitmap bitmap, float confidence) throws BaseException;
// 如InferManger 继承 DetectInterface
输入 Bitmap 默认格式或者指定Bitmap.Config.ARGB_8888
输出 DetectionResultModel List
异常:一般首次出现。可以打印出异常错误码。
DetectionResultModel
- label:标签,定义在label_list.txt中
- confidence:置信度
- bounds:Rect,左上角和右下角坐标
3.3.6 图像分割Segmentation
暂时只支持通用ARM引擎,不支持其它引擎
public interface SegmentInterface {
List<SegmentationResultModel> segment(Bitmap bitmap, float confidence) throws BaseException;
// 如InferManger 继承 SegmentInterface
输入 Bitmap 默认格式或者指定Bitmap.Config.ARGB_8888
输出 SegmentationResultModel
异常:一般首次出现。可以打印出异常错误码。
SegmentationResultModel
- label:标签,定义在label_list.txt中
- confidence:置信度
- lableIndex:标签对应的序号
- box: Rect对象表示的对象框
- mask:byte[]表示的原图大小的0,1掩码,绘制1的像素即可得到当前对象区域
mask 字段说明, 如何绘制掩码也可参考demo工程
1 0 1
image 1 1 0 => mask(byte[]) 101 110 011
0 1 1
3.3.7 文字识别OCR
暂时只支持通用ARM引擎,不支持其它引擎,暂时只支持EasyEdge的开源OCR模型。
public interface OcrInterface {
List<OcrResultModel> ocr(Bitmap bitmap, float confidence) throws BaseException;
// 如InferManger 继承 OcrInterface
输入 Bitmap 默认格式或者指定Bitmap.Config.ARGB_8888
输出 OcrResultModel List,每个OcrResultModel对应结果里的一个四边形。
异常:一般首次出现。可以打印出异常错误码。
OcrResultModel
- label:识别出的文字
- confidence:置信度
- List<Point>:4个点构成四边形
3.3.8 姿态估计Pose
暂时只支持通用ARM引擎,不支持其它引擎
public interface PoseInterface {
List<PoseResultModel> pose(Bitmap bitmap) throws BaseException;
// 如InferManger 继承 PoseInterface
输入 Bitmap 默认格式或者指定Bitmap.Config.ARGB_8888
输出 PoseResultModel List
异常:一般首次出现。可以打印出异常错误码。
PoseResultModel
- label:标签,定义在label_list.txt中
- confidence:置信度
- Pair<Point, Point>:2个点构成一条线
3.3.9 释放
释放后这个对象不能再使用,如果需要使用可以重新new一个出来。
public void destory() throws BaseException
3.3.10 整体示例
以通用ARM的图像分类预测流程为例:
try {
// step 1: 准备配置类
InferConfig config = new InferConfig(context.getAssets(), "infer");
// step 2: 准备预测 Manager
InferManager manager = new InferManager(context, config, "");
// step 3: 准备待预测的图像,必须为 Bitmap.Config.ARGB_8888 格式,一般为默认格式
Bitmap image = getFromSomeWhere();
// step 4: 预测图像
List<ClassificationResultModel> results = manager.classify(image, 0.3f);
// step 5: 解析结果
for (ClassificationResultModel resultModel : results) {
Log.i(TAG, "labelIndex=" + resultModel.getLabelIndex()
+ ", labelName=" + resultModel.getLabel()
+ ", confidence=" + resultModel.getConfidence());
}
// step 6: 释放资源。预测完毕请及时释放资源
manager.destroy();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
3.3.11 高通骁龙引擎的额外配置
"autocheck_qcom": true, // 如果改成false, sdk跳过检查手机是否是高通的Soc,非高通的Soc会奔溃直接导致app闪退
"snpe_runtimes_order": [],
// 不填写为自动,按照 {DSP, GPU, GPU_FLOAT16, CPU}次序尝试初始化,也可以手动指定如[2,1,3,0], 具体数字的定义见下段
public interface SnpeRuntimeInterface {
int CPU = 0;
int GPU = 1;
int DSP = 2;
int GPU_FLOAT16 = 3;
}
// SnpeManager 中,使用public static ArrayList<Integer> getAvailableRuntimes(Context context) 方法可以获取高通SOC支持的运行方式
集成指南
- 复制库文件libs
- 添加Manifest权限
- 复制模型文件
- 添加调用代码(见上一步具体接口说明)
4.1 复制库文件libs
A. 如果项目里没有自己的jar文件和so文件:
复制app/libs 至自己项目的app/libs目录。
参照demo的app/build.gradle 中添加
android {
....
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
B. 如果项目里有自己的jar文件,但没有so文件
easyedge.jar文件同自己的jar文件放一起
arm64-v8a和armeabi-v7a放到app/src/main/jniLibs目录下
参照demo的app/build.gradle 中添加
android {
....
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
C. 如果项目里有自己的jar文件和so文件
easyedge.jar文件同自己的jar文件放一起
arm64-v8a和armeabi-v7a取交集和自己的so放一起,交集的意思是比如自己的项目里有x86目录,必须删除x86。
参照demo的app/build.gradle 中添加
android {
....
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a' // abiFilter取交集,即只能少不能多
}
}
jar文件库如果没有设置成功的,编译的时候可以发现报错。
so库如果没有编译进去的话,也可以通过解压apk文件确认。运行的时候会有类似jni方法找不到的报错。
4.2 Manifest配置
参考app/src/main/AndroidManifest.xml文件,添加:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- Android 11 支持 -->
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<!-- 高版本 Android 支持 -->
<application
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true">
</application>
4.3 混淆规则(可选)
请不要混淆SDK里的jar文件。
-keep class com.baidu.ai.edge.core.*.*{ *; }
4.4 Android 11支持
除Manifest中必要配置外,请参考BaseActivity
获取所有文件访问权限,否则可能影响SDK正常使用。
SDK 默认使用 easyedge-sdk.jar,未启用 AndroidX,若您的项目使用 AndroidX,并在集成中提示 android.support 相关错误,请参考 app/build.gradle 使用 etc/easyedge-sdk-androidx.jar 以支持 AndroidX:
// app/build.gradle
dependencies {
implementation project(':camera_ui')
implementation files('libs/easyedge-sdk-androidx.jar') // 修改 jar 包依赖
}
错误码
错误码 | 错误描述 | 详细描述及解决方法 |
---|---|---|
1001 | assets 目录下用户指定的配置文件不存在 | SDK可以使用assets目录下config.json作为配置文件。如果传入的config.json不在assets目录下,则有此报错 |
1002 | 用户传入的配置文件作为json解析格式不准确,如缺少某些字段 | 正常情况下,demo中的config.json不要修改 |
19xx | Sdk内部错误 | 请与百度人员联系 |
2001 | XxxxMANAGER 只允许一个实例 | 如已有XxxxMANAGER对象,请调用destory方法 |
2002 | XxxxMANAGER 已经调用过destory方法 | 在一个已经调用destory方法的DETECT_MANAGER对象上,不允许再调用任何方法 |
2003 | 传入的assets下模型文件路径为null | XxxxConfig.getModelFileAssetPath() 返回为null。由setModelFileAssetPath(null)导致 |
2011 | libedge-xxxx.so 加载失败 | System.loadLibrary("edge-xxxx"); libedge-xxxx.so 没有在apk中。CPU架构仅支持armeabi-v7a arm-v8a |
2012 | JNI内存错误 | heap的内存不够 |
2103 | license过期 | license失效或者系统时间有异常 |
2601 | assets 目录下模型文件打开失败 | 请根据报错信息检查模型文件是否存在 |
2611 | 检测图片时,传递至引擎的图片二进制与长宽不符合 | 具体见报错信息 |
27xx | Sdk内部错误 | 请与百度人员联系 |
28xx | 引擎内部错误 | 请与百度人员联系 |
29xx | Sdk内部错误 | 请与百度人员联系 |
3000 | so加载错误 | 请确认所有so文件存在于apk中 |
3001 | 模型加载错误 | 请确认模型放置于能被加载到的合法路径中,并确保config.json配置正确 |
3002 | 模型卸载错误 | 请与百度人员联系 |
3003 | 调用模型错误 | 在模型未加载正确或者so库未加载正确的情况下调用了分类接口 |
50xx | 在线模式调用异常 | 请与百度人员联系 |
报错日志收集
通常 Logcat 可以看见日志及崩溃信息,若设备无法获取日志信息,可使用 Demo 中的 xCrash 工具:
// 1. 引入 app/build.gradle 的 xCrash 依赖
android {
...
dependencies {
implementation 'com.iqiyi.xcrash:xcrash-android-lib:2.4.5' // 可以保存崩溃信息,默认未引入
...
}
}
// 2. 启用日志收集。日志将保存在 /sdcard/<包名>/xCrash
// app/src/main/java/com.baidu.ai.edge/demo/MyApplication.java
protected void attachBaseContext(Context context) {
// 日志保存位置
String basePath = Environment.getExternalStorageDirectory().toString() + "/" + context.getPackageName();
// 启用
XCrash.InitParameters params = new XCrash.InitParameters();
params.setAppVersion(BaseManager.VERSION);
params.setLogDir(basePath + "/xCrash");
XCrash.init(this, params);
}