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

iOS_SDK

简介

本文档描述货架拼接iOS SDK如何使用。

系统支持

系统:iOS 9.0 以上

硬件:armv7 arm64 (Starndard architectures)(暂不支持模拟器)

Release Notes

时间 版本 说明
2022.12.22 5.0.0 更名为门店拜访SDK,新增门脸文字识别功能、防窜拍功能
2021.12.22 4.1.0 新增手机端实时拼接模糊图像检测功能
2021.10.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 支持拍摄视频,端上抽帧,云端拼接

集成指南

库依赖

SDK依赖以下静态库/动态库,需正确集成至项目中并配置Framework Search Paths / Header Search Paths / Library Search Paths:

  • opencv2.framework:OpenCV V4.5.2,必须引入
  • libmontage_algo.a:手机端实时拼接功能库,可选引入,集成时请一并拷贝头文件目录montage_algo至项目合适路径
  • libEasyDL.a:模糊图像检测引擎库,可选引入,集成时请一并拷贝头文件目录EasyDL至项目合适路径
  • libpaddle_api_full_bundled.a:模糊图像检测引擎库,可选引入,集成时请一并拷贝头文件目录paddlelite至项目合适路径

libEasyDL.a 和 libpaddle_api_full_bundled.a 需同时引入才可支持模糊图像检测

集成摄像头相关逻辑

UI部分包括摄像头代码均开源,可参考以下文件,用户拷贝相关代码至项目中即可,并修改相应文件名以避免符号冲突:

  • easydl-stitch-ios/ViewController/ImagePickerViewController:云端拼接拍照逻辑,重合度算法开源
  • easydl-stitch-ios/ViewController/MBStitchCameraViewController:手机端实时拼接拍照逻辑,拼接等相关算法依赖 libmontage_algo.a
  • easydl-stitch-ios/ViewController/VideoStitchViewController#startUIImagePicker():云端拼接视频逻辑入口,参考该方法内对系统UIImagePickerController的使用

拍照拼接参数配置

// easydl-stitch-ios/EasyDLStitch/EasyDLStitchParams.h

#define kThreshold 75 // 判断重合的阈值,0~100之间
#define kStrategy "phash" // 重合算法,类型:["ahash","phash","dhash"]
#define kThetaZ 60 // 手机倾斜Z轴角度阈值
#define kThetaXY 20 // 手机倾斜XY轴角度阈值
#define kOverLapControl true // 是否与遮罩重合才可以拍照
#define kOrientationControl true // 是否手机持握方向符合要求才可以拍照
#define kSkipFrames 3 // 跳过视频帧比对的数量,比如3为每3帧比对一次
#define kBrightnessLow -3 // 光线强度阈值,-99~99之间
#define kBrightnessHigh 5 // 光线强度阈值,-99~99之间
#define kBrightnessControl false // 是否光线符合要求才可以拍照

参数说明:

  • 获取重合度有"ahash","phash","dhash"三种算法,返回0~100之间的数值,越大表示重合度越高。不同算法返回的数值有区别,需相应调整阈值
  • 手机倾斜XY轴指左右倾斜,Z轴是前后倾斜,当倾斜角度过大会影响拼接效果
  • 设置只有手机倾斜角度、待拍摄图片与上一张图片重合度、环境光线亮度等条件符合要求才拍摄图片,保证拍摄效果
  • 相机默认为每秒30帧,修改kSkipFrames的值调节做重合度对比的速度,避免卡顿或拍摄状态切换过快

视频拼接参数配置

体验APP中对视频截取帧的频率为1秒1帧,由于每个视频的帧数不能大于60,所以体验APP不能拼接长度大于60s的视频。开发者可根据实际情况调整截帧的频率,并相应限制视频长度。调整频率方法:

// easydl-stitch-ios/ViewController/StitchViewController.m

static int frameInterval = 1;//截帧间隔(秒)

并在合适的地方提示视频长度限制:

UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:@"选择对象(视频长度不能超过60s)" message:nil preferredStyle:UIAlertControllerStyleActionSheet];

SDK工程结构

EasyDL-Image-Stitching-iOS
|- LIB
    |- include
        |- montage_algo/ // 手机端实时拼接功能库头文件
        |- EasyDL/       // 手机端实时拼接模糊图像检测引擎头文件
        |- paddlelite/   // 手机端实时拼接模糊图像检测引擎头文件
    |- libs
        |- opencv2.framework 		        // OpenCV库
        |- libmontage_algo.a 		        // 手机端实时拼接功能库
        |- libEasyDL.a                  // 手机端实时拼接模糊图像检测引擎
        |- libpaddle_api_full_bundled.a // 手机端实时拼接模糊图像检测引擎
|- EasyDLStitch
    |- images/              // 资源文件
    |- easydl-stitch-ios/   // Demo工程文件
    |- RES/
        |- conf.json       // API配置文件
        |- fuzzy_model/    // 模糊图像检测模型

SDK调用流程

获取鉴权

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

1.png

  1. 如果还未创建应用,请点击「创建应用」按钮进行创建。创建应用后,参考鉴权参考文档,使用API Key(AK)和Secret Key(SK)获取access_token

下载SDK包后,填写ak、sk等信息。在RES/conf.json相应位置填入:

{
  "ak": "Mz0zhObvEZ6lnG1K3renXXXX", // API Key的值

  "sk": "188fRHYvLPmlPrNCDpBnkhL3ydXXXXX", // Secret Key的值

  "apiUrl": "https://aip.baidubce.com/rpc/2.0/ai_custom_retail/v1/detection/XXXX"  // 定制商品检测服务API
}

云端非实时拼接调用流程

  1. 创建任务:开始拼接整个流程
  2. 加货架图:上传图片
  3. 开始任务:启动货架拼接离线任务
  4. 查询任务:查询拼接任务的状态和结果

其他:

  1. 取消任务:取消正在进行或者等待的任务
  2. 任务列表:查询所有状态的任务列表
  3. 终止任务:终止正在进行或者等待的任务

调用API

云端拼接API的调用逻辑已封装在EasyDLStitchApiService文件中,以下为SDK调用货架拼接API的方法说明。货架拼接API接口的返回值及其他信息参见文档货架拼接API调用方法

创建拼接任务
- (void)createSpliceTaskWithConfig:(NSDictionary *)config successHandler:(SuccessBlock)successHandler failHandler:(FailureBlock)failHandler;

其中config为参数,后面两个回调block。参数取值及描述:

参数名称 是否必需 参数类型 描述 参数值限制
api_url string 商品检测服务的url
row_image_nums array[number] 各行待拼接货架图片的数量,array长度为货架图片的行数,array[i]为第i行的货架图片数量 行数不大于3,行内图片数量不大于60
detection_threshold float 商品检测服务的阈值 默认值为商品检测服务的阈值,取值范围[0,1]
nms_iou_threshold float 检测框矫准去重的阈值 默认值为0.45, 取值范围[0.2,0.8]
上传图片
- (void)uploadImageWithConfig:(NSDictionary *)config successHandler:(SuccessBlock)successHandler failHandler:(FailureBlock)failHandler;

其中config为参数,后面两个回调block。参数取值及描述:

参数名称 是否必需 参数类型 描述 参数值限制
task_id string 货架拼接任务id
row number 图片对应行的index 取值从0开始,需小于创建任务参数row_image_nums的长度
column number 图片在行内所在的index 取值从0开始,需小于创建任务参数row_image_nums[row]的取值
image string 上传图片的base64编码
启动拼接任务
-(void)startSpliceTaskWithConfig:(NSDictionary *)config successHandler:(SuccessBlock)successHandler failHandler:(FailureBlock)failHandler;

其中config为参数,后面两个回调block。参数取值及描述:

参数名称 是否必需 参数类型 描述 参数值限制
task_id string 货架拼接任务id
查询任务状态
-(void)queryTaskResultWithConfig:(NSDictionary *)config successHandler:(SuccessBlock)successHandler failHandler:(FailureBlock)failHandler;

其中config为参数,后面两个回调block。参数取值及描述:

参数名称 是否必需 参数类型 描述 参数值限制
task_id string 货架拼接任务id
查询任务列表
-(void)listTaskWithConfig:(NSDictionary *)config successHandler:(SuccessBlock)successHandler failHandler:(FailureBlock)failHandler;

其中config为参数,后面两个回调block。参数取值及描述:

参数名称 是否必需 参数类型 描述 参数值限制
task_ids array[string] 只返回指定id的任务信息
begin_time number 只返回begin_time以后创建的任务信息 时间戳
end_time number 只返回end_time之前创建的任务信息 时间戳
终止任务
-(void)terminateTaskWithConfig:(NSDictionary *)config successHandler:(SuccessBlock)successHandler failHandler:(FailureBlock)failHandler;

其中config为参数,后面两个回调block。参数取值及描述:

参数名称 是否必需 参数类型 描述 参数值限制
task_id string 货架拼接任务id

手机端实时拼接调用流程

  1. 准备目录
  2. 对比图片:新图片(now)在参与实时拼接前需先与上一张参与拼接的图片(last)进行对比,如果now与last的对比特征合法则可以成功拼接,否则无法得到理想实时拼接结果
  3. 实时拼接:SDK会寻找now.jpg并进行实时拼接得到新拼接结果
  4. 上传云端,得到结果

其他:

  1. 撤销拼接:撤销最后一次拼接结果

SDK的调用

手机端实时拼接的调用逻辑已封装在EasyDLMBStitchApiService文件中,包括商品检测API以及拼接算法的调用,以下为SDK调用的方法说明。

准备目录

实时拼接过程中产生的文件需保存在本地,首先初始化准备保存的目录。单个拼接任务的保存目录不可发生变化。

- (void)prepare;

// 调用示例
[[EasyDLMBStitchApiService sharedService] prepare];
对比图片
- (void)compareImage:(UIImage *)image firstFrame:(BOOL)isFirstFrame completionHandler:(CompletionHandler)completionHandler;

// 调用示例
[[EasyDLMBStitchApiService sharedService] compareImage:image firstFrame:_firstFrameCompare completionHandler:^(id responseObject, NSError *error) {
    if (error) {
        NSLog(@"%@", error.localizedDescription);
    } else {
      	// 回调结果
        CompareResult *compareResult = responseObject;
      	// do something
    }
}];

参数说明:

  • image:当前要参与对比的图片
  • isFirstFrame:是否是第一帧

    • 第一帧的定义取决于上一张参与拼接的图片(last)是否已经被对比过。假设有图片A和B,先用A与last对比,且last是初次被对比,此时isFirstFrame应为true,再用B与last对比,此时isFirstFrame应为false
  • completionHandler:异步回调,在主线程
CompareResult
// montage_algo/EasyDLStitchAlgo.h

// 当前图片相对上一张参与拼接的图片的方位
@property(nonatomic) ImageDirection direction;
/**
 * 是否需要判断方向,如当拍摄完图片过近时,direction可能由于两图过于相似而不可靠,这种情况不需要判断方向,即该值=false
 * 一般direction不可靠时,该值=false
 * 对比的两张图是第一次对比时,该值=false
 * 当该值=true时,请在调用实时拼接API前确认方法是否合法,否则可能导致拼接失败
 */
@property(nonatomic, getter = needCheckDirection) BOOL checkDirection;
// 对比结果中的方位是否合法,非法的方位将无法完成拼接
@property(nonatomic) BOOL directionValid;
// 两张图片重叠部分的点位
@property(nonatomic, retain) NSArray<NSValue *> *points;
// 两张图片重叠状态
@property(nonatomic) OverlapStatus overlapStatus;
// 最后一次参与拼接的图片序号,从1开始
@property(nonatomic) int lastImgIndex;
对比结果的合法性判断参考
switch (compareResult.overlapStatus) {
    case OverlapStatus_Correct:
        if (compareResult.needCheckDirection && !compareResult.directionValid) {
            // 非法,当前参与对比的图片方位不正确,无法拼接
        } else {
            // 合法
        }
        break;
    case OverlapStatus_TooFar:
        // 非法,两张图重叠度过低
        break;
    case OverlapStatus_TooClose:
        // 非法,两张图重叠度过高
        break;
}
实时拼接
  • 建议调用拼接前参考【对比结果的合法性判断】,用不合法的对比结果进行实时拼接将无法获得正确输出
  • 将要参与拼接的图片必须命名为“now.jpg”(也可使用EasyDLMBStitchApiService.FILENAME_IMAGE_NOW),并保存在[EasyDLMBStitchApiService sharedService].currentTask.workDir指向的目录下,否则实时拼接无法正常工作。成功拼接后"now.jpg"会被SDK重新命名为{index}.jpg,其中{index}代表图片序号。
  • 为获得更快的拼接效率,建议减小参与拼接的图片尺寸;为了保证拼接效果,缩放后的图片尺寸应不小于宽648和高864
- (void)stitchImageWithCompareResult:(CompareResult *)compareResult completionHandler:(CompletionHandler)completionHandler;

// 调用示例
[[EasyDLMBStitchApiService sharedService] stitchImageWithCompareResult:_latestCompareResult completionHandler:^(id responseObject, NSError *error) {
    if (error) {
        NSLog(@"%@", error.localizedDescription);
    } else {
      	// 回调结果
        StitchResult *stitchResult = responseObject;
      	// do something
    }
}];

// 保存now.jpg示例
NSURL *workDirUrl = [EasyDLMBStitchApiService sharedService].currentTask.workDir;
/* 小图为拼接,大图为获得更好的商品检测效果 */
[EasyDLFileManager saveImage:image toUrl:[workDirUrl URLByAppendingPathComponent:FILENAME_IMAGE_NOW] andResizeTo:CGSizeMake(648, 864)];
// SDK默认使用保存的一系列`{index}.jpg`调用商品检测API并取得结果。
// 由于建议减小该系列图片尺寸以获得更优的拼接效率,但同时更小尺寸的图片对商品检测精度有一定影响,因此为提高精度,建议同时保存最佳尺寸的图片用于上传云端。
[EasyDLFileManager saveImageForBestInfer:image toUrl:[workDirUrl URLByAppendingPathComponent:[NSString stringWithFormat:@"%@/%@", DIR_NAME_FULL_IMAGE, FILENAME_IMAGE_NOW]]];

参数说明:

  • compareResult:对比图片回调返回的结果
  • completionHandler:异步回调,在主线程。该回调在拼接任务全部完成后到达,如需更快获取缩略图和完整拼接图,可配置EasyDLMBAPIStitchDelegate协议
StitchResult
// montage_algo/EasyDLStitchAlgo.h

// 拼接错误码,0表示成功,其他为错误
@property(nonatomic) int errCode;
// 最近一张参与拼接的图片的序号
@property(nonatomic) int latestImgIndex;
// 缩略拼接图路径
@property(nonatomic, retain) NSURL *thumbnailUrl;
// 完整拼接图路径
@property(nonatomic, retain) NSURL *fullImageUrl;
EasyDLMBAPIStitchDelegate
// easydl-montage-ios/EasyDLStitch/EasyDLMBStitchApiService.h

@protocol EasyDLMBAPIStitchDelegate <NSObject>
- (void)onStitchThumbnailGenerated:(NSURL *)thumbnailURL;
- (void)onStitchFullImageGenerated:(NSURL *)fullImageURL;
@end
  
// 配置示例
[EasyDLMBStitchApiService sharedService].stitchDelegate = self;
上传云端,得到结果
- (void)mergeDetectedResultsWithCompletionHandler:(CompletionHandler)completionHandler;

// 调用示例
[[EasyDLMBStitchApiService sharedService] mergeDetectedResultsWithCompletionHandler:^(id responseObject, NSError *error) {
    if (error) {
        NSLog(@"%@", error.localizedDescription);
    } else {
      	// 回调结果
        MergeResult *mergeResult = responseObject;
      	// do something
    }
}];

参数说明:

  • completionHandler:异步回调,在主线程。该回调在检测任务全部完成后到达,如需感知检测任务的开始和进度更新,可配置EasyDLMBAPIMergeDelegate协议
MergeResult
// montage_algo/EasyDLStitchAlgo.h

// 错误码,0表示成功,其他为错误
@property(nonatomic) int errCode;
// 商品检测并去重合并后的结果
@property(nonatomic, retain) NSDictionary *correctSKUDict;
EasyDLMBAPIMergeDelegate
// easydl-montage-ios/EasyDLStitch/EasyDLMBStitchApiService.h

@protocol EasyDLMBAPIMergeDelegate <NSObject>
- (void)onMergeResultsStarted:(int)totalImageCount;
- (void)onMergeProgressUpdated:(int)totalImageCount completedCount:(int)completedCount;
@end
  
// 配置示例
[EasyDLMBStitchApiService sharedService].mergeDelegate = self;
撤销拼接

SDK支持撤销最后一次拼接结果,如需撤销多张,请多次操作

- (void)undoLastTakenImageWithCompletionHandler:(CompletionHandler)completionHandler;

// 调用示例
[[EasyDLMBStitchApiService sharedService] undoLastTakenImageWithCompletionHandler:^(id responseObject, NSError *error) {
    if (error) {
        NSLog(@"%@", error.localizedDescription);
    } else {
      	// 回调结果,包含撤销后,当前最后一次参与拼接的图片信息
        ImageInfo *lastImageInfo = responseObject;
      	// do something
    }
}];

参数说明:

  • completionHandler:异步回调,在主线程
ImageInfo
// easydl-montage-ios/EasyDLStitch/EasyDLMBStitchApiService.h

// 图片序号
@property(nonatomic) int index;
// 图片列坐标
@property(nonatomic) int x;
// 图片行坐标
@property(nonatomic) int y;

模糊图像检测

手机端实时拼接已接入AI模型以支持模糊图像检测,除参考库依赖正确引入依赖库,需保证 RES/fuzzy_model 目录下的模型文件存在。调用示例如下,也可参考 EasyDL-Stitch/easydl-stitch-ios/ViewController/MBStitchCameraViewController.m 文件中对 FuzzyModelProxy 的使用:

// 模型初始化
- (NSError *)modelInit;
// 推理图像判断是否模糊
- (void)inferImage:(UIImage *)image completionHandler:(void (^)(BOOL fuzzy, NSError *error))completionHandler;

// 调用示例
FuzzyModelProxy *fuzzyModelProxy = [[FuzzyModelProxy alloc] init];
[fuzzyModelProxy modelInit];
if (fuzzyModelProxy && fuzzyModelProxy.engineActive) {
    [fuzzyModelProxy inferImage:image completionHandler:^(BOOL fuzzy, NSError *error) {
        if (!error && !fuzzy) {
            // 图像非模糊
        } else {
            // 图像模糊或推理失败
        }
    }];
}

阈值设置

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

  • 最小IOU置信度
  • 最大IOU置信度
  • NMS置信度
  • 商品检测API最大重试次数
// easydl-montage-ios/EasyDLStitch/EasyDLMBStitchApiService.h

/**
 * 最小拼接引导置信度
 */
@property(nonatomic) CGFloat minIOUThreshold;
/**
 * 最大拼接引导置信度
 */
@property(nonatomic) CGFloat maxIOUThreshold;
/**
 * 去重置信度
 */
@property(nonatomic) CGFloat nmsIOUThreshold;
/**
 * 商品检测API重试次数
 */
@property(nonatomic) int detectRetryTimes;
/**
 * 商品检测API最大并发数
 */
@property(nonatomic) int maxQPS;

门脸文字识别调用流程

  1. 初始化门店定位
  2. 门脸图片上传云端

SDK 调用

门脸文字识别流程通过 EasyDLDoorAPIService 调用,具体使用和返回参数见下

初始化门店定位

[[EasyDLDoorAPIService sharedService] startLocation];

门脸图片上传云端,获取门店检测结果

// easydl-montage-ios/EasyDLDoor/EasyDLDoorAPIService.h

// 开始门脸文字识别
[[EasyDLDoorAPIService sharedService] detectDoorImage:image];
// 获取门脸识别结果
[EasyDLDoorAPIService sharedService].blockNSDictionary = ^(NSDictionary * _Nonnull blockNSDictionary, NSError * _Nonnull error) {
    if(blockNSDictionary != nil && error == nil) {
      // 门脸图片识别成功
      ..............
      // 校验门店结果
      [EasyDLStitchAlgo checkDoorData:documentsDirectory ocrInfo:ocrJson];
    }
}

模糊图像检测

门脸文字识别已接入AI模型以支持模糊图像检测,除参考库依赖正确引入依赖库,需保证 RES/fuzzy_model 目录下的模型文件存在。 调用示例可参考【手机端实时拼接调用流程-模糊图像检测】,也可参考【门脸文字识别调用流程】 EasyDL-Stitch/easydl-stitch-ios/ViewController/DoorCameraViewController.mm 文件中对 FuzzyModelProxy 的使用。

防止图片窜拍开关参数设置

// easydl-montage-ios/EasyDLDoor/CheckImageConfig.h

- (BOOL)getPirateImageCheck;

// 调用示例
/**
 * 窜拍开关默认开启
 */
[CheckImageConfig sharedService].pirateImageCheck = true;
// 获取开关状态
[[CheckImageConfig sharedService] getPirateImageCheck];

错误码

以下为SDK使用的错误码,API接口错误码参见货架拼接API错误码

错误码 说明
200002 模型配置错误,请检查传入的配置文件是否有效
100006 API,AK/SK 换取token失败
100007 API,请求 API 失败
100008 API,请求商品检测API失败
200001 手机端实时拼接 - 前端引导对比图像出错
200003 手机端实时拼接 - 撤销上一次拼接结果出错
200004 手机端实时拼接 - 商品检测+去重过程中出错
200005 手机端实时拼接 - 拼接出错
300001 手机端实时拼接 - 模糊图像检测出错
上一篇
SDK介绍
下一篇
Android_SDK