# 简介
本文档介绍FastDeploy中的模型SDK,在Android环境下:(1)推理操作步骤;(2)介绍模型SDK使用说明,方便开发者了解项目后二次开发。
* [简介](#简介)
* [系统支持说明](#系统支持说明)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. APP 标准版测试](#2-app-标准版测试)
* [2.1 扫码体验](#21-扫码体验)
* [2.2 源码运行](#22-源码运行)
* [3. 精简版测试](#3-精简版测试)
* [SDK使用说明](#sdk使用说明)
* [1. 集成指南](#1-集成指南)
* [1.1 依赖库集成](#11-依赖库集成)
* [1.2 添加权限](#12-添加权限)
* [1.3 混淆规则(可选)](#13-混淆规则可选)
* [2. API调用流程示例](#2-api调用流程示例)
* [2.1 初始化](#21-初始化)
* [2.2 预测图像](#22-预测图像)
* [错误码](#错误码)
# 系统支持说明
1. Android 版本支持范围:Android 5.0(API21)<= Android < Android 10(API 29)。
2. 硬件支持情况:支持 arm64-v8a 和 armeabi-v7a,暂不支持模拟器。
* 官网测试机型:红米k30,Vivo v1981a,华为oxp-an00,华为cdy-an90,华为pct-al10,荣耀yal-al00,OPPO Reno5 Pro 5G
3. 其他说明
* 【图像分割类算法】(1)图像分割类算法,暂未提供实时摄像头推理功能,开发者可根据自己需要,进行安卓开发;(2)PP-Humanseg-Lite模型设计初衷为横屏视频会议等场景,本次安卓SDK仅支持竖屏场景,开发者可根据自己需要,开发横屏功能。
* 【OCR模型】OCR任务第一次启动任务,第一张推理时间久,属于正常情况(因为涉及到模型加载、预处理等工作)。
> 预测图像时运行内存不能过小,一般大于模型资源文件夹大小的3倍。
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。SDK目录结构如下:
```
.EasyEdge-Android-SDK
├── app
│ ├── src/main
│ │ ├── assets
│ │ │ ├── demo
│ │ │ │ └── conf.json # APP名字
│ │ │ ├── infer # 模型资源文件夹,一套模型适配不同硬件、OS和部署方式
│ │ │ │ ├── model # 模型结构文件
│ │ │ │ ├── params # 模型参数文件
│ │ │ │ ├── label_list.txt # 模型标签文件
│ │ │ │ └── infer_cfg.json # 模型前后处理等配置文件
│ │ ├── java/com.baidu.ai.edge/demo
│ │ │ ├── infertest # 通用ARM精简版测试
│ │ │ │ ├── TestInferClassifyTask.java # 图像分类
│ │ │ │ ├── TestInferDetectionTask.java # 物体检测
│ │ │ │ ├── TestInferSegmentTask.java # 实例分割
│ │ │ │ ├── TestInferPoseTask.java # 姿态估计
│ │ │ │ ├── TestInferOcrTask.java # OCR
│ │ │ │ └── MainActivity.java # 精简版启动 Activity
│ │ │ ├── MainActivity.java # Demo APP 启动 Activity
│ │ │ ├── CameraActivity.java # 摄像头UI逻辑
│ │ │ └── ...
│ │ └── ...
│ ├── libs
│ │ ├── armeabi-v7a # v7a的依赖库
│ │ ├── arm64-v8a # v8a的依赖库
│ │ └── easyedge-sdk.jar # jar文件
│ └── ...
├── camera_ui # UI模块,包含相机逻辑
├── README.md
└── ... # 其他 gradle 等工程文件
```
## 2. APP 标准版测试
考虑部分Android开发板没有摄像头,因此本项目开发了标准版和精简版两种。标准版会调用Android系统的摄像头,采集摄像头来进行AI模型推理;精简版在没有摄像头的开发板上运行,需要开发者准备图像。开发者根据硬件情况,选择对应的版本。
### 2.1 扫码体验
扫描二维码(二维码见下载网页`体验Demo`),无需任何依赖,手机上下载即可直接体验。

### 2.2 源码运行
(1)下载对应的SDK,解压工程。

(2)打开Android Studio, 点击 "Import Project...",即:File->New-> "Import Project...", 选择解压后的目录。
(3)手机链接Android Studio,并打开开发者模式。(不了解开发者模式的开发者,可浏览器搜索)
(4)此时点击运行按钮,手机上会有新app安装完毕,运行效果和二维码扫描的一样。

## 3. 精简版测试
* 考虑部分Android开发板没有摄像头,本项目提供了精简版本,精简版忽略摄像头等UI逻辑,可兼容如无摄像头的开发板测试。
* 精简版对应的测试图像路径,在代码`src/main/java/com.baidu.ai.edge/demo/TestInfer*.java`中进行了设置,开发者可以准备图像到对应路径测试,也可以修改java代码测试。
* 支持以下硬件环境的精简版测试:通用ARM:图像分类、物体检测、实例分割、姿态估计、文字识别。
示例代码位于 app 模块下 infertest 目录,修改 app/src/main/AndroidManifest.xml 中的启动 Activity 开启测试。
修改前:
```
infertest.MainActivity
```
修改后:
```
```
注意:修改后,因为没有测试数据,需要开发者准备一张测试图像,放到 `app/src/main/asserts/` 路径下,并按照`app/src/main/java/com/baidu/ai/edge/demo/infertest/TestInfer*.java`中的图像命名要求对图像进行命名。
| Demo APP 检测模型运行示例 | 精简版检测模型运行示例 |
| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|  |  |
# SDK使用说明
本节介绍如何将 SDK 接入开发者的项目中使用。
## 1. 集成指南
步骤一:依赖库集成
步骤二:添加必要权限
步骤三:混淆配置(可选)
### 1.1 依赖库集成
A. 项目中未集成其他 jar 包和 so 文件:
```
// 1. 复制 app/libs 至项目的 app/libs 目录
// 2. 参考 app/build.gradle 配置 NDK 可用架构和 so 依赖库目录
android {
...
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
```
B. 项目中已集成其他 jar 包,未集成 so 文件:
```
// 1. 复制 app/libs/easyedge-sdk.jar 与其他 jar 包同目录
// 2. 复制 app/libs 下 armeabi-v7a 和 arm64-v8a 目录至 app/src/main/jniLibs 目录下
// 3. 参考 app/build.gradle 配置 NDK 可用架构
android {
...
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
```
C. 项目中已集成其他 jar 包和 so 文件:
```
// 1. 复制 app/libs/easyedge-sdk.jar 与其他 jar 包同目录
// 2. 融合 app/libs 下 armeabi-v7a 和 arm64-v8a 下的 so 文件与其他同架构 so 文件同目录
// 3. 参考 app/build.gradle 配置 NDK 可用架构
android {
...
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a' // 只支持 v7a 和 v8a 两种架构,有其他架构需删除
}
}
}
```
### 1.2 添加权限
参考 app/src/main/AndroidManifest.xml 中配置的权限。
```
```
### 1.3 混淆规则(可选)
请不要混淆 jar 包文件,参考 app/proguard-rules.pro 配置。
```
-keep class com.baidu.ai.edge.core.*.*{ *; }
```
## 2. API调用流程示例
以通用ARM的图像分类预测流程为例,详细说明请参考后续章节:
```
try {
// step 1-1: 准备配置类
InferConfig config = new InferConfig(context.getAssets(), "infer");
// step 1-2: 准备预测 Manager
InferManager manager = new InferManager(context, config, "");
// step 2-1: 准备待预测的图像,必须为 Bitmap.Config.ARGB_8888 格式,一般为默认格式
Bitmap image = getFromSomeWhere();
// step 2-2: 预测图像
List results = manager.classify(image, 0.3f);
// step 3: 解析结果
for (ClassificationResultModel resultModel : results) {
Log.i(TAG, "labelIndex=" + resultModel.getLabelIndex()
+ ", labelName=" + resultModel.getLabel()
+ ", confidence=" + resultModel.getConfidence());
}
// step 4: 释放资源。预测完毕请及时释放资源
manager.destroy();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
```
### 2.1 初始化
**准备配置类**
芯片与配置类对应关系:
- 通用ARM:InferConfig
```
// 示例
// 参数二为芯片对应的模型资源文件夹名称
InferConfig config = new InferConfig(context.getAssets(), "infer");
```
**准备预测 Manager**
芯片与 Manager 对应关系:
- 通用ARM:InferManager
```
// 示例
// 参数二为配置类对象
// 参数三保持空字符串即可
InferManager manager = new InferManager(context, config, "");
```
> **注意**
>
> 1. 同一时刻只能有且唯一有效的 Manager,若要新建一个 Manager,之前创建的 Manager 需先调用 destroy() 销毁;
> 2. Manager 的任何方法都不能在 UI 线程调用;
> 3. Manager 的任何成员变量及方法由于线程同步问题,都必须在同一个线程中执行;
### 2.2 预测图像
本节介绍各种模型类型的预测函数及结果解析。
> **注意**
> 预测函数可以多次调用,但必须在同一个线程中,不支持并发
> 预测函数中的 confidence 非必需,默认使用模型推荐值。填 0 可返回所有结果
> 待预测的图像必须为 Bitmap.Config.ARGB_8888 格式的 Bitmap
**图像分类**
```
// 预测函数
List classify(Bitmap bitmap) throws BaseException;
List classify(Bitmap bitmap, float confidence) throws BaseException;
// 返回结果
ClassificationResultModel
- label: 分类标签,定义在label_list.txt中
- labelIndex: 分类标签对应的序号
- confidence: 置信度,0-1
```
**物体检测**
```
// 预测函数
List detect(Bitmap bitmap) throws BaseException;
List detect(Bitmap bitmap, float confidence) throws BaseException;
// 返回结果
DetectionResultModel
- label: 标签,定义在label_list.txt中
- confidence: 置信度,0-1
- bounds: Rect,包含左上角和右下角坐标,指示物体在图像中的位置
```
**实例分割**
```
// 预测函数
List segment(Bitmap bitmap) throws BaseException;
List segment(Bitmap bitmap, float confidence) throws BaseException;
// 返回结果
SegmentationResultModel
- label: 标签,定义在label_list.txt中
- confidence: 置信度,0-1
- lableIndex: 标签对应的序号
- box: Rect,指示物体在图像中的位置
- mask: byte[],表示原图大小的0,1掩码,绘制1的像素即可得到当前对象区域
- maskLEcode: mask的游程编码
```
> 关于 maskLEcode 的解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
**姿态估计**
```
// 预测函数
List pose(Bitmap bitmap) throws BaseException;
// 返回结果
PoseResultModel
- label: 标签,定义在label_list.txt中
- confidence: 置信度,0-1
- points: Pair, 2个点构成一条线
```
**文字识别**
```
// 预测函数
List ocr(Bitmap bitmap) throws BaseException;
List ocr(Bitmap bitmap, float confidence) throws BaseException;
// 返回结果
OcrResultModel
- label: 识别出的文字
- confidence: 置信度,0-1
- points: List, 文字所在区域的点位
```
# 错误码
| 错误码 | 错误描述 | 详细描述及解决方法 |
| ---- | ------------------------------ | ------------------------------------------------------------------------------------ |
| 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 | 在线模式调用异常 | 请与百度人员联系 |