开放能力
开发平台
行业应用
生态合作
开发与教学
资讯 社区 控制台
技术能力
语音技术
文字识别
人脸与人体
图像技术
语言与知识
视频技术
AR与VR
数据智能
场景方案
部署方案
行业应用
智能教育
智能医疗
智能零售
智能工业
企业服务
智能政务
信息服务
智能园区

物体检测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..."。在一台较新的手机上测试。

详细步骤如下:

  1. 准备一台较新的手机,如果不是通用arm版本,请参见本文的“硬件要求”,确认是否符合SDK的要求
  2. 安装较新版本的AndroidStudio ,下载地址
  3. 新建一个HelloWorld项目, Android Studio会自动下载依赖, 在这台较新的手机上测试通过这个helloworld项目。注意不支持模拟器。
  4. 解压下载的SDK。
  5. 打开AndroidStudio, 点击 "Import Project..."。 即:File->New-> "Import Project...", 选择解压后的目录。
  6. 此时点击运行按钮(同第3步),手机上会有新app安装完毕,运行效果和二维码扫描的一样。
  7. 手机上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 检测模型运行示例 精简版检测模型运行示例
image.png image.png

使用说明

3.1 代码目录结构

集成时需要“复制到自己的项目里”的目录或者文件:

  1. app/libs
  2. 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

  1. 准备配置类,如InferConfig,输入:通常为一个assets目录下的文件夹,如infer。
  2. 初始化Manager,比如InferManager。输入:第1步的配置类和序列号
  3. 推理图片,可以多次调用 3.1 准备图片,作为Bitmap输入 3.2 调用对应的推理方法,比如detect 3.3 解析结果,结果通常是一个List,调用结果类的Get方法,通常能获取想要的结果
  4. 直到长时间不再使用我们的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

注意要点

  1. 同一个时刻只能有唯一有效的InferManager。旧的InferManager必须调用destory后,才能新建一个new InferManager() 。
  2. InferManager的任何方法,都不能在UI线程中调用。
  3. 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支持的运行方式

集成指南

  1. 复制库文件libs
  2. 添加Manifest权限
  3. 复制模型文件
  4. 添加调用代码(见上一步具体接口说明)

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);
}
上一篇
纯离线SDK简介
下一篇
iOS集成文档