文档简介:
简介
本文介绍SDK的的功能使用,即下载包中的sdk module。
SDK为货架拼接云端非实时API和手机端实时拼接的封装,无任何额外功能。如果有和API文档不符的地方,以SDK为准。
支持Android Level 22及以上编译和使用。
Release Notes
时间 | 版本 | 说明 |
---|---|---|
2021.12.22 | 4.1.0 | 新增手机端实时拼接模糊图像检测功能 |
2021.08.20 | 4.0.0 | 新增手机端实时拼接功能 |
2021.03.09 | 3.0.1 | 新增光线和手机方向检测功能 |
2020.12.30 | 3.0.0 | 新增支持拍摄图片,云端拼接功能 |
2020.11.12 | 2.0.0 | 新增支持排面统计占比 |
2019.08.30 | 1.0.0 | 支持拍摄视频,端上抽帧,云端拼接 |
测试
获取鉴权
- 进入EasyDL零售版的百度智能云控制台应用列表页面,如下图所示:
- 如果还未创建应用,请点击「创建应用」按钮进行创建。创建应用后,参考鉴权参考文档,使用API Key(AK)和Secret Key(SK)获取access_token
{
"ak": "Mz0zhObvEZ6lnG1K3renXXXX", // API Key的值
"sk": "188fRHYvLPmlPrNCDpBnkhL3ydXXXXX", // Secret Key的值
"apiUrl": "https://aip.baidubce.com/rpc/2.0/ai_custom_retail/v1/detection/XXXX" // 定制商品检测服务API
}
正常情况下,启动的app及其功能和扫描二维码一致
demo的请求和结果会放在/sdcard/com.baidu.ai.easydl.montage中
测试云端非实时拼接mini demo
测试app通过后,可以修改app/src/main/AndroidManifest.xml 内的启动app,修改为 "com.baidu.ai.easydl.minidemo.MiniActivity"
MiniActivity中有3个task,测试时需要填入 Appkey, AppSecret, ApiUrl信息
- ApiTestAsyncTask ,测试简单流程。
- QueryAsyncTask , 测试查询列表。
- RequestTestAsyncTask,测试assets/request下的图片输入。这个目录可以从SD卡中/sdcard/com.baidu.ai.easydl.montage/X/request复制。
云端非实时拼接调用流程
第1步, 创建任务,上传图片
1)【创建任务:开始拼接整个流程】
2)【加货架图:上传图片】
3)【开始任务:启动货架拼接离线任务】
第2步,不定时查询结果,一般10分钟后有结果参数
【查询结果:查询任务运行状态或者结果】
其它可选操作:
【终止任务:终止正在进行或者等待的任务】
【任务列表:查询所有状态的任务列表】
SDK 调用
根据调用流程, SDK有两种调用方式:
- StitchApi,api的封装
- StitchTask,StitchApi的封装,避免taskId的传递。一个task对应一个StitchTask
返回参数以及其他信息详见文档货架拼接API调用方法。
StitchApi
初始化
/** * 初始化 * @param appKey 网页上的应用的appkey * @param secretKey 网页上的应用的appSecret */ public StitchApi(String appKey, String secretKey) { super(appKey, secretKey); } /** * 初始化 * @param appKey 网页上的应用的appkey * @param secretKey 网页上的应用的appSecret * @param connection 自定义HTTP连接 */ public StitchApi(String appKey, String secretKey, ISdkConnection connection)
{ super(appKey, secretKey, connection); }
创建任务
public CreateStitchResponse create(CreateStitchRequest request);
// CreateStitchRequest 及 CreateStitchResponse 参数同API文档
同步上传图片
public CommonStitchResponse upload(UploadImageRequest request);
// UploadImageRequest 及 CreateStitchResponse 参数同API文档
设置图片的话,以下2个方法2选1 public void setImageFile(String imageFile);
public void setImageInputStream(InputStream inputStream)
异步上传图片
public void uploadAsync(UploadImageRequest request, IApiResponseListener<CommonStitchResponse>
listener) // UploadImageRequest 参数同API文档 // IApiResponseListener<CommonStitchResponse>
接口: onSdkResponse(CommonStitchResponse response, String userDefinedRequestId)
// 其中userDefinedRequestId是在UploadImageRequest 里面设置的 // 使用 clearAysncQueue()可以清空未开始的任务
开始任务
CommonStitchResponse start(CommonStitchRequest request)
查询结果
public QueryStitchReponse query(CommonStitchRequest request)
任务列表
public ListStitchResponse list(ListStitchRequest request)
StitchTask
一个任务新建一个StitchTask 调用方式同 StitchApi, 参数中不必设置taskId
AbstractApiRequest
目前Request类的基类 。
// 设置自定义请求Id, 调用异步接口的回调使用 public void setUserDefinedRequestId(String userDefinedRequestId)
// 设置是否添加debug日志 public void setEnableDebug(boolean enableDebug)
CommonStitchResponse 及 AbstractApiResponse
// 获取任务状态 public String getTaskStatus(); // 获取logId public String getLogId();
// 获取服务端返回的原始json public JSONObject getOriginalJson(); // 获取请求 public AbstractApiRequest getRequest();
手机端实时拼接调用流程
第1步:初始化
1)【获取实例】
2)【初始化API】
第2步:对比图片
新图片(now)在参与实时拼接前需先与上一张参与拼接的图片(last)进行对比,如果now与last的对比特征合法则可以成功拼接,否则无法得到理想实时拼接结果
第3步:实时拼接
SDK会寻找now.jpg并进行实时拼接得到新结果
第4步:上传云端,得到结果
SDK 调用
手机端实时拼接各流程通过 MobileStitchAPI 调用,具体使用和返回参数见下
初始化
MobileStitchAPI不支持多线程,且仅有一个实例以保证实时拼接过程中的正确文件操作。
获取实例
/**
* 获取实例
*
* @param appKey 网页上的应用的appkey
* @param secretKey 网页上的应用的appSecret
* @param apiUrl 商品检测服务API
*/ public static MobileStitchAPI getInstance(String appKey, String secretKey, String apiUrl); /**
* 获取实例
*
* @param appKey 网页上的应用的appkey
* @param secretKey 网页上的应用的appSecret
* @param apiUrl 商品检测服务API
* @param numConcurrency 同时调用商品检测API的并发数
*/ public static MobileStitchAPI getInstance(String appKey, String secretKey, String apiUrl, int numConcurrency);
初始化API
/**
* 初始化API
*
* @param workDirPath 保存实时拼接过程产生的各类文件的路径
*/ public void init(String workDirPath);
- 异步回调:MobileStitchAPIListener.onAPIPrepared(int, int[])
对比图片
/**
* 对比当前图片与上一张参与拼接的图片
*
* @param currentImgBitmap 当前要参与对比的图片
* @param firstFrame 是否是第一帧
*/ public void compareImages(Bitmap currentImgBitmap, boolean firstFrame);
- 第一帧的定义取决于上一张参与拼接的图片(last)是否已经被对比过。假设有图片A和B,先用A与last对比,且last是初次被对比,此时firstFrame应为true,再用B与last对比,此时firstFrame应为false。
- 异步回调:MobileStitchAPIListener.onImagesCompared(CompareResult)
CompareResult
// 当前图片相对上一张参与拼接的图片的方位,参考MobileStitchAPI.DIRECTION_{LEFT|UP|RIGHT|DOWN|UNKNOWN}
public int getDirection(); // 对比结果中的方位是否合法,非法的方位将无法完成拼接 public boolean isDirectionValid(); /** * 是否需要判断方向,如当拍摄完图片过近时,direction可能由于两图过于相似而不可靠,这种情况不需要判断方向,即该值=false * 一般direction不可靠时,该值=false * 对比的两张图是第一次对比时,该值=false * 当该值=true时,请在调用实时拼接API前确认方法是否合法 */ public boolean needCheckDirection(); // 两张图片重叠部分的点位 public List<PointF> getPoints();
对比结果的合法性判断参考
switch (compareResult.getOverlapStatus()) { case CompareResult.OVERLAP_CORRECT: if
(compareResult.needCheckDirection() && !compareResult.isDirectionValid()) { //
非法,当前参与对比的图片方位不正确,无法拼接 } else { // 合法 } break; case CompareResult.OVERLAP_TOO_FAR:
// 非法,两张图重叠度过低 break; case CompareResult.OVERLAP_TOO_CLOSE: // 非法,两张图重叠度过高 break; }
实时拼接
/**
* 拼接图片
*
* @param compareResult 对比图片回调返回的结果
*/ public void stitchImage(CompareResult compareResult);
- 建议调用拼接前参考【对比结果的合法性判断】,用不合法的对比结果进行实时拼接将无法获得正确输出
- 将要参与拼接的图片必须命名为“now.jpg”(也可使用MobileStitchAPI.IMAGE_NAME_NOW),并保存在初始化API时的 workDirPath 目录下,否则实时拼接无法正常工作。成功拼接后"now.jpg"会被SDK重新命名为{index}.jpg,其中{index}代表图片序号。
- 为获得更快的拼接效率,建议减小参与拼接的图片尺寸;为了保证拼接效果,缩放后的图片尺寸应不小于宽648和高864
-
异步回调:
- 缩略拼接图生成:MobileStitchAPIListener.onStitchThumbnailGenerated(String)
- 完整拼接图生成:MobileStitchAPIListener.onStitchFullImageGenerated(String)
- 拼接完成:MobileStitchAPIListener.onStitchCompleted(MobileStitchResult)
MobileStitchResult
// 获取缩略拼接图路径 public String getThumbnailPath(); // 获取完整拼接图路径 public String getFullImgPath();
// 获取最近一张参与拼接的图片的序号 public int getLatestPhotoIndex(); // 拼接是否成功 public boolean isSuccess();
保存最佳尺寸的图片以提高商品检测精度
SDK默认使用以上保存的一系列{index}.jpg调用商品检测API并取得结果,由于建议减小该系列图片尺寸以获得更优的拼接效率,但同时更小尺寸的图片对商品检测精度有一定影响,因此为提高精度,建议同时保存最佳尺寸的图片用于上传云端。
// 1.原图 Bitmap bitmap = getFromSomewhere(); // 2.计算最佳缩放系数 float scaleFactor
= calculateScaleFactor(bitmap); // 3.缩放获得最佳尺寸的图片 Bitmap scaledBitmap =
Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() * scaleFactor), (int)
(bitmap.getHeight() * scaleFactor), true); // 4.保存 String fullImgFilepath = workDirPath +
"/" + MobileStitchAPI.DIR_NAME_FULL_IMAGE + "/" + MobileStitchAPI.IMAGE_NAME_NOW; ImageUtil.
saveBitmap(scaledBitmap, fullImgFilepath); /** * 计算最佳缩放系数 */ private float calculateScaleFactor(Bitmap originalBitmap) { int longerSide; int shorterSide;
if (originalBitmap.getWidth() > originalBitmap.getHeight()) { longerSide = originalBitmap.getWidth();
shorterSide = originalBitmap.getHeight(); } else { longerSide = originalBitmap.getHeight();
shorterSide = originalBitmap.getWidth(); } return Math.min(1333f / longerSide, 800f / shorterSide); }
撤销拼接结果
SDK支持撤销最后一次拼接结果,请自行编码删除最后一张参与拼接的图片,再调用MobileStitchAPI.notifyLatestPhotoDeletion()通知SDK,参考:
// 最后一张参与拼接的图片路径,workDirPath为初始化时工作目录路径 // latestPhotoIndex为最后一张参与拼接的图片序号,
可在 MobileStitchAPIListener 以下回调时赋值 // 1. onAPIPrepared() - 参数takenPhotoSize //
2. onStitchCompleted() - 参数result.getLatestPhotoIndex() // 3. onDeletionConfirmed()
- 参数latestPhotoIndex String filepath = workDirPath + "/" + latestPhotoIndex + ".jpg";
// 删除图片 FileUtil.deleteFile(filepath); // 通知SDK // SDK确认删除后回调 MobileStitchAPIListener.
onDeletionConfirmed(int, int[]) mobileStitchAPI.notifyLatestPhotoDeletion();
上传云端,得到结果
/**
* 上传云端检测,并获得结果
*/ public void mergeDetectResults();
-
异步回调:
- 上传进度更新:MobileStitchAPIListener.onDetectProgressUpdated(int)
- 检测完成:MobileStitchAPIListener.onDetectedResultsMerged(MergeResult)
MergeResult
// 获取商品检测并去重后的结果 public String getCorrectedSKUJson();
MobileStitchAPIListener
手机端实时拼接通过 MobileStitchAPIListener 异步回调各函数结果,监听器可通过:
- mobileStitchAPI.registerListener()注册
- mobileStitchAPI.unRegisterListener()注销
/**
* API准备好时的回调
*
* @param takenPhotoSize 工作目录下已拍摄的图像数量
* @param latestPhotoPos 最新拍摄图片的坐标
*/ void onAPIPrepared(int takenPhotoSize, int[] latestPhotoPos); /**
* 图片对比完成
*
* @param compareResult 对比结果
*/ void onImagesCompared(CompareResult compareResult); /**
* 调用拼接接口后,缩略图生成后的回调
*
* @param thumbnailName 缩略图在工作目录下的文件名
*/ void onStitchThumbnailGenerated(String thumbnailName); /**
* 调用拼接接口后,完整拼接图片生成后的回调
*
* @param fullImageName 完成拼接图片在工作目录下的文件名
*/ void onStitchFullImageGenerated(String fullImageName); /**
* 拼接完成回调
*
* @param mobileStitchResult 拼接结果
*/ void onStitchCompleted(MobileStitchResult mobileStitchResult); /**
* 删除确认回调
*
* @param latestPhotoIndex -1=操作失败,否则返回删除后,最新拍摄图片的下标;如删除了3.jpg,将返回2
* @param latestPhotoPos 最新拍摄图片的坐标
*/ void onDeletionConfirmed(int latestPhotoIndex, int[] latestPhotoPos); /**
* 检测图片进度更新回调
*
* @param leftCount 剩余要处理图片的数量
*/ void onDetectProgressUpdated(int leftCount); /**
* 商品检测并去重处理完成的回调
*
* @param mergeResult 检测并去重结果
*/ void onDetectedResultsMerged(MergeResult mergeResult);
模糊图像检测
手机端实时拼接已接入AI模型以支持模糊图像检测,需引入以下依赖库及模型文件:
- libedge-infer.so:模糊图像检测引擎库
- easyedge-sdk.jar:模糊图像检测引擎库
- sdk/src/main/assets/infer/:模糊图像检测模型所在文件夹
以下为调用示例,也可参考 app/src/main/java/com/baidu/ai/easydl/montage/page/photo/mobilestitch/MobileStitchViewPresenter.java 类中对 FuzzyModelProxy 的使用:
/* 初始化 */ FuzzyModelProxy fuzzyModelStateListener = new FuzzyModelProxy.ModelStateListener()
{ @Override public void onInitialized(Exception exception) { if (exception != null)
{ // 模糊模型初始化失败 } else { // 模糊模型初始化成功 } } @Override public void onDestroyed()
{ // 模糊模型销毁回调 } }; FuzzyModelProxy fuzzyModelProxy = new FuzzyModelProxy(mContext,
fuzzyModelStateListener); fuzzyModelProxy.initModel(); /* 调用示例 */ if (fuzzyModelProxy.
modelEngineActivate()) { Bitmap bitmap = bitmapFromSomewhere(); fuzzyModelProxy.infer
(bitmap, new FuzzyModelProxy.ModelInferListener() { @Override public void onCompleted(boolean fuzzy)
{ if (!fuzzy) { // 图像非模糊 } else { // 图像模糊 } } @Override public void onException(Exception
exception) { // 图像检测失败 } } } else { // 模糊图像推理引擎异常 } /* 销毁 */ if (fuzzyModelProxy
!= null) { fuzzyModelProxy.destroyModelEngine(); fuzzyModelStateListener = null; }
阈值的设置
手机端实时拼接支持设置:
- 最小IOU置信度
- 最大IOU置信度
- NMS置信度
- 商品检测API最大重试次数
/**
* 设置最低iou置信度,需在init()后调用
*
* @param threshold 在0-1范围内有效
*/ public void setMinIouThreshold(float threshold); /**
* 设置最高iou置信度,需在init()后调用
*
* @param threshold 在0-1范围内有效
*/ public void setMaxIouThreshold(float threshold); /**
* 设置NMS置信度,需在init()后调用
*
* @param threshold 在0-1范围内有效
*/ public void setNmsIouThreshold(float threshold); /**
* 设置商品检测API最大重试次数
*
* @param maxRetryTimes 最大重试次数,<=0无效
*/ public void setMaxRetryTimes(int maxRetryTimes);
集成指南
添加NDK编译架构
SDK依赖OpenCV库,需添加NDK编译选项,支持常用的两个架构,可参考app/build.gradle配置
ndk {
abiFilters "arm64-v8a", "armeabi-v7a"
}
集成拍照逻辑
查看com.baidu.ai.easydl.montage.page.photo.take 包,里面均为摄像拍照逻辑。
拍照参数设置
package com.baidu.ai.easydl.montage.page.photo; public interface IPhotoParam { /** * 两张图片的hash算法 */ String IMAGE_COMPARE_HASH_METHOD = "pHash"; // pHash,dHash,ahash /** * 两张图片的hash比较值 */ float IMAGE_COMPARE_HASH_CONFIDENCE_THRESHOLD = 0.75f; /** * 相机的Sensor的旋转误差值, 取值为0-180,大于180表示忽略 */ int SENSOR_ORIENTATION_EVENT_DELTA = 20; /** * 传感器的SensorY的旋转误差值, 取值为0-180,大于180表示忽略 */ double SENSOR_ORIENTATION_SENSOR_Y_DELTA = Math.PI / 6; /** * 拍照建议的最低亮度值 */ double SENSOR_LIGHT_LUMEN_MIN = 100; /** * 拍照建议的最高亮度值 */ double SENSOR_LIGHT_LUMEN_MAX = 500; /** * 40%图片的透明度 */ float IMAGE_SLIDE_TRANSPARENT_ALPHA = 0.5f; /** * 每行货架最多的照片数量,服务端支持最大60 */ int SLOT_MAX_PHOTO_NUM = 60; // 下面的参数,请不要修改 float IMAGE_SLIDE_CROP_RATIO
= 0.4f; boolean IMAGE_COMPARE_HASH_DEBUG_SAVE_IMAGES = false; }