热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

二维码(QRCode)的生成原理及解析

转载自:琦小虾https:blog.csdn.netajianyingxiaoqinghanarticledetails78837864#comments二维码生成原

转载自:琦小虾
https://blog.csdn.net/ajianyingxiaoqinghan/article/details/78837864#comments
二维码生成原理及解析代码

自从大街小巷的小商小贩都开始布满了腾讯爸爸和阿里爸爸的二维码之后,我才感觉到我大天朝共享支付的优越性。最近毕业论文写的差不多了,在入职之前多学一些东西也是好的。这里秉着好奇心,研究一下二维码的生成,并尝试性写一个二维码解析源码。

注:暂时只有二维码原理,笔者这段时间会持续研究解析代码,并随进度持续更新。

参考网址:
《二维码的生成细节和原理》
《QR Code Tutorial》
《Hello World!》—— 知乎专栏文章
《为程序员写的Reed-Solomon码解释》


一. 二维码基本知识

二维码另一个名称是QR Code(Quick Response Code),近年来在移动设备上经常使用,与传统条形码相比,可以存储更多的信息。二维码本质上是个密码算法,基本知识总结如下。
首先,二维码存在 40 种尺寸,在官方文档中,尺寸又被命名为 Version。尺寸与 Version 存在线性关系:Version 1 是 21×21 的矩阵,Version 2 是 25×25 的矩阵,每增加一个 Version,尺寸都会增加 4,故尺寸 Size 与 Version 的线性关系为:




Size=(Version1)×4Size=(Version−1)×4

Version 的最大值是 40,故尺寸最大值是(40-1)*4+21 = 177,即 177 x 177 的矩阵。

二维码结构如下图 1.1 所示:




图6.7 时序图案例程 2




这里写图片描述


6.4 格式信息

格式信息如下图 6.8 所示:




图6.8 格式信息

格式信息在定位图案周围分布,由于定位图案个数固定为 3 个,且大小固定,故格式信息也是一个固定 15bits 的信息。每个 bit 的位置如下图 6.9 所示:(注:图中的 Dark Module 是固定永远出现的)




图6.9 格式信息位置

15bits 中数据,按照 5bits 的数据位 + 10bits 纠错位的顺序排列:


  • 数据位占 5bits:其中 2bits 用于表示使用的纠错等级 (Error Correction Level),3bits 用于表示使用的蒙版 (Mask) 类别;
  • 纠错位占 10bits:主要通过 BCH Code 计算;

为了减少扫描后图像识别的困难,最后还需要将 15bits 与 101010000010010 做异或 XOR 操作。因为我们在原格式信息中可能存在太多的 0 值(如纠错级别为 00,蒙版 Mask 为 000),使得格式信息全部为白色,这将增加分析图像的困难。

纠错等级的编码如下图 6.10 的表格所示:




图6.10 纠错等级编码

关于蒙版图案的生成,在后文 6.7 中具体说明。格式信息的示例如下:

假设存在纠错等级为 M(对应 00),蒙版图案对应 000,5bits 的数据位为 00101,10bits 的纠错位为 0011011100:
则生成了在异或操作之前的 bits 序列为:001010011011100
101010000010010 做异或 XOR 操作,即得到最终格式信息:100000011001110


6.5 版本信息 (Version Information)

对于 Version 7 及其以上的二维码,需要加入版本信息。如下图 6.11 蓝色部分所示:




图6.11 版本信息

版本信息依附在定位图案周围,故大小固定为 18bits。水平竖直方向的填充方式如下图 6.12 所示:




图6.12 版本信息填充方式

18bits 的版本信息中,前 6bits 为版本号 (Version Number),后 12bits 为纠错码 (BCH Bits)。示例如下:

假设存在一个 Version 为 7 的二维码(对应 6bits 版本号为 000111),其纠错码为 110010010100;
则版本信息图案中的应填充的数据为:000111110010010100


6.6 数据码与纠错码

此后即可填充第五章得到的数据内容了。填充的思想如下图 6.13 的 Version 3 二维码所示,从二维码的右下角开始,沿着红线进行填充,遇到非数据区域,则绕开或跳过。




图6.13 二维码数据填充(原始版)

然而这样难以理解,我们可以将其分为许多小模块,然后将许多小模块串连在一起,如下图 6.14 所示(截取自 QR Code Spec 的图 15):




图6.14 二维码数据填充

小模块可以分为常规模块和非常规模块,每个模块的容量都为 8。常规情况下,小模块都为宽度为 2 的竖直小矩阵,按照方向将 8bits 的码字填充在内。非常规情况下,模块会产生变形。
填充方式上图 6.14,图中深色区域(如 D1 区域)填充数据码,白色区域(如 E15 区域)填充纠错码。遍历顺序依旧从最右下角的 D1 区域开始,按照蛇形方向(D1→D2→…→D28→E1→E2→…→E16→剩余码)进行小模块的填充,并从右向左交替着上下移动。下面给出若干填充原则:

原则 1:无论数据的填充方向是向上还是向下,常规模块(即 8bits 数据全在两列内)的排列顺序应是从右向左,如下图 6.15所示;




图6.15 常规模块内的填充方向

原则 2:每个码字的最高有效位(即第7个bit)应置于第一个可用位。对于向上填充的方向,最高有效位应该占据模块的右下角;向下填充的方向,最高有效位占据模块的右上方。
注:对于某些模块(以下图 6.17 为例),如果前一个模块在右边模块的列内部结束,则该模块成为不规则模块,且与常规模块相比,原本填充方向向上时,最高位应该在右上角,此时则变为左下角;
原则 3:当一个模块的两列同时遇到对齐图案或时序图案的水平边界时,它将继续在图案的上方或下方延续;
原则 4:当模块到达区域的上下边界(包括二维码的上下边界、格式信息、版本信息或分隔符)时,码字中任何剩余 bits 将填充在左边的下一列中,且填充方向反转;如下图 6.16 中的两个模块遇到了二维码的上边界,则方向发生变化;




图6.16 非常规模块填充方向的改变(举例于 QR Code Spec 图 13)

原则 5:当模块的右一列遇到对齐图案,或遇到被版本信息占据的区域时,数据位会沿着对齐图案或版本信息旁边的一列继续填充,并形成一个不规则模块。如果当前模块填充结束之前,下一个的两列都可用,则下一个码字的最高有效位应该放在单列中,如下图 6.17 所示:




图6.17 模块单列填充


6.7 蒙版图案

按照上述思路即可将二维码填充完毕。但是那些点并不均衡,如果出现了大面积的空白或黑块,扫描识别会十分困难,所以按照在前文 6.4 中格式信息的处理思路,对整个图像与蒙版进行蒙版操作(Masking),蒙版操作即为异或 XOR 操作。
二维码又 8 种蒙版可以使用,如下图 6.18 所示,公式也在图中说明。蒙版只会和数据区进行异或操作,不会影响与格式信息相关的功能区。
注:选择一个合适的蒙版也是有一定算法的。

蒙版图案如下图 6.18 所示,对应的产生公式与蒙版 ID 如下图 6.19 的表格所示:




图6.18 蒙版图案




图6.19 蒙版图案产生公式

蒙版操作的过程与对比图如下图 6.20 所示,图中最上层是没有经过蒙版操作的原始二维码,其中存在大量黑色区域,难以后续的分析识别。经过两种不同蒙版的处理,可以看到最后生成的二维码变的更加混乱,容易识别。




图6.20 蒙版操作示例

蒙版操作之后,得到的二维码即为最终我们平常看到的结果。


七. 源码

笔者原本准备用 C++ 与 OpenCV 写一个二维码解析程序,现在学了二维码的原理后,发现好难。另外网上关于二维码解析与生成的程序基本都是用 Python 写的,笔者又想找个合适机会学习一下 Python,所以这段时间就准备从二维码入手,学习一下 Python 的基础~

源码及解析笔者会随学习的进度持续更新~


八. 后记

笔者学习完毕二维码内容后不禁感叹,二维码规则的制定当真是凝聚了多少研究者的心血。学无止境,在知识的海洋中,当真是需要抱着敬畏之心和谦卑的态度,才能体会到这片海洋的浩瀚。
研究二维码的过程十分有趣,学到了不少东西,后续过程中笔者会持续更新对二维码的学习心得体会~


推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 解决VS写C#项目导入MySQL数据源报错“You have a usable connection already”问题的正确方法
    本文介绍了在VS写C#项目导入MySQL数据源时出现报错“You have a usable connection already”的问题,并给出了正确的解决方法。详细描述了问题的出现情况和报错信息,并提供了解决该问题的步骤和注意事项。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
author-avatar
000000
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有