资讯 文档
技术能力
语音技术
文字识别
人脸与人体
图像技术
语言与知识
视频技术

Android-SDK

简介

此文档介绍飞桨开源模型SDK如何进行开发集成

系统支持

Android 版本:支持 Android 5.0(API 21) 及以上

硬件:支持 arm64-v8a 和 armeabi-v7a,暂不支持模拟器

预测图像时运行内存不能过小,一般大于模型资源文件夹大小的3倍。

快速开始

文件结构说明

.EasyEdge-Android-SDK
├── app
│   ├── src/main
│   │   ├── assets
│   │   │   ├── demo					# demo配置文件夹
│   │   │   │   └── conf.json
│   │   │   ├── infer					# 模型资源文件夹
│   │   │   │   ├── 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 等工程文件

测试精简版

精简版忽略摄像头等UI逻辑,可兼容如无摄像头的开发板测试。

支持以下硬件环境的精简版测试:

  • 通用ARM:图像分类、物体检测、实例分割、姿态估计、文字识别

示例代码位于 app 模块下 infertest 目录,修改 app/src/main/AndroidManifest.xml 中的启动 Activity 开启测试。

<!-- 以通用ARM为例 -->
<activity android:name=".infertest.MainActivity">
	<intent-filter>
		<action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
Demo APP 检测模型运行示例 精简版检测模型运行示例
image.png image.png

SDK使用说明

本节介绍如何将 SDK 接入开发者的项目中使用。

集成指南

步骤一:依赖库集成 步骤二:添加必要权限 步骤三:混淆配置(可选)

依赖库集成

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 两种架构,有其他架构需删除
        }
	}
}

添加权限

参考 app/src/main/AndroidManifest.xml 中配置的权限。

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

混淆规则(可选)

请不要混淆 jar 包文件,参考 app/proguard-rules.pro 配置。

-keep class com.baidu.ai.edge.core.*.*{ *; }

调用流程示例

以通用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());
}

初始化

准备配置类 芯片与配置类对应关系:

  • 通用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 的任何成员变量及方法由于线程同步问题,都必须在同一个线程中执行;

预测图像

本节介绍各种模型类型的预测函数及结果解析。

注意 预测函数可以多次调用,但必须在同一个线程中,不支持并发 预测函数中的 confidence 非必需,默认使用模型推荐值。填 0 可返回所有结果 待预测的图像必须为 Bitmap.Config.ARGB_8888 格式的 Bitmap

图像分类

// 预测函数
List<ClassificationResultModel> classify(Bitmap bitmap) throws BaseException;
List<ClassificationResultModel> classify(Bitmap bitmap, float confidence) throws BaseException;

// 返回结果
ClassificationResultModel
- label: 分类标签,定义在label_list.txt中
- labelIndex: 分类标签对应的序号
- confidence: 置信度,0-1

物体检测

// 预测函数
List<DetectionResultModel> detect(Bitmap bitmap) throws BaseException;
List<DetectionResultModel> detect(Bitmap bitmap, float confidence) throws BaseException;

// 返回结果
DetectionResultModel
- label: 标签,定义在label_list.txt中
- confidence: 置信度,0-1
- bounds: Rect,包含左上角和右下角坐标,指示物体在图像中的位置

实例分割

// 预测函数
List<SegmentationResultModel> segment(Bitmap bitmap) throws BaseException;
List<SegmentationResultModel> 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

姿态估计

// 预测函数
List<PoseResultModel> pose(Bitmap bitmap) throws BaseException;

// 返回结果
PoseResultModel
- label: 标签,定义在label_list.txt中
- confidence: 置信度,0-1
- points: Pair<Point, Point>, 2个点构成一条线

文字识别

// 预测函数
List<OcrResultModel> ocr(Bitmap bitmap) throws BaseException;
List<OcrResultModel> ocr(Bitmap bitmap, float confidence) throws BaseException;

// 返回结果
OcrResultModel
- label: 识别出的文字
- confidence: 置信度,0-1
- points: List<Point>, 文字所在区域的点位

模型替换说明

模型资源文件位于 app/src/main/assets 目录下,开发者可替换运行其他模型:

  • infer/model:模型网络结构文件,对应Paddle1.x的__model__,Paddle2.x的model.pdmodel
  • infer/params:模型网络参数文件,对应Paddle1.x的__params__,Paddle2.x的model.pdiparams
  • infer/label_list.txt:label文件
  • infer/infer_cfg.json:模型推理的预处理、后处理配置文件,具体见下
  • demo/conf.json:【非必需】Demo App 配置文件,建议配置 modelName,缺少不影响运行

infer_cfg.json说明

其中,非标记【必须】的可不填

{
    "version": 1,
    "model_info": { 
        "best_threshold": 0.3,   // 默认0.3
        "model_kind": 1, // 【必须】 1-分类,2-检测,6-实例分割,14-语义分割,401-人脸,402-姿态
    },
    "pre_process": { // 【必须】
        // 归一化, 预处理会把图像 (origin_img - mean) * scale 
        "skip_norm": false, // 默认为false, 如果设置为true,不做mean scale处理
        "mean": [123, 123, 123],  // 【必须】
        "scale": [0.017, 0.017, 0.017],  // 【必须】
        "color_format": "RGB", // BGR 【必须】
        "channel_order": "CHW", // HWC
        // 大小相关
        "resize": [300, 300],  // w, h 【必须】
        "rescale_mode": "keep_size", // 默认keep_size, keep_ratio, keep_ratio2, keep_raw_size, warp_affine
        "max_size": 1366, // keep_ratio 用。如果没有提供,则用 resize[0]
        "target_size": 800,  // keep_ratio 用。如果没有提供,则用 resize[1]
        "raw_size_range": [100, 10000], // keep_raw_size 用
        "warp_affine_keep_res": // warp_affine模式使用,默认为false
        "center_crop_size": [224, 224], // w, h, 如果需要做center_crop,则提供,否则,无需提供该字段
        "padding": false,
        "padding_mode": "padding_align32",  // 【非必须】默认padding_align32, 其他可指定:padding_fill_size
        "padding_fill_size": [416, 416], // 【非必须】仅padding_fill_size模式下需要提供, [fill_size_w, fill_size_h], 这里padding fill对齐paddle detection实现,在bottom和right方向实现补齐
        "padding_fill_value": [114, 114, 114] // 【非必须】仅padding_fill_size模式下需要提供
        // 其他
        "letterbox": true,
        "ocr_rec_resize": [320, 48], // 【非必须】仅ocr需提供
        "ocr_rec_batch_num": 6, // 【非必须】仅ocr需提供,默认为1
     }
}

预处理的顺序如下(没有的流程自动略过):

  1. 灰度图 -> rgb图变换
  2. resize 尺寸变换
  3. center_crop
  4. rgb/bgr变换
  5. padding_fill_size
  6. letterbox(画个厚边框,填上黑色)
  7. chw/hwc变换
  8. 归一化:mean, scale
  9. padding_align32

rescale_mode说明:

  • keep_size: 将图片缩放到resize指定的大小
  • keep_ratio: 将图片按比例缩放,长边不超过max_size,短边不超过target_size
  • keep_raw_size: 保持原图尺寸,但必须在raw_size_range之间
  • warp_affine: 仿射变换,可以设置warp_affine_keep_res指定是否keep_res,在keep_res为false场景下,宽高通过resize字段指定

错误码

错误码 错误描述 详细描述及解决方法
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);
}
上一篇
飞桨开源模型体验介绍
下一篇
iOS-SDK