淘宝拍立淘多码识别方案总结

25add6738c37fd884dc96c8c47d102e5.gif

本文通过拆解原始问题、发散思路优化等方式,记录了扫一扫从单码到多码识别的技术框架改造及多码识别率优化方案。其中涉及解码SDK的能力、码处理技术链路、码转换算法、降低漏检率策略等设计与实现。

d1e0e352614cc51cbf58eef22ada8351.png

背景与挑战

多码即在同一个界面中同时存在多个条码或二维码, 其在现实场景中广泛存在,如服饰吊牌、饮料瓶身、快递单等。然而对于拍立淘的扫一扫场景来说,最初只支持单码能力,用户对于在多码场景识别到的是哪个码毫无感知,影响体验。基于上述现状,在淘宝现有的条件下,是否具备改造成识别多码的能力;进一步地,是否能够进行码位置的锚定,并将该能力同时应用于单码场景。

935f32101796c8cf13231565b551b183.png

多码实现

要实现单码到多码的转变,需要从逻辑层、视图层进行重新设计。下面分别阐述。

  逻辑层:单码识别到多码识别

我们通过对逻辑层梳理,把对单码的处理全部改为对码数组的依次处理。扫一扫解码层需要处理的内容如下,改动是由单数据处理切换为批量处理。在第五步中,因为在展示层后续需要有多码场景的展示,因此这里特地缓存了一帧当前帧。

3c70fc04e09328ad6b20ac47fd48ccbd.png

  展示层:单码展示到多码展示

当识别到多码之后,需要让用户保持所见即所得:即覆盖缓存帧在镜头页上,通过箭头锚定码框的中心点。等待用户的操作后再进行进一步的响应。考虑到要展示当前帧的实现方式有下述两种方案:

方案一、将相机会话数据输入停止,则屏幕不会刷新新的帧数据,停留在当前帧,镜头页盖蒙层展示锚点。

方案二、将当前帧缓存图添加在镜头页上,镜头页盖蒙层展示锚点。

两种方案各有利弊。方案一不额外消耗内存,但需要控制相机会话的开启和停止,在重新启动相机时状态切换导致画面有明显切换痕迹。方案二不影响相机启停,但帧缓存图需要额外消耗的内存。解法是通过对分辨率控制来实现对内存的控制,并在用户操作后及时回收内存。

改造后的层级如下所示。同时为了严格枚举不同状态(正常、单码、多码)的流转,使用了状态机模式。

- 镜头页容器
  - 扫一扫镜头页
    - 当前帧缓存图(新增)
    - 多码场景页(新增)
      - 蒙层(新增)
      - 导航栏(新增)
      - 码框(新增)
      - 提示文本框(新增)

扫一扫业务实现层需要处理的内容如下,蓝色部分为改动点。

a0138d1ce88ceaac31fe3952b5363f78.png

  二维码码框转换算法

实现多码视觉展示的一个重要内容,是要在条码/二维码的中心展示箭头。这里涉及到解码SDK返回的原始数据映射到设备屏幕的码框的计算。对于二维码,整体三步走文字描述及伪代码如下,主要包含三步处理:

第一步、原图(即相机输入帧) 0° → 顺时针90°。原图为横屏的图,需要将原始rect顺时针旋转90°

第二步、将旋转后的图,缩放到和设备屏幕同一个尺寸

第三步、将码框坐标变换:原图坐标点 → 屏幕坐标点

码框旋转rect = CGRect(x: 原图宽 - (原码框.y + 原码框.height), 
                    y: 原码框.x, 
                width: 原码框.height, 
               height: 原码框.width);






BOOL 是否长屏幕 = 图片宽/图片高 > 屏幕宽/屏幕高 ? YES : NO;
缩放比例 = 是否长屏幕 ? 屏幕高/图片高 : 屏幕宽/相机宽;
码框缩放rect = CGRect(x: 图片旋转rect.x * scale, 
                     y: 图片旋转rect.y * scale, 
                 width: 图片旋转rect.width * scale, 
                height: 图片旋转rect.height * scale);


码框坐标变换rect = null;
if(长屏幕) {
    CGFloat xOffset = (图片宽*scale - 屏幕宽)/2.0;
    码框坐标变换rect = CGRectMake(x:码框缩放rect.x-xOffset, 
                                y:码框缩放rect.y,     
                            width:码框缩放rect.width, 
                           height:码框缩放rect.height);
}else {
    CGFloat yOffset = (图片高*scale - 屏幕高)/2.0;
    码框坐标变换rect = CGRectMake(x:码框缩放rect.x, 
                                y:码框缩放rect.y-yOffset,     
                            width:码框缩放rect.width, 
                           height:码框缩放rect.height);
}


return 码框坐标变换rect;

整体三步走图示:

96be8ad2aa5464458b1a9adfa955fa7d.png

59e348cfdd3ba790f8b1b5dc25636c09.png

降低漏检率

在上述章节中,直观地看起来,要支持多码识别只要将解码SDK切换并开发上层链路就解决了,但是现实中情况并不如此。

单帧数据的解码成功率会受到很多因素的影响,比如当前帧的模糊程度、传输给解码SDK的帧图像压缩比例、解码算法等等。在完成完成上述内容后,我们发现在多码识别的场景中,多码解码漏检率是比较高的。但是核心解码SDK的改动是比较难的。因此这时候我们考虑从别的角度入手来解决问题。

  Vision解码

基于iOS13以上的Vision解码能力,我们能够进行大多是码类型的解码。同时,在多数场景中,Vision能够解码SDK的漏检问题进行补充,下图为帧数据增加Vision解码的链路:

cd78b6232f44b605bb38f1f519055886.png

使用Visioin方案设计的核心关键点如下:

  • 图像串行解码

通过测算,扫一扫中解码SDK 和 Vision 解码耗时均在 50-100ms 左右,采用串行的解码能够满足业务要求。因此,在不阻塞单帧处理的情况下,使用 Vision 可以提高准确度。

5ae996071e050d4e99542ab018064201.png

从结果(VNRequest.results)当中,我们核心要获取的原始数据包括(和现有解码SDK对齐的数据,即最终数据格式要能够统一):

  1. 码类型(symbology.rawValue)

  2. 码内容(payloadStringValue)

  3. 置信度(confidence)

  4. 原始码框(boundingBox)

  • 置信度检测

增加置信度检测,是为了保证用户取得的码框是符合预期的。通过参数调优,我们设定了 0.9 作为可接受的置信度(confidence)最小值。


  • 数据去重

在条形码的解码场景中,因为码竖条长度的不确定性以及底层算法的实现不同。存在一个条形码出现多个返回结果的情况,这些返回结果的中心点沿着条形码的中轴线纵向分布。基于用户的意图和常规操作场景,我们把位置重合且同样的码内容(payloadStringValue),只去重展示一个数据。去重策略上,选择置信度(confidence)最高的数据。


  • 模型映射

进行码展示和码处理都是使用解码SDK原有的模型(Model),我们需要把 Vision 输出的结果进行转换。最重要的是将码类型(symbology.rawValue)转化成扫一扫需要的码类型和码子类型。

  数据融合

有了Vision的数据之后,我们后续需要对解码数据做融合。融合的意思就是去重后合并,这就要求不同解码方式输出的解码结果是能够比较的。有了模型映射这个步骤,融合就比较简单了:我们把位置重合且同样的码内容,只去重展示一个数据。去重策略上,选择置信度(confidence)最高的数据。

cba691c409ede84ca11bb611ee4d6459.png

  端智能

有了Vision的帮助,我们能够对解码SDK解不出来的码做一次融合。但有没有办法提高解码SDK的成功率?前面说到,对于原图的压缩、码过小等场景都会影响解码SDK的解码率。那么有没有办法预先识别出当前图片的码框范围并抠图解码?

通过拍立淘的端智能架构,我们增加了码检测算法。码检测能力的提供,让我们不再是“摸黑”地进行解码了。而是有目的、有预期的进行解码。当码检测模型检测到当前帧具备一个或多个码,同时能够返回码框的位置。针对这个码框的位置,我们就能够进行抠图解码,能够增加解码SDK的解码成功率。

cb8d1227f10ab3d167de0eb7dae441e7.png

fda2b292ae263627717b454cb3d99cdb.jpeg

效果展示

左图为相册链路的多码识别,右图为镜头链路的多码识别。通过应用降低漏检率的策略,我们在多码场景上的识别率有非常显著提升。

4c595f73826dc26ef5dba35a5f143e01.png

bf0470e838bd8bbd732bfec7fd01fc56.jpeg

总结和展望

本篇是从真实场景入手,在优化用户体验的维度发现问题,并尝试解决问题。但解决了问题(完成了多码实现)并不代表完成,因为始终能够有提升的空间(降低漏检率,提高解码率)。可以说,解决问题只是一个新的开始,是一个可以展开更广泛想象力,使用更广泛工具去不断优化的开始。

扫一扫作为手淘主要解码能力的载体,对扫码能力相关的优化是永无止境的。除了解码SDK本身对算法的不断升级之外,借助iOS系统和端智能技术,也能够对解码成功率起到正向的促进作用。扫一扫在经过多次迭代后,相册解码成功率提升了30pt+。同时,全屏识别、多码识别、药品码物流码的识别能力,也都是我们的优势所在。后续我们将会不断优化扫码解码的用户体验,缩短码识别时间,提高码识别场景的图片稳定性,做到

c1fdaa4790062953e83d6ecf8d95b61e.jpeg

团队介绍

我们是大淘宝技术搜索终端团队,负责手机淘宝搜索,拍立淘等核心业务的研发和技术创新,同时打造了端侧的搜索终端通用框架,提供搜索领域端到端解决方案,以平台化能力支撑了手机淘宝等多个集团电商和本地生活业务,同时我们和算法技术紧密结合,将端智能和边缘计算充分应用于我们的文本和图像搜索业务,我们研发的产品为亿级消费者提供服务,期待您的加入。
感兴趣的同学可将简历发送到 taozi.ly@taobao.com

¤ 拓展阅读 ¤

3DXR技术 | 终端技术 | 音视频技术

服务端技术 | 技术质量 | 数据算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/18647.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Node.js 与 WebAssembly

目录 1、简介 2、关键概念 3、生成WebAssembly模块 4、如何使用它 5、与操作系统交互 1、简介 首先,让我们了解为什么WebAssembly是一个很棒的工具,并学会自己使用它。 WebAssembly是一种类似汇编的高性能语言,可以从各种语言编译&…

从零开始的强化学习入门学习路线

强化学习是机器学习领域中的一个分支,它是指智能体通过与环境的交互来学习如何采取最佳行动以最大化奖励信号的过程。强化学习在许多领域都有广泛的应用,如游戏、自动驾驶和机器人控制等。如果你对强化学习感兴趣,下面是一个入门强化学习的学…

【分布式锁】Redisson分布式锁的使用(推荐使用)

文章目录 前言一、常见分布式锁方案对比二、分布式锁需满足四个条件三、什么是Redisson?官网和官方文档Redisson使用 四、Redisson 分布式重入锁用法Redisson 支持单点模式、主从模式、哨兵模式、集群模式自己先思考下,如果要手写一个分布式锁组件,怎么做&#xff…

数据备份系列:Rsync 备份实战记录(二)

一、Rsync Cron 场景使用 在对数据备份要求实时性不高的情况下,可优先考虑该场景,选择一个合适的时间,对数据进行定时远程增量同步。 在《数据备份系列:Rsync 备份详解(一)》中我们已经对服务搭建以及远程…

鸿蒙学习总结

控件 button 源码所在路径,小编也只是猜测,还没搞懂鸿蒙上层app到底层的玩法,网上也没相关资料,找源码真是费劲(不是简单的下载个源码的压缩包,而是找到里面的控件比如Button,或者UIAbility实现的源码&…

基于python语言dlib库和opencv库的视频眨眼检测

功能说明: 基于python编程语言,使用dlib 和opencv开发的视频眨眼检测。 环境: * python 3.6.8 * opencv 3.4.2.16 * dlib 19.7.0 原理: 1.使用opencv-python读取处理视频图像 2.使用线程机制处理人脸检测关键点 3.根…

elk生命周期删除日志

elk版本:7.14 一、简介 ELK日志我们一般都是按天存储,例如索引名为"prodlog-2023-05-08",因为日志量所占的存储是非常大的,我们不能一直保存,而是要定期清理旧的,这里就以保留7天日志为例。 自…

UDP通信机制详解

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和…

opencv_c++学习(五)

Mat类数值存储方式 上图为opencv中三通道数据的存储方式,反映到图像上则为空间维度为3*3,通道为3的图像。 Mat类的属性 Mat类的属性如上,在这里我们解释一下step。step是行列数与数据类型的字节数相乘的数据。 Mat类元素读取 在Mat中&…

[GFCTF 2021] day2

Baby_Web 查看源码发现 <!--源码藏在上层目录xxx.php.txt里面&#xff0c;但你怎么才能看到它呢?--> 然后抓包看中间件&#xff0c;Apache/2.4.49 (Unix) 存在目录穿越漏洞 curl http://node4.anna.nssctf.cn:28805/cgi-bin/.%2e/.%2e/.%2e/.%2e/var/www/index …

Linux LED 驱动开发实验

1、LED 灯驱动原理 Linux 下的任何外设驱动&#xff0c;最终都是要配置相应的硬件寄存器。LED 灯驱动最 终也是对 I.MX6ULL 的 IO 口进行配置&#xff0c;在 Linux 下编写驱动要符合 Linux 的驱动框架。I.MX6U-ALPHA 开发板上的 LED 连接到 I.MX6ULL 的 GPIO1_IO03 这个引脚上&…

一起Talk Android吧(第五百四十二回:无进度值ProgressBar)

文章目录 概念介绍使用资源文件实现使用默认设置修改风格使用动画资源 使用代码实现经验总结 各位看官们大家好&#xff0c;上一回中咱们说的例子是"ProgressBar总结",本章回中介绍的例子是" 无进度值ProgressBar"。闲话休提&#xff0c;言归正转&#xf…

基于磁盘的Kafka为什么这么快

基于磁盘的Kafka为什么这么快 原创 Wyman 大数据技术架构 2019-05-23 18:04 Kafka是大数据领域无处不在的消息中间件&#xff0c;目前广泛使用在企业内部的实时数据管道&#xff0c;并帮助企业构建自己的流计算应用程序。Kafka虽然是基于磁盘做的数据存储&#xff0c;但却具有…

从FPGA说起的深度学习(九)- 优化最终章

这是新的系列教程&#xff0c;在本教程中&#xff0c;我们将介绍使用 FPGA 实现深度学习的技术&#xff0c;深度学习是近年来人工智能领域的热门话题。 在本教程中&#xff0c;旨在加深对深度学习和 FPGA 的理解。 用 C/C 编写深度学习推理代码高级综合 (HLS) 将 C/C 代码转换为…

CTFHub-Git泄露-Log

前言 git是一个版本控制工具&#xff0c;通过泄露的.git文件可还原代码 题目如下 wp 1. dirsearch目录扫描 发现存在git泄露&#xff0c;根据提示下载对应git利用工具GitHack&#xff0c;这个工具的特点是能还原历史版本 2. 使用工具下载源码 tips: 最好在linux中操作&…

RabbitMQ、RabbitMQ发布/订阅模式

1.RabbiMQ RabbitMQ是一个消息中间件 MQ的基本结构 1.1RabitMQ安装 参考&#xff1a;Docker安装 Docker中部署RabbitMQ 2.入门案例 2.1.publisher实现 package cn.itcast.mq.helloworld;import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; im…

算法记录 | Day53 动态规划

1143.最长公共子序列 思路&#xff1a; 本题和动态规划&#xff1a;718. 最长重复子数组 (opens new window)区别在于这里不要求是连续的了&#xff0c;但要有相对顺序&#xff0c;即&#xff1a;“ace” 是 “abcde” 的子序列&#xff0c;但 “aec” 不是 “abcde” 的子序…

力扣sql中等篇练习(十六)

力扣sql中等篇练习(十六) 1 不同性别每日分数统计 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 a 示例输入 b 示例输出 1.2 示例sql语句 # 分数是往后累加的 SELECT s2.gender,s2.day,sum(s1.score_points) total FROM Scores s1 CROSS JOIN Scores s2 ON s2.gen…

细谈抽象类

目录 抽象类 1.抽象类是被abstract修饰的类 2.抽象类中的抽象方法 3.抽象类中可以有和普通类一样的成员变量和成员方法 4.抽象类不能被实例化 5.那么抽象类不能被实例化要它有何用&#xff1f;&#xff1f;&#xff1f; 6.注意&#xff1a; 抽象类 如果一个类中没有包含足…

Web3.0介绍与产业赛道(去中心化,金融与数字资产,应用与存储,区块链技术)

文章目录 1、web3.0时代——区块链技术2、产业赛道&#xff1a;去中心化金融与数字资产3、产业赛道&#xff1a;去中心化应用与存储4、区块链&#xff1a;基础设施与区块链安全和隐私 1、web3.0时代——区块链技术 Web3.0是什么 Web3.0是指下一代互联网技术&#xff0c;它将在…