上云无忧 > 文档中心 > 百度智能云飞桨EasyDL零门槛AI开发平台零售行业版 - 货架拼接服务Android_SDK
飞桨EasyDL零门槛AI开发平台
百度智能云飞桨EasyDL零门槛AI开发平台零售行业版 - 货架拼接服务Android_SDK

文档简介:
本文介绍SDK的的功能使用,即下载包中的sdk module。 SDK为货架拼接云端非实时API和手机端实时拼接的封装,无任何额外功能。如果有和API文档不符的地方,以SDK为准。 支持Android Level 22及以上编译和使用。
*此产品及展示信息均由百度智能云官方提供。免费试用 咨询热线:400-826-7010,为您提供专业的售前咨询,让您快速了解云产品,助您轻松上云! 微信咨询
  免费试用、价格特惠

简介

本文介绍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 支持拍摄视频,端上抽帧,云端拼接

测试

获取鉴权

  1. 进入EasyDL零售版的百度智能云控制台应用列表页面,如下图所示:

  1. 如果还未创建应用,请点击「创建应用」按钮进行创建。创建应用后,参考鉴权参考文档,使用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个方法21 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; }

阈值的设置

手机端实时拼接支持设置:

  1. 最小IOU置信度
  2. 最大IOU置信度
  3. NMS置信度
  4. 商品检测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; }

相似文档
官方微信
联系客服
400-826-7010
7x24小时客服热线
分享
  • QQ好友
  • QQ空间
  • 微信
  • 微博
返回顶部