二维码原理入门 · 讲义与学习笔记
了解二维码如何把信息编码成黑白方块图案的基本原理。
整理:问学·科技
第 1 关 · 二维码是什么:从扫码日常说起
认识二维码的来历、与一维条形码的区别,以及它在生活中的地位
二维码在日常生活中的普及
二维码在日常生活中的普及
想象一下十年前去菜市场买菜:摊主找零、收钱、记账,全靠现金和脑子里的账本。今天呢?抬头一个二维码,低头一笔支付就完成了。二维码已经像水电气一样,成了我们生活的基础设施。
一、你今天扫了几次码?
试着回忆一下:从早上起床到晚上睡觉,你可能已经在不知不觉中扫过好几次码了。
- 早上出门:地铁站闸机口的乘车码
- 到公司:扫一下签到,或打开健康码
- 午餐时间:餐厅桌角的点餐码,扫一下看菜单、下单、付款
- 下午茶:奶茶店柜台前的下单码
- 加好友:朋友发来一张名片码,你扫一下就加上了
- 买东西:便利店、超市、甚至菜市场小摊都贴着收款码
- 取快递:驿站柜子上的取件码
- 晚上回家:小区门禁码、电梯里的乘梯码
这些场景有一个共同点:**原本需要「输入」或「口头传递」的信息,现在只需要「扫一下」**。
二、二维码扮演的三种角色
仔细看上面这些场景,二维码其实在扮演三种不同的角色:
- **身份凭证**——健康码、乘车码、门禁码:扫码 = 亮明「我是我」
- **入口指引**——点餐码、加好友码、公众号关注码:扫码 = 进入一个服务或页面
- **资金通道**——收款码、付款码:扫码 = 完成一笔钱的转移
flowchart LR
A[日常生活中的二维码] --> B[身份凭证]
A --> C[入口指引]
A --> D[资金通道]
B --> B1[健康码/乘车码/门禁码]
C --> C1[点餐码/加好友码/关注码]
D --> D1[收款码/付款码]
这三种角色覆盖了「人-机」、「人-人」、「人-钱」三种最基础的连接。所以有人说,**二维码是移动互联网时代最朴素的连接器**——它不漂亮、不复杂,但任何一部手机、任何一个人都能用。
三、一个值得记住的事实
2010 年前后,扫码支付在中国开始普及;到今天,全球绝大多数日常扫码行为都发生在中国。换句话说——**二维码这项日本发明的技术,在中国被用得最广最深**。
这个细节先留个印象,等我们讲到 QR 码的诞生历史时,会再聊这个故事。
**要点:** 二维码早已从「偶尔用一下的工具」变成「生活的基础设施」——它在不同场景里扮演着身份凭证、入口指引、资金通道三种角色,核心作用都是把「信息」和「动作」之间的成本降到最低。
一维条形码与二维码的核心区别
一维条形码与二维码的核心区别
想象你去图书馆找一本书。贴在书脊上的那串「竖线条」就是**一维条形码**——它只能告诉你这本书的「编号」(比如 ISBN 编号),相当于一个身份证号;而贴在封底或海报上的那个「方方正正的黑白格子」就是**二维码**,相当于把整本书的简介、目录、几段文字都印在了这一小块地方。
下面从三个最根本的维度,把这两种码拆开对比。
区别一:方向——条形码认「横竖」,二维码认「方位」
条形码是横向排列的黑白条纹,它储存信息的方式是「这一条粗,那一条细,再来一条细的」。这就要求**扫的时候必须大致水平、顺着条纹方向划过**。你把它竖过来、斜过来、倒过来扫,机器就读不懂了。
二维码是一个**正方形的方阵**,三个角上有三个一模一样的大方块(叫「定位图案」)。无论你正着扫、斜着扫、倒着扫,机器只要认出这三个角,就能立刻判断出方块的朝向和边界,然后正确读取。所以你用手机扫海报、墙上的码,怎么歪都能扫出来——这就是为什么我们从来没见人「摆正了再扫」。
区别二:容量——条形码存「一个编号」,二维码存「一段信息」
条形码最多大概只能存 **几十个数字**(典型如商品 EAN-13 条码就是 13 位数字)。所以你扫一瓶水的条形码,看到的只是「这瓶水的厂商代码 + 商品编号」,背后还要靠后台数据库告诉你这是「农夫山泉 550ml」。
二维码能存的量大得多,**纯数字可以到 7000 多个,汉字也能装 1000 多个**,相当于塞进一整段话、一个小网页、一张电子名片都不在话下。这就是为什么付款、加好友、看菜单这些动作都能靠一个二维码完成——它自己就带得动全部信息,根本不用联网去查。
区别三:容错——条形码「一脏就废」,二维码「缺角也能读」
条形码没有任何保护机制:只要中间一道黑条被污渍盖住、被撕掉、被折皱,那一段对应的数字就丢了,机器直接报错。
二维码则天生**自带「纠错能力」**。它的方阵里专门划分了一部分区域用于存放「纠错码」——你可以把它理解成一份「备份+校验信息」,就像考试答卷时把答案誊抄了一遍,并且还留了空让你事后核对。所以二维码脏了一块、缺了一个角、甚至 logo 盖住中间一小片,通常都能照常扫出来。
flowchart LR
subgraph A1[一维条形码]
A1A[方向: 只能横着扫]
A1B[容量: 几十个数字]
A1C[容错: 脏了就废]
end
subgraph A2[二维码]
A2A[方向: 360度都能扫]
A2B[容量: 数千字符]
A2C[容错: 缺角也能读]
end
A1A --- A2A
A1B --- A2B
A1C --- A2C
一个直观的数字
同样大小(约 2 厘米见方)的一小块地方:
- 条形码能存 **13 位数字**(一箱可口可乐的全球编号)
- 二维码能存 **几百个汉字**(相当于一篇微博的全部正文)
密度的差距,差了不止一个数量级。
**要点:** 条形码是「横条纹+只能横扫+几十个数字+毫无保护」的线性码;二维码是「方阵+360度可扫+数千字符+自带纠错」的矩阵码——两者不只是形状不同,而是**信息组织方式**完全不同,这正是二维码能撑起今天这么多扫码场景的根本原因。
QR 码的诞生与历史
QR 码的诞生与历史
你可能觉得二维码是「互联网时代的产物」——其实它比你想象的老得多:1994 年,QR 码在日本一家汽车零件工厂的车间里诞生,最初根本没想过要让我们这些普通人扫一扫。
1994 年:丰田工厂里的痛点
QR 码的发明者是日本电装公司(Denso Wave),是丰田汽车集团旗下的零部件供应商。当时的工厂车间里,每个零件都要贴一个一维条形码,用来追踪生产批次、序列号、检验记录等。但一维条形码的问题在工厂里被放大了:
- 容量太小,一个条形码只能装十几个数字
- 必须把扫描枪精确地对准条形码才能读
- 工厂里油污、灰尘、反光金属表面到处都是,扫描经常失败
- 一旦条形码脏了或被撕掉一角,就完全读不出来了
电装的工程师原昌宏(Masahiro Hara)带领团队,被要求设计一种**能在嘈杂工厂环境下快速、稳定读取更多信息**的码。1994 年,这种新的方格码诞生了,名字叫 **QR(Quick Response)码**——「快速响应」,意思就是「一扫就出结果,不用等」。
三个「工厂基因」决定了今天的扫码体验
回头看,QR 码最初为工厂做的几个设计,恰恰成了今天我们随手就能扫一扫的关键:
flowchart LR
A1[零件反光脏污] --> B1[三个角的定位图案] --> C1[歪着倒着都能扫]
A2[条形码容量小] --> B2[方阵式二维结构] --> C2[能装下整段网址文字]
A3[标签破损常发生] --> B3[内置纠错码] --> C3[缺角污渍照常读]
这三个设计不是为今天移动支付准备的,是为 1994 年的丰田工厂准备的——但它们意外地让 QR 码成为了最适合普通人用手机摄像头扫的码。
1997 年:一个改变命运的决策
QR 码刚诞生时,电装主要是为自家和丰田的工厂使用。但 1997 年,电装做了一个在当时看来很不可思议的决定:**把 QR 码的技术规范向全世界公开,不收任何专利费**。
公司当时的判断是:QR 码本身不赚钱,但如果能成为全球通用标准,卖配套的扫描设备、工业读码器就能持续盈利。这个决策为 QR 码后来的爆发扫清了最大的障碍——任何公司、任何国家想用,都不需要付钱。
从工厂车间到街头巷尾
QR 码真正走入日常生活,靠的是两个时间点的叠加:
- **2000 年代中后期**,手机摄像头越来越普及,人们开始用手机「拍照」代替专用扫描枪
- **2011 年前后**,微信、支付宝先后推出「扫一扫」支付功能,把 QR 码推到了中国几亿人的日常里
到今天,付款、加好友、点餐、查核酸、领优惠券……我们的生活已经被这个 30 岁的小方块承包了大半。
**要点:** QR 码是 1994 年日本电装公司为解决汽车零件工厂的追踪难题而发明的,「QR」意为「快速响应」;1997 年电装免费公开技术规范,使它得以走向全球;它身上那些为工厂环境设计的特点(定位图案、大容量、纠错),恰好也让它成为了最适合手机扫的码。
二维码家族:QR 码的近亲们
二维码家族:QR 码的近亲们
你以为「扫一扫」扫的就都叫二维码?严格说,二维码是一个**家族**,QR 码只是这个家族里最出名的那个成员。它们的共同点是「用黑白方块在两个方向上编码信息」,但形状、容量、适用场景各有不同。
想象一下交通工具家族:轿车、卡车、摩托车、电动车都是车,但有人用来通勤、有人用来拉货、有人用来飙车。QR 码是二维码家族里的「家用轿车」——最常见、最普及,但绝不是唯一一种。
家族主要成员
**QR 码(Quick Response Code)** 方方正正的大方块,**三个角**各有一个「回」字形的大方块作为定位图案。这是最经典、你在街头巷尾扫到的几乎都是它。
**Data Matrix(数据矩阵码)** 也是方形的,但比 QR 码更「迷你」。它的定位图案是一条**沿左下两边的 L 形实线**(不是三个角的大方块),所以整张码可以做得非常小,最小能塞进 2-3 毫米见方的面积。工厂里手机芯片、电子元器件追溯用的就是它——这些元件上的标签本来就小,QR 码塞不进去。
**PDF417** 长得最不一样:**长方形**,看起来像是把好几个一维条形码**堆叠**在一起。容量特别大(可以装下几千个字符),所以美国驾照、登机牌、一些国家的身份证背面贴的都是它。你见过美国大片里机场安检时刷的那张纸片吗?那就是 PDF417,不是 QR 码。
**汉信码** 中国在 2007 年发布的**自主国家标准**。形状和 QR 码很像,但定位图案有**四个**(不只是三个角),理论上抗变形能力更强。在国内一些政务、物流场景偶有应用,但普通消费者几乎不会碰到。
一图看清区别
flowchart LR
Q[QR 码] --> Q1[方形 三个角定位] --> Q2[支付加好友点餐]
D[Data Matrix] --> D1[小方形 L 形定位] --> D2[电子元件追溯]
P[PDF417] --> P1[长方形 条码堆叠] --> P2[美国登机牌驾驶证]
H[汉信码] --> H1[方形 四个角定位] --> H2[中国国标 政务偶见]
为什么日常说的「扫一扫」特指 QR 码?
不是所有二维码都能被你的微信、支付宝扫出来。这两个 App 里「扫一扫」按钮背后的识别模块,**主要就是 QR 码解码器**。如果你拿着一张 PDF417 的登机牌去扫,弹出来的多半是「无法识别」。
再加上我们生活中 99% 的码(付款码、点餐码、加好友码、防疫码、电影票……)都是 QR 码,**「扫一扫」这个词在中文语境里几乎已经成了 QR 码的代名词**。
**要点:** 二维码是一个家族,QR 码、Data Matrix、PDF417、汉信码是其中常见的几位成员;QR 码因免费公开+设计通用,成为「扫一扫」的实际代名词,但工厂小零件、美国登机牌这些场景里,你看到的会是 QR 码的「近亲」。
学习笔记
二维码学习笔记
一、二维码在日常生活中的角色
二维码已从偶尔使用的工具变成生活的基础设施。
**典型扫码场景**:乘车码、健康码、签到码、点餐码、加好友码、收款码、取件码、门禁码、乘梯码等。共同点是把原本需要「输入」或「口头传递」的信息,变成「扫一下」即可完成。
**二维码扮演的三种角色**:
- 身份凭证:健康码、乘车码、门禁码——扫码即亮明身份
- 入口指引:点餐码、加好友码、公众号关注码——扫码即进入服务或页面
- 资金通道:收款码、付款码——扫码即完成资金转移
这三种角色覆盖「人-机」「人-人」「人-钱」三种基础连接,因此二维码被称为移动互联网时代最朴素的连接器。
2010 年前后扫码支付在中国开始普及;二维码是日本发明的技术,却在中国被用得最广最深。
二、一维条形码与二维码的核心区别
| 维度 | 一维条形码 | 二维码 | | --- | --- | --- | | 方向 | 只能横着扫,顺条纹方向划过 | 360 度都能扫,三个角有定位图案 | | 容量 | 最多几十个数字(如 EAN-13 共 13 位) | 纯数字 7000 多个,汉字 1000 多个 | | 容错 | 无保护机制,脏了就废 | 自带纠错码,缺角也能读 |
**直观对比**:同样约 2 厘米见方的面积,条形码能存 13 位数字(一箱可口可乐的全球编号),二维码能存几百个汉字(相当于一篇微博正文)。
两种码的根本差异是**信息组织方式**不同:条形码是「横条纹+线性编码」,二维码是「方阵+二维编码」。这是二维码能撑起今天众多扫码场景的根本原因。
三、QR 码的诞生与历史
**1994 年,丰田工厂的痛点**:日本电装公司(Denso Wave,丰田集团旗下零部件供应商)发明 QR 码,发明者为原昌宏。当时工厂用一维条形码追踪零件,遭遇四大问题:
- 容量太小,只能装十几个数字
- 必须把扫描枪精确对准才能读
- 油污、灰尘、反光金属表面导致扫描常失败
- 脏污或破损即无法读取
QR 即 Quick Response(快速响应),意为「一扫就出结果,不用等」。
**三个「工厂基因」决定今天的扫码体验**:
- 为应对零件反光脏污→设计三个角的定位图案→歪着倒着都能扫
- 为突破条形码容量小→采用方阵式二维结构→可装下整段网址或文字
- 为应对标签破损→内置纠错码→缺角、污渍照常读
**1997 年的关键决策**:电装将 QR 码技术规范向全世界免费公开,不收专利费;判断 QR 码本身不赚钱、配套扫描设备才是利润来源。这一决策为 QR 码走向全球扫清了最大障碍。
**走入日常的两个时间点叠加**:
- 2000 年代中后期,手机摄像头普及,人们用手机代替专用扫描枪
- 2011 年前后,微信、支付宝先后推出「扫一扫」支付功能
四、二维码家族
「二维码」是一个家族,QR 码只是其中最出名的成员,常见成员包括:
**QR 码(Quick Response Code)**
- 形状:方形,三个角各有一个「回」字形定位图案
- 用途:支付、加好友、点餐等,街头巷尾最常见
**Data Matrix(数据矩阵码)**
- 形状:比 QR 码更迷你的小方形,定位图案为左下两边的 L 形实线
- 用途:最小可塞进 2-3 毫米见方,用于手机芯片、电子元器件追溯
**PDF417**
- 形状:长方形,把多个一维条形码堆叠在一起
- 用途:容量特别大,可装几千个字符;美国驾照、登机牌、部分国家身份证背面使用
**汉信码**
- 形状:方形,定位图案有四个
- 性质:中国 2007 年发布的自主国家标准
- 用途:国内部分政务、物流场景偶有应用,普通消费者几乎不会碰到
**「扫一扫」特指 QR 码的原因**:微信、支付宝的「扫一扫」模块主要就是 QR 码解码器,扫 PDF417 等其他类型会显示「无法识别」。由于生活中 99% 的码都是 QR 码,「扫一扫」在中文语境中几乎成了 QR 码的代名词。
第 2 关 · 解剖一个二维码:整体结构与各区域作用
看懂一个二维码由哪几部分构成,每个区域分别负责什么
位置探测图形:三个角的『回』字方块
你有没有过这种经历:在陌生商场里找厕所,先抬头找一面特别大的招牌墙,认准了它就知道整个商场的方向了?
二维码三个角上的「回」字方块,就扮演着这个角色——它们是扫码器在画面里最先要找的「地标」。
三个回字方块长什么样
把任何一个二维码放大看,左上角、右上角、左下角各有一个由黑白相间方块组成的图案,看起来像一个汉字「回」——外圈是 7×7 的黑色边框,里面是 5×5 的白色,再里面是 3×3 的黑色实心方块。
这三个图案大小完全一样,黑白比例固定(1:1:3:1:1),无论二维码里的数据怎么变,这三个角的样子永远不变。它们是二维码的「身份证」——只要看到这三个一模一样的方块,扫码器就知道:这是一张二维码。
为什么是三个角,不是四个
你可能会问:四个角都放上回字方块,不是定位更准吗?
其实三个就够了。三个点确定一个平面——只要在画面里找到这三个固定图案的位置和倾斜角度,扫码器就能算出整张二维码的朝向:是歪了 10 度?还是旋转了 90 度?倒着扫的?
而第四个角(与左下角对角的右下角)没有放定位图案,是因为:
- 三个点已经足够确定方向,再加一个不会让定位更准
- 把右下角空出来,可以多塞一些数据
这就是为什么你看到的二维码,三个角特别「重」、很显眼,第四个角相对「轻」的原因。
扫码器拿到这三个图案后做什么
整个识别过程可以简化成下面这条流水线:
flowchart LR
A[摄像头画面] --> B[搜索三个回字方块]
B --> C{找到三个了吗}
C -->|否| D[继续扫描等待]
C -->|是| E[根据三点位置计算朝向]
E --> F[建立网格坐标系]
F --> G[按格读取黑白数据]
最关键的一步是「根据三点位置计算朝向」——通过三点确定一个平行四边形,再把这个平行四边形「摆正」成矩形,整个二维码的方向就校正完成了。哪怕你把手机歪着拍、倒着拍、斜着拍,最后落到扫码器眼里的都是一张「正」的二维码。
正因为这三个角图案这么简单又这么显眼,无论你贴出来的海报是斜的、皱的、远到只露出一角,扫码器都能迅速把它从背景里挑出来。
**要点:** 三个角上的「回」字方块是二维码的定位地标——它们帮扫码器在画面里找到二维码、判断朝向、摆正网格,是整个识别流程的起点。
校正图形:用于大尺寸二维码的位置参考
你可能已经注意到:有些大尺寸的二维码,在三个角上的大「回」字方块之外,里面还会冒出一两个甚至更多个更小的「回」字方块。它们是干什么用的?
校正图形长什么样
校正图形(Alignment Pattern)看起来是三个角那种大「回」字方块的缩小版——5×5 的外黑边、3×3 的内白圈、最中间 1×1 的黑点。整个图案只占 5×5 个模块的大小。
它和大「回」字(7×7)不一样,结构更简单,最明显的特征是「中心有一个孤立的黑点」。
什么时候会出现
校正图形不是所有二维码都有。它从**版本 2**开始出现(也就是 25×25 模块以上的二维码),而且随着版本号增大,数量也变多:
- 版本 1(21×21):没有
- 版本 2(25×25):1 个
- 版本 7(45×45):6 个
- 版本 40(177×177):多达 46 个
每一个校正图形出现的位置都不是随机的,而是按标准严格规定——扫码器只要知道这是哪个版本,就能预判出所有校正图形的坐标。
为什么要多个校正点
三个角上的定位图案只够解决两件事:**找到二维码**、**判断整体朝向**。但当二维码变大、贴的表面不平整时,靠近中心的部分会被拉扯变形。
举个生活中的例子:你把一张 A4 纸平铺在桌上对得很齐,但要是把它贴在一个圆柱面上,纸的中段会被横向拉伸、两端会被压缩。如果你只在纸的四个角画上标记,中间被拉成什么样你根本算不出来——除非中间还有几个参考点。
校正图形就扮演了「中间参考点」的角色。当扫码器算出整张网格的坐标时,它会用每一个校正图形的位置来反推:这一区域的网格间距应该是多少?这一行的模块有没有被挤压或拉伸?发现偏差就立即局部校正。
flowchart LR
A[三个大回字定位] --> B[确定整体方向]
A --> C[建立初步网格]
C --> D[扫描校正图形位置]
D --> E{实际位置与预期位置一致吗}
E -->|是| F[网格准确 继续读数据]
E -->|否| G[局部微调网格间距]
G --> F
正是因为有校正图形做网格「校准」,哪怕你把二维码印在易拉罐的曲面上、贴在皱巴巴的海报上、远远地斜着拍,扫码器也能把每个模块的边界算得八九不离十。
最后要注意一点:校正图形本身**不存储任何数据**,纯粹是为定位服务的。这也是为什么无论二维码里存什么内容、什么纠错等级,校正图形的位置和样子都不会变。
**要点:** 校正图形是大尺寸二维码里的「中间参考点」——它们不存数据,只负责帮扫码器在大面积、易变形的二维码中精确还原网格坐标。
定时图形:连接模块的隐形坐标线
你已经知道了:三个角的「回」字负责让扫码器找到二维码、判断朝向。但找到整张图之后,还有一个更细致的问题没解决——这张图里有几十上百个模块,每个方块到底应该落在哪个坐标上?光靠三个角的方块是算不出中间的。这一块要讲的「定时图形」就是来解决这个问题的。
定时图形长什么样
定时图形(Timing Pattern)是横纵各一条的黑白交替条纹,从一个角的「回」字延伸到另一个角的「回」字。
- 一条横线从左上角的「回」字出发,穿过整个二维码,连接到右上角的「回」字。
- 一条竖线从左上角的「回」字出发,穿过整个二维码,连接到左下角的「回」字。
- 两条线在中间相交(交点落在二维码内部)。
这条线的关键特征是**严格的黑白交替**——一个黑模块、一个白模块、一个黑模块、一个白模块……永远不会出现两个相同颜色的模块挨在一起。整条线看起来就像一条虚线,或者像尺子上的刻度。
它在哪里
定时图形的位置是固定的,**永远在第 6 行和第 6 列**(从 0 开始数是第 6 行/列,从 1 开始数是第 7 行/列)。
为什么是这个位置?三个角的「回」字每个都占 7×7 个模块。「回」字和二维码其他内容之间需要留一条边,定时图形就填在第 6 行/列这条边上的位置。
它解决什么问题
回到一开始的问题:扫码器找到二维码、确定朝向之后,怎么知道每个方块的精确边界?
flowchart LR
A[三个角的定位图案] --> B[确定整体方向]
B --> C[顺着定时图形追溯]
C --> D[数黑白交替的次数]
D --> E[算出每个模块的精确位置]
E --> F[建立完整网格]
定时图形就是「尺子」。它横纵各一条,从角到角穿过去,黑白严格交替——这条线上的每个模块位置都是可以**直接数出来**的:起点是 0,第二个模块是 1,第三个是 2……因为颜色严格地一黑一白,扫码器不可能数错(不会出现两个黑挤在一起,导致判断不出「这一格是从哪开始的」)。
数完这条线,扫码器就知道了:
- 这一行/列上有多少个模块(也就是整个二维码的版本号)
- 每个模块的物理宽度是多少像素
有了这个基准,再配合上一节讲的校正图形,扫码器就能把整张二维码的网格画出来,然后才准备好去读中间的数据。
它存数据吗
不存。定时图形是固定图案,不管二维码里放的是网址、文字还是名片,定时图形长得都一样。它纯粹是为「定位」服务的。
**要点:** 定时图形是位于第 6 行和第 6 列、从一个「回」字连到另一个「回」字的黑白交替条纹——它像一把尺子,让扫码器能精确数出每个模块的位置,从而建立完整的网格坐标。
数据区与纠错区:方块阵里装了什么
到目前为止,三个角的「回」字帮扫码器找到二维码并确认方向,校正图形和定时图形帮它精确画出网格。但这些都还是「准备工作」——把准备工作做完之后,扫码器其实还没看到二维码里真正装着什么。这一块要讲的「数据区」和「纠错区」,才是二维码的本体。
数据区:装的就是内容本身
中间密密麻麻的黑白方块,绝大多数是「数据区」。它们存的就是你扫码时真正要拿到的内容——一个网址、一段文字、一张名片。
内容是怎么变成方块的呢?大致分三步:
- 把内容转成数字(文本有编码、网址直接是字符)
- 数字再转成二进制——也就是一串 0 和 1
- 二进制按 8 位一组切成小块,每一字节对应 8 个模块:黑代表 1,白代表 0(标准固定)
所以中间那些方块,**每个方块就是一个比特**。一个 V5(37×37)的二维码,扣掉三个角的「回」字、校正图形、定时图形等保留区域,剩下的几乎全是数据区,大约能存 100 多字节,相当于几十个汉字。
纠错区:存的是「数学备份」
数据区装的是真正内容,但中间区域里**不是所有方块都是内容**——还有相当一部分是纠错码。
纠错码的思路是:内容在写入二维码之前,先用一种叫 Reed-Solomon 的算法,给原始数据算出一批「备份数字」。这些备份数字本身不是内容,但它们和原始数据之间有严格的数学关系。
怎么理解「数学关系」?可以用一个类比:
- 你发短信「明天下午三点开会」,担心对方漏看,又发一条「下午三点,会议室见」——两条消息单独看是重复的,但即使第一条丢了,从第二条也能猜出原意。
- Reed-Solomon 更聪明:它不是简单重复信息,而是把信息**重新组装**成一组数字,这组数字里**任何一部分丢失,剩下的部分依然能反推出全部**。就像给朋友三个不同措辞的摘要,任何一个到达,他都能猜出全文。
纠错码也是按 0/1 转成黑白模块,**和数据区一起填进中间区域**。
它们怎么混在一起
注意:不是「先填一整片数据区,再填一整片纠错区」。真实情况是数据和纠错码按一定规则**交错排列**。扫码器按规则去读,知道哪些字节是数据、哪些是纠错,遇到某些字节因污损读不出来时,就把剩下的纠错字节代进去反推——只要丢得不太多,就能精确算回原始内容。
flowchart LR
A[原始内容] --> B[转成二进制]
B --> C[Reed-Solomon 算法]
C --> D[生成纠错码]
B --> D
D --> E[数据 + 纠错码<br/>按规则交错]
E --> F[填进中间区域的模块]
F --> G[扫码时]
G --> H{模块是否可读}
H -->|可读| I[直接拼接内容]
H -->|部分不可读| J[用纠错码反推]
I --> K[还原出原始信息]
J --> K
为什么脏了或缺角也能扫
二维码有 4 个纠错等级,生成时由制作者选择:
- L 级:能恢复约 7% 的丢失
- M 级:能恢复约 15%
- Q 级:能恢复约 25%
- H 级:能恢复约 30%
纠错等级越高,纠错码占的空间越大,能存的内容就越少。朋友圈里带 logo 的彩色艺术二维码,常用 H 级——因为中间要加图,必须留出大量冗余。
这就是为什么:
- 二维码缺了一块角还能扫
- 上面有污渍、折痕、涂鸦还能扫
- 中间用马克笔涂黑一块,只要不超过纠错等级允许的范围,依然能扫出来
**要点:** 中间密密麻麻的方块里,既有真正装内容的数据区,也有用 Reed-Solomon 算法算出的「数学备份」纠错区。两者按规则交错排列——只要丢失的模块不超过纠错等级允许的比例(最高 30%),扫码器就能用纠错码把丢失的内容精确反推回来。
格式信息与版本信息:方块阵周边的元数据
上一块讲了中间装内容的数据区和作备份的纠错区。但细想会发现:扫码器在读内容之前,还有几件**必须先知道**的事——这个二维码用了几级纠错、用了哪种掩码图案、是多大尺寸的版本。这些「二维码的身份证信息」,就存在两个专门的区域里。
格式信息:二维码的「小身份证」
把二维码看成一本书,数据区和纠错区是书的**正文**。但书有封面、有目录,告诉读者「这是什么语言写的、几月几号印的、哪个版本」。二维码也有类似的东西——**格式信息**(format information),可以理解为二维码的「小身份证」。
格式信息主要告诉扫码器两件事:
- **纠错等级**:L、M、Q、H 中的哪一个(上一块讲过,决定丢了多少能恢复)
- **掩码图案编号**:0 到 7 中的哪一种(让黑白分布更均匀的处理,下一块会讲到)
格式信息一共 15 个比特,存放在两个对称位置——**左上角「回」字的两条边**,以及**右上角、左下角「回」字之间的镜像位置**。每 15 比特存两遍,相当于「双保险」。
flowchart LR
A[左上角回字<br/>右侧一列] --> R[扫码器]
B[左上角回字<br/>下方一行] --> R
C[右上角与左下角回字间<br/>的镜像位置] --> R
R --> O[两份合并<br/>多数表决]
版本信息:尺寸的「名片」
格式信息每个二维码都有,但**版本信息**只在大尺寸二维码里出现——V7(45×45)及以上才有。
为什么?因为小二维码「长得都差不多」,一眼能数清行列;版本一多,V10(57×57)、V20(97×97)、V40(177×177),扫码器要是一开始不知道是哪个版本,就没法提前安排好「要扫多少模块、跳过哪些保留区域」。
版本信息一共 18 比特:6 比特表示版本号(V1–V40,正好 6 比特够用),剩下 12 比特是纠错码。它同样存两遍,放在两个对称位置——**左下角「回」字的上方**和**右上角「回」字的左侧**。
元数据自己也有纠错保护
这里有个值得停一下的细节:格式信息和版本信息**自己也是模块**,也会被污损、遮挡。它们凭什么保证自己被正确读出来?
答案是:它们内部也带了纠错码,用的是 BCH 算法——一种和 Reed-Solomon 同源的纠错思路:
- 格式信息:5 比特有效内容 + 10 比特纠错码 = 15 比特
- 版本信息:6 比特版本号 + 12 比特纠错码 = 18 比特
再加上本身存两遍做多数表决,**即使有一份被部分涂掉,扫码器也能从另一份或通过纠错码反推出正确内容**。这就好比书里最重要的「扉页」单独又用硬壳精装了一遍——因为太关键了,必须多穿几层防护。
为什么这是「先决条件」
用生活场景打个比方:你在陌生车站看站牌,第一反应是看**语言标识**——中文、英文、还是日文?只有先确认语言,才能读懂。格式信息和版本信息就扮演这个角色:
- 不知道纠错等级 → 不知道哪些字节是数据、哪些是备份
- 不知道掩码编号 → 读出来的 0/1 是「错位」的,必须先反转
- 不知道版本 → 不知道一共要扫多少模块、保留区在哪
任何一个缺失,整个二维码都解不开。**所以这两个小区域,是解码能开始的入场券。**
**要点:** 二维码方块阵周边有专门的「元数据区」——格式信息记录纠错等级和掩码编号(15 比特、所有版本都有、存两遍),版本信息记录尺寸版本(18 比特、V7 及以上才有、存两遍)。这些元数据本身也带了 BCH 纠错保护,因为一旦它们出错,整个二维码都解不开。
静默区:二维码四周的空白边距
静默区:二维码四周的空白边距
到这一节为止,我们已经讲完二维码方块阵内部的全部内容——三个角的「回」字定位图案、散布的「小回字」校正图案、横纵交替的定时坐标线、中间装内容和纠错码的数据区、再加上记录纠错等级与版本号的元数据小区域。
但你把目光拉远一点看整张图,会发现**二维码方块阵并不是直接贴着画布边缘的**。它的四周还留着一圈明显的白色空白——这圈空白就是**静默区**(quiet zone),也叫「空白边距」或「隔离区」。
静默区到底是什么
静默区不是二维码的一部分,而是二维码**外面**的留白。
按照官方标准,这圈空白至少要 **4 个模块宽**(1 个模块就是 1 个最小黑白方块的边长)。也就是说:如果你看到一个版本 1 的二维码(21×21),那它四周还要再各留 4 个方块那么宽的白边,整个白边宽度差不多是方块阵边长的 20%。
flowchart LR
A[画布边缘] --> B[静默区<br/>4 个模块宽白边]
B --> C[二维码方块阵<br/>包含定位 校正 定时 数据 元数据]
C --> D[静默区<br/>4 个模块宽白边]
D --> E[画布边缘]
静默区为什么必须存在
扫码器第一步要做的事叫**图像定位**——它在摄像头拍到的画面里,先要找到「二维码大致在哪里、占多大、是什么方向」。这一步靠的是识别那三个角的「回」字图案。
但识别算法有个前提:它需要从一片**明显单一**的背景里,把「回」字图案的边缘「拎」出来。如果二维码紧贴着文字、贴着其他图案、贴着边框,算法就会困惑——哪个是二维码、哪个是背景、哪里是边缘?
静默区的作用就是**告诉扫码器:「二维码从这里开始」**。
打个比方:你在剧场的观众席上找舞台,并不需要舞台上的灯光告诉你——**舞台和观众席之间那片空地本身就在告诉你「表演的边界在这里」**。静默区就是二维码和周围环境之间的那片「空地」。
实际场景里常见的踩坑
理解了原理之后,很多日常踩坑就有了清晰解释:
- **海报上的二维码直接顶到纸边缘**:扫描成功率断崖式下降,因为没有静默区
- **把二维码贴在一张满是文字的传单上**:周围的文字、线条、装饰会侵入静默区,扫码器「找不准边界」
- **电子屏幕上用软件截图,截到二维码顶到屏幕边缘**:哪怕内容是好的,也扫不出
- **在 PPT 里缩小二维码时没留白边**:常见的失败原因,不是二维码坏了,是「出场仪式」没准备好
反过来,**只要静默区留够,再脏、缺角、甚至部分被涂黑,只要不破坏三个角的「回」字和整体内容,扫码器依然能正确识别**——这一点我们前面讲过的纠错码帮了大忙,但静默区是这一切能发生的前提。
一个反直觉的小细节
你可能会想:那我把静默区留得**特别宽**呢?比如包了 10 个模块的白边,会不会扫不出来?
不会。**静默区比标准宽,是完全没有问题的**,扫码器仍然能正确识别。它害怕的是「窄」或「没有」,而不是「宽」。
这也是为什么很多印刷品里的二维码看起来白边异常宽——设计师往往是出于美观考虑留了更多空白,结果反而让扫码更稳。
**要点:** 静默区是二维码方块阵四周的纯白边距(标准至少 4 个模块宽),它本身不存任何信息,只负责「告诉扫码器二维码从哪里开始」。没有静默区或静默区被周围图案侵占,再好的二维码也扫不出来;但留得比标准更宽完全没问题。
学习笔记
位置探测图形
二维码左上、右上、左下三个角各有一个「回」字方块:外圈 7×7 黑色边框、内圈 5×5 白色、中心 3×3 黑色实心方块。黑白比例为 1:1:3:1:1,三个图案大小完全相同,无论二维码里的数据怎么变,这三个角的样子永远不变。
三个角而不是四个的原因:
- 三个点即可确定一个平面,足以判断二维码的朝向与倾斜角度
- 空出右下角可多塞数据
扫码流程:摄像头画面 → 搜索三个回字方块 → 找到则根据三点位置计算朝向 → 建立网格坐标系 → 按格读取黑白数据。最关键一步是「根据三点位置计算朝向」——通过三点确定平行四边形再「摆正」成矩形。
校正图形
形似大「回」方块的缩小版:5×5 外黑边、3×3 内白圈、最中间 1×1 黑点。**中心有一个孤立黑点**是与定位图案最显著的区别。
仅在版本 2(25×25)及以上出现,数量随版本增大而增多:
- 版本 1(21×21):0 个
- 版本 2(25×25):1 个
- 版本 7(45×45):6 个
- 版本 40(177×177):46 个
每一个校正图形的位置按标准严格规定,扫码器能预判所有坐标。校正图形**不存任何数据**,只负责在大面积、容易变形的二维码中提供中间参考点,让扫码器反推每个区域的网格间距,局部校正被挤压或拉伸的模块。
定时图形
横纵各一条、严格黑白交替的条纹:
- 横向:从左上角「回」字连到右上角「回」字
- 纵向:从左上角「回」字连到左下角「回」字
- 两条线在中间相交
位置固定在**第 6 行和第 6 列**(从 0 开始数)。黑白严格一比一交替,不会出现两个同色模块相邻。
功能相当于一把「尺子」:扫码器沿这条线数黑白交替次数,即可确定每行/列的模块总数(也就是版本号)与每个模块的物理像素宽度。**不存数据**,无论二维码里放什么内容,定时图形长得都一样。
数据区与纠错区
数据区装的是扫码真正要拿到的内容(网址、文字、名片)。内容→二进制→按 8 位分组→每字节对应 8 个模块(黑=1,白=0),**每个方块就是一个比特**。
纠错区用 Reed-Solomon 算法在写入前为原始数据算一批「备份数字」:把信息重新组装成一组数字,任一部分丢失,剩余部分仍可反推全部。纠错码也按黑白模块填入。
数据与纠错码按规则**交错排列**,而非分区独立存放。扫码时按规则区分各字节用途,遇到污损无法读出的字节用纠错码反推。
四个纠错等级(生成时选择):
- L:约 7% 可恢复
- M:约 15%
- Q:约 25%
- H:约 30%
等级越高,纠错码占比越大,能存内容越少。
格式信息与版本信息
格式信息(共 15 比特)告诉扫码器两件事:
- 纠错等级(L/M/Q/H)
- 掩码图案编号(0–7)
存放在左上角「回」字的两条边及右上、左下角「回」字之间的镜像位置,**存两遍**做多数表决。
版本信息(18 比特)只在版本 7(45×45)及以上出现:
- 6 比特表示版本号(V1–V40 正好 6 比特够用)
- 12 比特为纠错码
存放在左下角「回」字上方与右上角「回」字左侧的对称位置,同样存两遍。
两者自身也带 BCH 纠错保护:格式信息 5 比特内容+10 比特纠错;版本信息 6 比特+12 比特纠错。**这些元数据是解码的入场券**——少了它们,纠错等级、掩码、版本、保留区位置全无法判断,整个二维码都解不开。
二维码方块阵外部四周的白色空白边距
二维码方块阵**外部**四周的白色空白边距,按标准至少 4 个模块宽(1 模块=1 个最小黑白方块的边长)。它不是二维码的一部分,而是为扫码器提供的隔离带。版本 1(21×21)的二维码四周各留 4 个模块宽的白边,整个白边宽度约为方块阵边长的 20%。
第 3 关 · 信息如何变成黑白方块:编码的大致流程
理解一段文字或网址是如何一步步『翻译』成二维码里的黑白方块的
起点:要被编码的原始内容
想象一下:你面前有一个固定大小的盒子,最多能装 7000 多个纯数字(或者更少的汉字)。这就是二维码这个「容器」的容量上限。在讨论「怎么把这些东西变成黑白方块」之前,我们先得搞清楚一件事——**到底什么东西能往里装、什么东西装不进去**。
二维码只能装「数字化的文字」
二维码本质上只能装一种东西:**可以用字符表达的内容**。具体来说包括:
- **纯数字**:比如订单号「20240715001」、金额「88.50」、身份证号
- **英文字母与符号**:比如「Hello」「https://example.com」
- **中文、日文等文字**:比如「张三」「北京市朝阳区」
- **结构化信息**:比如名片(姓名+电话+邮箱拼成一段文本)、Wi-Fi 密码、短信草稿
这些内容的共同点是——它们都可以被写成「一串字符」。不管原本是中文、英文还是数字,最终在计算机里都是数字和字母的组合。
图片、视频、音频装不进去
但有些东西,**二维码装不下**:
- 一张照片
- 一段视频
- 一首歌曲
- 一份 PDF 文件
为什么装不下?两个原因:
- **太大**:一张普通手机照片就有 2-5 MB,一段手机视频动辄几十上百 MB,而整个二维码最多只能装几千个字符
- **不是字符**:照片、视频的原始数据是像素点、音频是采样波形,不是「文字」
那为什么扫码能看到视频?
你可能会问:商场里那些「扫码看视频」「扫码听歌」「扫码看菜单」的海报,二维码里不也装着视频吗?
这里有个**关键的小心机**:海报上的二维码里装的不是视频本身,而是一个**网址链接**——比如 `https://shop.example.com/video/123`。手机扫码识别出这个网址后,自动用浏览器打开它,再从服务器上把视频下载下来播放。
flowchart LR
A[要装进二维码的内容] --> B{能不能写成字符}
B -->|能| C[可以直接装]
C --> D[纯数字]
C --> E[英文字母]
C --> F[中文汉字]
C --> G[网址]
B -->|不能| H[不能直接装]
H --> I[照片]
H --> J[视频]
H --> K[音频]
H --> L[只能装一个指向它们的地址]
这就像你家小区门口的信箱格:信箱本身只能装「纸条」——纸条上写着「快递在楼下菜鸟驿站」。你要取的东西不在信箱里,信箱只负责告诉你「去哪取」。
二维码装的是「地址」,不是「东西」
再举几个你可能没注意过的例子:
- **加好友码**:装的不是头像,是一串包含对方账号信息的文本
- **收款码**:装的不是钱,是一段包含商户号、金额等信息的字符串
- **健康码**:装的不是你的健康记录,是一个网页地址,手机打开后会从服务器调出你的健康状态
所以准确地说,二维码是一个**「文字容器」**——它把原本要输入或口述的字符,变成一秒钟就能扫出来的图形。要装的「内容」必须是「可以写成字符」的东西;装不下的,就用一个**指向它的地址**代替。
**要点:** 二维码只能装文字、数字、网址这类「字符内容」;图片、视频、音频装不下,只能装一个指向它们的网址。
编码模式:选择合适的翻译规则
编码模式:选择合适的翻译规则
想象一下你要把一批东西装进旅行箱:装书和装衣服的叠法不一样;装易碎品和装不怕压的堆法也不一样。**二维码也是这样——不同类型的内容,用不同的「翻译规则」能装得更紧凑**。
这种「针对内容类型挑选规则」的思想,就叫做**编码模式**。
为什么需要分模式?
二维码的空间是有限的(最常见的版本最多也就装几千个字符),所以要尽量省着点用。**字符越少,能装的二进制位就越短**。如果不管三七二十一,所有内容都用同一种最「通用」的规则翻译,那英语字母、中文汉字、纯数字全都得占用相同长度——太浪费了。
于是二维码设计了**几种模式**,让你根据内容挑最划算的那种。
三种最常见的模式
**1. 数字模式(Numeric Mode)**
- 适用:纯数字 `0-9`
- 特点:最省空间
- 翻译思路:每 3 个数字压缩成 10 个二进制位(10 位二进制能表示 0–1023,足够装下 000–999 这 1000 种组合)
**2. 字母数字模式(Alphanumeric Mode)**
- 适用:数字 `0-9`、大写字母 `A-Z`,以及 9 个符号(空格、$、%、*、+、-、.、/、:),共 45 个字符
- 特点:比数字模式「胖」一点,但能装英文短句和大写英文网址
- 翻译思路:每 2 个字符压缩成 11 个二进制位(11 位二进制能表示 0–2047,足够区分 45×45=2025 种组合)
**3. 字节模式(Byte Mode)**
- 适用:任意 8 位字符,主要是中文、日文、特殊符号、小写字母等字母数字模式装不下的内容
- 特点:最通用但也最占地方
- 翻译思路:1 个字符 = 8 个二进制位(不压缩,直接用 UTF-8 编码)
flowchart LR
A[原始内容] --> B{看内容类型}
B -->|纯数字| C[数字模式]
B -->|大写英文加数字加符号| D[字母数字模式]
B -->|中文等其他字符| E[字节模式]
一个具体例子:不同模式占的「位」差多少
假设要编码「12345」这 5 个字符:
- 数字模式:10 位 + 7 位 = **17 位**
- 字母数字模式:每个字符 6 位 = **30 位**
- 字节模式:每个字符 8 位 = **40 位**
可见选对模式,能省下将近一半的空间。
再比如「您好」这两个汉字:字母数字模式根本装不下(字符集里没有中文),只能走字节模式,2 × 8 = 16 位;而同样的 16 位用字节模式装纯英文「hi」都能装 2 个字符了。
模式是怎么「声明」的
你可能会问:扫码端怎么知道这段 0/1 该按哪种规则解?答案是在所有数据前面,会有 4 位的「模式指示符」——像给这批内容贴个标签:「接下来这串请用数字模式翻译」「接下来这串请用字节模式翻译」。扫码端看到标签,就知道用什么规则反向还原。
**要点:** 二维码有数字、字母数字、字节等多种编码模式,针对内容挑最合适的模式能让二进制序列更短、更省空间;模式本身会在数据开头用一个 4 位的「标签」告诉扫码端按哪种规则还原。
位流到模块:把 0/1 摆成黑白方块
把脸凑近手机屏幕上的二维码看——你会发现它并不是一张整张的图,而是由**几百个、几千个小方块**拼成的:每个小方块要么全黑、要么全白,没有第三种颜色。
这些小方块在扫码端的术语里叫做**模块(module)**——可以理解成二维码的「最小积木」。整个二维码就是由这些积木拼成的一张方阵图。
一长串 0/1 等着落座
上一节讲到,编码模式会把文字或网址翻译成一长串 0 和 1。这串 0/1 现在就像一长串珠子,**接下来要做的事,就是把每颗珠子(一个 bit)落进一个小方块**:1 落进去是黑块,0 落进去是白块。
(约定俗成:1 对应黑、0 对应白,但反一反也不影响理解。)
方阵有多大?
二维码有一个**版本**的概念:
- 版本 1:21 × 21 个模块(最小的二维码)
- 版本 2:25 × 25
- 往上每升一版,边长大 4 个模块
- 版本 40 最大:177 × 177,三万多个小方块
装的内容越多、版本越高,方阵就越大。
落座顺序:蛇形走位
0/1 是按什么顺序填进方阵的?不是横着扫、也不是竖着扫,而是**蛇形(zigzag)走位**:
- 从**右下角**起步
- 向上**两列两列**地填:先填右列、再填左列
- 走到最顶,调头向左两列,再向下走
- 像贪吃蛇一样反复上下
flowchart LR
A[右下角起步] --> B[向上两列两列填]
B --> C[到顶向左移两列]
C --> D[向下两列两列填]
D --> E[到底再向左移两列]
E --> B
蛇形的好处是:不管二维码怎么旋转,扫码端只要找到定位用的固定标志(比如三个角的大方框),就能从右下角开始反着解出整条 0/1 序列。
不是所有方块都给内容用
你看到的二维码里,**三个角的大方框、中间一条条横竖的虚线、零散的小方块**——这些位置并不是给 0/1 序列用的。它们是**功能性图案**,是给扫码端用来定位和校准的「保留席」。
所以 0/1 序列真正能落座的,是**扣掉这些保留席之后**剩下的区域。打个比方:电影票上的「保留席」不卖观众,观众只能坐剩下的位置。
一个具体例子
假设一段 16 位的 0/1:`10011010 | 01101001`,要摆到 4×4 方阵里(现实比这大得多,只是把原理缩小):
- 右下角 = 第 1 位(1)→ 黑块
- 上方 = 第 2 位(0)→ 白块
- 第 3 位(0)→ 白块
- ……蛇形向上摆完一列,再向左摆下一列
最终这 16 个方块按某种深浅交错排出来——每个方块对应原文里的一个 bit,组合起来就是原始内容的视觉投影。
提一句
你扫二维码扫多了可能会发现:偶尔会出现大块连片同色,或者奇怪的「棋盘格」「横条纹」——这些花纹容易让扫码端看花眼。怎么解决?下一节「数据掩码」会讲。
**要点:** 二维码每一个 0 或 1 都有自己对应的「小方块座位」(叫模块);扫码端从右下角开始按蛇形路径一个一个填进方阵,1 涂黑、0 涂白,填完就得到一张我们看到的黑白方块图。
数据掩码:让花纹更易识别
上一节我们把 0/1 序列按蛇形摆进了方阵里——理论上这就够了。但实际操作时会遇到一个头疼的问题。
问题:摆完之后可能「不好看」
假设内容碰巧就是 `0000000000` 这种全 0,或者 `1010101010` 这种规律横纹。直接按位摆进方阵会出现什么?
- 全 0 → 出现大块连片白
- 规律横纹 → 整张图看起来像斑马线
- 大块同色区域 → 扫码端难以找到方块边界
可以理解成:你画了一幅画,但不小心把整片天空涂成了一模一样的蓝色——别人想看清你画的是什么,反而被这大片同色「晃」到了眼。
flowchart LR
A[原始 0/1 序列] --> B[按位摆到方阵]
B --> C{出现大块同色?}
C -->|是| D[扫码端难以识别]
C -->|否| E[正常可读]
解决方案:套一层「掩码模板」
为了让最终图样「花得更均匀」,二维码规范定义了 **8 种掩码模板**,每一种都是一张和二维码同样大小的固定 0/1 图案。
具体做法是**异或(XOR)**——一种「相同就变 0、不同就变 1」的翻转规则:
- 原方块是黑,掩码该位置是黑 → 翻成白
- 原方块是黑,掩码该位置是白 → 保持黑
- 原方块是白,掩码该位置是黑 → 翻成黑
- 原方块是白,掩码该位置是白 → 保持白
简单说:**掩码是黑的格子把原图翻色,掩码是白的格子原样保留**。一层「打散花纹的筛子」就套上去了。
flowchart LR
A[原始方块图] --> C[XOR 异或运算]
B[选中的掩码模板] --> C
C --> D[最终方块图:花纹更均匀]
八种模板,哪种最好?
8 种掩码模板的图案是规范里固定写死的(每种用一行数学公式就能描述出来),生成二维码时会**挨个试一遍**:
- 把原方块图和模板 0 异或 → 算出评分
- 把原方块图和模板 1 异或 → 算出评分
- …… 一直试到模板 7
- 选**评分最低**的那一个
评分依据是几条「惩罚规则」,大意是:
- 大片同色连块 → 扣分多
- 容易和定位图案撞脸的图案 → 扣分多
- 大量 1:1:3:1:1 比例的图案(看起来像定位图案的「假货」)→ 扣分多
可以理解成:扫码端有一份「最讨厌看到的图案」清单,每种模板都拿去对照一遍打分,**最让人不讨厌**的那一个胜出。
选完之后,还要告诉扫码端
既然从 8 种里挑了 1 种用,最终图里**必须告诉扫码端用的是哪一个**——否则扫码端拿到图也没法反推出原始 0/1。
所以二维码的固定功能区里,**有 3 个小块专门用来记录「我用的是几号掩码」**(用 3 bit 表示 0-7)。扫码端扫到图后先读这 3 个小块,知道了掩码编号,再把图和对应掩码再异或一次,就能还原出原始 0/1 序列。
一个直观的对比
想象一段纯 0 序列(比如 16 个 0),直接摆进 4×4 方阵会得到一整片白块。套上掩码后——白块里有些位置被翻成了黑,**整张图变成了均匀分布的散点花纹**,扫码端一扫就能找到方块边界、读出 0/1。
**要点:** 摆好方块之后,二维码会用 8 种固定掩码模板之一(用 XOR 翻转)去「打散」大块同色区域,让最终图样更易识别;生成时会按惩罚规则挑评分最低的那一种,并把「用了几号掩码」记在二维码里,扫码端据此反推原始 0/1。
纠错码:编码流程中的备份步骤
你有没有过这种经历:传纸条给同桌,关键字被墨水糊掉一半,但靠上下文能猜出来?纠错码的思路跟这个很像——主信息被弄脏了一部分,凭借「额外的备份信息」还能把原文还原回来。
为什么需要纠错码?
二维码和纸条一样,会被磨损:
- 塑料袋上的二维码被折过、磨花
- 商品包装上的二维码被油渍盖住一角
- 远距离扫描时一部分方块超出识别区
如果方块图只是「原原本本」的内容,缺一块就读不出来。生成二维码时必须**提前预留**应对这些情况的能力——这就是纠错码的作用。
纠错码是什么?
可以把它想成「**原文的备份线索**」:
- 主信息(比如一段网址)本身变成一串 0/1
- 然后根据这串 0/1,按某种数学规则**算出一批额外的 0/1**——这就是纠错码
- 主信息和纠错码**一起**摆进二维码的方阵
扫码端读出图后,先用纠错码反推哪些 0/1 出了错,**修正或重建**那些丢失的部分,再还原出原始网址。
打个比方
想象你给朋友寄一封手写信,但信封可能被雨淋湿:
- 普通做法:只写信的内容,湿了就认不出来
- 加纠错码的做法:除了信的内容,还**附上几个「提示词」**——比如「每句话都是 8 个字」「第 3 句话末尾是'吗'」。哪怕部分字被水糊掉,朋友靠这些提示能**重新拼出全文**
纠错码就是这种「提示词」的角色——**它本身不携带新信息,但能让丢失的部分被反推出来**。
四种纠错等级
二维码规范规定了**四个纠错等级**,从弱到强:
- **L(低)**:大约能修复 7% 的方块丢失
- **M(中)**:大约 15%
- **Q(较高)**:大约 25%
- **H(高)**:大约 30%
**等级越高,纠错码占的方块越多,留给主信息的位置就越少**——所以同一尺寸的二维码:
- 选 L → 能装最多的网址/文字
- 选 H → 网址变短,但二维码「耐脏」能力极强
可以这样理解:你准备背一段课文。
- 如果只背原文本身,你能背一大段
- 如果再背「每段最后一句是什么」「每段的中心词」这些提示,提示越多原文就得**腾位置**给它们
纠错等级越高,分配给「提示词」的位置就越多。
编码流程里的位置
到这里,整个编码流程就完整了:
flowchart LR
A[原始内容] --> B[选编码模式]
B --> C[变成 0/1 序列]
C --> D[追加纠错码]
D --> E[摆成方阵]
E --> F[套掩码]
F --> G[最终二维码]
纠错码是**主信息编码完成、摆进方阵之前**追加的——和主信息一起被摆进方块,又一起被掩码处理。
**要点:** 纠错码是编码流程里的「备份步骤」——在主信息之后追加一批根据主信息算出的额外 0/1,扫码端据此反推并修复丢失的部分;规范规定了 L/M/Q/H 四种等级,等级越高越耐脏,但能装的主信息也越少。
学习笔记
二维码编码流程笔记
二维码的容量与能装的内容
- 二维码的容量上限约能装 7000 多个纯数字(或更少的汉字)。
- 只能装「可以用字符表达的内容」:纯数字(如订单号、身份证号)、英文字母与符号(如网址)、中日文等文字、结构化信息(名片、Wi-Fi 密码、短信草稿)。
- 装不下:照片、视频、音频。原因有二——体积太大(一张照片 2-5 MB,一段视频几十上百 MB,而二维码最多装几千个字符);原始数据不是字符,而是像素点或采样波形。
- 关键小心机:海报二维码装的是网址链接(如 `https://shop.example.com/video/123`),不是视频本身;扫码识别出网址后由浏览器去服务器下载。
- 同样道理:加好友码装的是对方账号信息的文本、收款码装的是包含商户号的字符串、健康码装的是网页地址(服务器再去调出健康状态)。
- 核心结论:二维码是一个「文字容器」——装得下的就直接装字符,装不下的就装一个指向它的地址。
三种编码模式:让 0/1 序列更短
- 编码模式 = 针对内容类型挑选最划算的翻译规则,让二进制序列尽量短。
- **数字模式(Numeric Mode)**:适用纯数字 0-9,最省空间;每 3 个数字压缩成 10 位二进制(10 位可表示 0–1023,足够装 000–999 共 1000 种组合)。
- **字母数字模式(Alphanumeric Mode)**:适用数字 0-9、大写字母 A-Z 加 9 个符号(空格、$、%、*、+、-、.、/、:),共 45 个字符;每 2 个字符压缩成 11 位二进制(11 位可表示 0–2047,足够区分 45×45=2025 种组合)。
- **字节模式(Byte Mode)**:适用中文、日文、小写字母等上面两种装不下的任意 8 位字符;1 个字符 = 8 位二进制(直接用 UTF-8 编码,不压缩)。
- 节省对比:「12345」5 个字符 → 数字模式 17 位、字母数字模式 30 位、字节模式 40 位。
- 中文例子:「您好」2 个汉字字母数字模式装不下,只能走字节模式 16 位;同样 16 位用字节模式装纯英文「hi」可以装 2 个字符。
- 模式声明:所有数据开头会有 4 位「模式指示符」作为标签,告诉扫码端按哪种规则反向还原。
位流落座:把 0/1 摆成黑白方块
- 模块(module)= 二维码的最小积木;每个模块要么全黑、要么全白,没有第三种颜色。
- 约定:1 对应黑块,0 对应白块(反一反也不影响理解)。
- 版本决定方阵大小:版本 1 是 21×21 个模块(最小),每升一版边长大 4 个模块,版本 40 最大为 177×177(3 万多个小方块)。装的内容越多、版本越高、方阵越大。
- 落座走蛇形(zigzag):从右下角起步,两列两列地填(先填右列再填左列),到顶后调头向左移两列再向下走,像贪吃蛇一样反复上下。
- 蛇形的好处:无论二维码怎么旋转,扫码端找到三个角的固定定位标志后,都能从右下角开始反着解出整条 0/1 序列。
- 不是所有方块都给内容用:三个角的大方框、中间的横竖虚线、零散小方块都是「功能性图案」(保留席),不装 0/1 序列;0/1 真正能落座的是扣掉这些保留席后的区域。
数据掩码:用 8 种模板打散花纹
- 问题:直接按位摆放可能撞上全 0、规律横纹、大块同色区域——扫码端难以找到方块边界,像被大片同色「晃」到眼。
- 解决方案:二维码规范定义了 8 种掩码模板,每种是和二维码同样大小的固定 0/1 图案,用 XOR(异或)规则套到原方块图上。
- XOR 效果:掩码是黑的格子把原图翻色,是白的格子原样保留(相同→0,不同→1)。
- 模板挑选:8 种模板挨个试一遍,按「惩罚规则」评分(大片同色连块、与定位图案撞脸、1:1:3:1:1 比例的「假定位图案」都扣分),选评分最低的那种。
- 掩码编号要记:最终图里用 3 个小块(3 bit 表示 0-7)记录「我用的是几号掩码」;扫码端先读这 3 个小块,再和对应掩码再异或一次,就能还原原始 0/1 序列。
纠错码:给主信息加备份线索
- 纠错码 = 原文的备份线索:本身不携带新信息,但能让丢失的部分被反推出来。
- 追加方式:主信息先变成一串 0/1,然后按某种数学规则算出额外的 0/1(纠错码),两者一起摆进方阵。
- 四个纠错等级:L 约修复 7%、M 约 15%、Q 约 25%、H 约 30% 的方块丢失。
- 等级越高,纠错码占的方块越多,留给主信息的位置越少——同一尺寸下选 L 能装最多的内容,选 H 则网址更短但二维码更「耐脏」。
- 追加位置:主信息编码完成之后、摆进方阵之前。
完整编码流程
原始内容 → 选编码模式 → 变成 0/1 序列 → 追加纠错码 → 按蛇形走位摆成方阵 → 套掩码(XOR)→ 最终二维码。
第 4 关 · 为什么脏了缺角也能扫:纠错码的基本概念
明白二维码的容错能力来自哪里,能区分四个纠错级别
冗余思想:纠错码的直觉来源
冗余思想:纠错码的直觉来源
想象一个场景:朋友让你在小区的公告栏上抄一条通知——比如周六下午三点在 B 栋一楼开业主大会。公告栏露天下雨会被雨淋、被人撕角、被涂鸦都可能发生。
**最朴素的做法:把同一句话多抄几遍。**
比如你在公告栏上写三遍「周六下午三点 B 栋一楼」。就算下大雨冲糊了一遍,或者有人撕掉一个角,只要另外两遍还看得清,消息就保住了。这个「多说几遍」的做法,核心思想就是**冗余**——冗余的意思是「超出必需的那一份」。本来抄一遍就够的信息,你多放了同样的几份作为备份。
二维码的容错能力,最底层就来自这个思想。
**为什么「多说几遍」还不够聪明?**
把所有信息都重复多份太浪费空间了。公告栏就这么大点地方,你抄三遍同样的话,本来可以再放三条别的通知的位置就被挤掉了。
更聪明的做法是:不是把原话原封不动多抄几遍,而是**用原话「算」出一些「陪练」信息**——这些陪练信息跟原话有数学上的关联,但占的空间更小。
举个例子,老师批改作业时不只看你答案对不对,还会看你列的算式。如果你只写「答案=42」,老师会怀疑你是不是抄的;但你把「算式过程」也写出来,老师就更容易判断你是不是真懂。这「算式过程」不重复答案本身,但能从它反推答案是否正确——这就是一种更聪明的「陪练信息」。
二维码用的纠错码就是这种更聪明的「陪练信息」:根据原始数据,用数学方法「算」出一些附加方块。这些方块本身不重复原始内容,但跟原始内容绑在一起。哪怕原始数据被雨淋、缺角了一部分,只要这些陪练方块还在一部分,扫码器就能反推出原始内容应该是什么。
整个流程可以这样看:
flowchart LR
A[原始数据] --> B[算出纠错码]
A --> C[组合成二维码方块]
B --> C
C --> D[部分方块丢失]
D --> E[用纠错码反推原始数据]
**核心结论:**
二维码的容错不是靠「把方块多放几份」这种笨办法,而是靠「用数学方法算出来的关联备份」——业内叫「纠错码」。具体怎么算的我们后面再展开,但这一节你要先建立一个心智模型:
> 原始数据 + 纠错码 一起塞进二维码 → 局部丢失 → 扫码器用剩下的纠错码反推原始数据。
**要点:** 纠错码的底层思想是冗余——多放一些跟原始信息相关联的「陪练」内容,让丢失的部分可以被反推回来;不是简单重复,而是数学关联。
里德-所罗门码:纠错码的工作原理(概念版)
里德-所罗门码:纠错码的工作原理(概念版)
上一节我们说,二维码的「陪练信息」是「用原话算出来的数学关联」。但具体是怎么算的?算出来之后,怎么就能「反推」回被弄丢的部分?这就是里德-所罗门码(Reed-Solomon Code)要解决的问题——它是二维码实际使用的纠错码方案。
从一个更简单的例子入手:校验位
你有没有注意过,身份证最后一位、银行账号的某几位,是「算出来的」而不是随便填的?比如,把身份证前面 17 位数字按一定规则加权求和,再除以 11,得到的余数对应的数字就是第 18 位。这最后一位本身不是身份信息,但和前面 17 位绑得死死的——你前面填错一位,这一位就一定对不上。
这就是「聪明的冗余」的最简单形态:多加一位,它不是原信息的重复,但能帮你**发现**前面有没有错。
但校验位只能告诉你「哪里出错了」,还不能直接告诉你「正确的是什么」。而且它一般只能扛一两个错误,遇到大面积缺角就抓瞎了。
里德-所罗门码的升级思路
里德-所罗门码干的是同一件事,但做得更狠:
- **多算几份「校验」**:不是只多加一位,而是算出多份「陪练数据」,每份都和原始数据有数学关联,相当于给原信息套了好几道「安全锁」。
- **能定位错在哪**:当一部分数据被弄丢,里德-所罗门码可以根据剩下的「陪练数据」反推出「丢失的是哪几个位置」。这比单纯校验位强大很多——它能「精确定位伤员」。
- **能反推出原文**:定位到丢失位置之后,再用剩下的原始数据加陪练数据一起做「数学运算」,把丢失的方块重新算出来。
整个过程可以这样看:
flowchart LR
A[原始数据] --> B[里德-所罗门编码<br/>算出多份陪练数据]
B --> C[原始加陪练<br/>一起塞进二维码]
C --> D[部分方块丢失]
D --> E[用剩余方块反推]
E --> F[定位丢失位置]
F --> G[算出丢失内容]
G --> H[恢复完整原始数据]
一个生活化的类比
想象 5 个朋友约好去某个地方会合,出发前大家约定:
- 每个人记一下自己的名字;
- 大家再约定一个「暗号计算规则」:比如「我们 5 人名字首字母拼起来」是个特定词。
到了现场,如果其中 2 个人被大风吹走了(缺角),剩下 3 个人只要还记得这个「暗号」,就能反推那 2 个人的名字应该是什么——因为「暗号」是 5 个人的名字共同决定的,反过来也能定出每个位置应该是谁。
里德-所罗门码做的就是这件事的数学版。「暗号」不止一个,而是好几个互相独立的暗号;「名字」也不是字面名字,而是数据片段。哪怕丢了相当一部分,暗号还在,原始信息就能被算回来。
**要点:** 里德-所罗门码的核心是「算出来的多份关联数据」——它能定位丢失的位置,也能反推出原文内容;和单校验位比,它能扛的错更多、更智能,是二维码能抗脏抗缺角的真正功臣。
四个纠错等级:L、M、Q、H
四个纠错等级:L、M、Q、H
上一节我们讲了里德-所罗门码的工作哲学:多算几份关联数据,既能定位丢失位置,也能反推原文。但——多算几份,到底应该算几份?QR 码规范没有一刀切,而是提供了**四档选择**,让你按场景挑。这四档就是 L、M、Q、H(取自 Low、Medium、Quartile、High 的首字母),对应不同的「陪练数据」数量。
四个等级的具体能力
| 等级 | 名字 | 容错率(约) | 实际意义 | |------|------|--------------|----------| | L | Low 低 | 7% | 丢失不超过约 7% 的方块,仍能扫出来 | | M | Medium 中 | 15% | 丢失不超过约 15% 的方块,仍能扫出来 | | Q | Quartile 四分之一 | 25% | 丢失不超过约 25% 的方块,仍能扫出来 | | H | High 高 | 30% | 丢失不超过约 30% 的方块,仍能扫出来 |
注意:7%、15%、25%、30% 是「约数」,规范里写的更精确一点(7.5%、15%、25%、30% 左右),但业界普遍用这一组整数,方便记忆。
「30%」是什么概念?打个比方:一个 10cm × 10cm 的二维码,中央被贴了一个 3cm × 3cm 的 logo,它依然能扫——这就是 H 等级的实力。
怎么直观理解四个档位的差异?
用你工作中的备份思维来打比方:
- L 级 ≈ 只做了一份异地备份,万一损坏能恢复一点;
- M 级 ≈ 标准备份,能扛常见故障;
- Q 级 ≈ 比较完整的备份方案;
- H 级 ≈ 多重异地多份备份,坏掉近三分之一也无所谓。
备份越完善,能抗的风险就越大——但占用的「资源」(这里指二维码的方块)也越多。这条「容错能力 vs 占地方」的取舍,下一节会专门讲。
实际场景里,谁在用哪个档?
- **M 级最常见**:餐厅点餐、电影院取票、商场活动页——15% 是个甜蜜点,日常磨损够扛,又不会浪费太多空间。
- **H 级用于恶劣环境**:
- 户外广告牌(风吹日晒、可能被人涂鸦);
- 产品包装(印在曲面上、运输途中磨损);
- 印在 T 恤或海报上(穿在身上摆动、扫描距离远、角度歪)。
这些地方「能不能扫出来」比「能不能多塞点字」更重要,宁可牺牲容量也要选 H。
- **L 级空间紧张时用**:比如要在一张很小的卡片上印二维码,同时要装很多信息,这时候就只能用最低的容错换容量。
- **Q 级是个折中**:比 M 强、比 H 省空间,常见于工业产品标签。
flowchart LR
L[L 级<br/>约 7% 容错]
M[M 级<br/>约 15% 容错]
Q[Q 级<br/>约 25% 容错]
H[H 级<br/>约 30% 容错]
L --> M --> Q --> H
**要点:** QR 码的纠错强度分 L、M、Q、H 四档,分别能扛约 7%、15%、25%、30% 的损坏;选哪一档,是在「抗损能力」和「能装多少信息」之间做权衡。
纠错等级与容量的取舍
纠错等级与容量的取舍
上一节我们说了 L、M、Q、H 四档:H 档最强,能扛约 30% 损坏。但——等等,那为什么不全用 H 级?答案就是「好东西是要付代价的」。
为什么不直接全选 H 级?
用你最熟悉的场景来打比方:你有一个固定大小的行李箱,要装易碎品去托运。
- 如果只放易碎品本身:能装很多,但飞机颠簸时一个就碎一个。
- 如果每一件都包厚厚的泡泡纸:能装的东西少多了,但飞机再颠也不怕。
- 你不会全用 H 级,正如你不会给每双袜子都包三层泡泡纸。
QR 码的「泡泡纸」就是上一节讲的纠错陪练数据。它们也要占方块——方块总数是固定的(25×25 就是 625 个模块),纠错陪练数据一档一档变多,**留给「真正内容」的方块就一档一档变少**。这就是同一段内容在高纠错等级下「方块需求变多」的真正原因:不是内容变长了,而是陪练数据挤占了内容原本的位置。
具体数字:版本 2(25×25)的例子
拿一个最常见的尺寸 25×25 的二维码举例,里面能装的字母数字字符数大约是:
| 纠错等级 | 大约能装多少 | |----------|--------------| | L | 约 47 个 | | M | 约 38 个 | | Q | 约 29 个 | | H | 约 20 个 |
(数据来源:ISO 18004 标准,版本 2、字母数字模式。)
同一张图,从 L 升到 H,能装的内容**差不多腰斩**——47 个掉到 20 个,剩下不到一半。这就是「容错」的价格。
那到底怎么选?
记住一个原则:**先想「会坏到什么程度」,再想「要装多少东西」,最后才决定选哪档**。
几个常见判断:
- **要往中间贴 logo?** 必选 H 级。logo 直接吃掉中心区域,相当于固定损伤 5%–10%。
- **印在 T 恤、海报、户外广告上?** 选 Q 或 H。这些场景下变形、磨损、扫描距离远是常态。
- **产品包装上?** 选 H。运输磨损 + 曲面印刷双重压力。
- **餐厅点餐、办公场景?** 选 M。够用,省空间。
- **卡片大小但内容很多?** 选 L,必要时换更大的二维码尺寸。
还有一个隐藏选项
如果你发现 H 级装不下你想放的内容,**不是只能选 H**。还有一条路:换成更大的二维码(升一个「版本」)。从 25×25 升到 29×29,总方块多了,每个等级装的内容也就都多了一些。
flowchart LR
A[先评估环境] --> B{会坏吗?}
B -- 会很坏 --> C[H 级]
B -- 一般 --> D[Q 或 M]
B -- 几乎不坏 --> E[L 级]
C --> F{装得下吗?}
D --> F
E --> F
F -- 装得下 --> G[定稿]
F -- 装不下 --> H[升一档版本<br/>换更大的图]
**要点:** 纠错等级越高,陪练数据挤占的方块越多,固定大小的二维码能装的内容就越少;选哪档本质是在「抗损能力」和「信息容量」之间做权衡——而不是「越高级越好」。
动手玩一玩:贴 Logo、画花、撕角看扫码
动手玩一玩:贴 Logo、画花、撕角看扫码
前面四节我们聊了「为什么」「是什么」「怎么选」。这一节,我们关上书,去**扫一扫**——光看不练,等于没学。
准备一张「耐造的」二维码
先去网上找一个「二维码在线生成器」(百度搜一下一大堆),输入你公众号的链接、一段话,或者任意网址作为内容。
**关键一步:把纠错等级调到 H**。原因你现在已经知道了:我们要主动破坏它,必须用最高档才扛得住。
生成出来,打印在 A4 纸上——纸越大越好,方便后面动手「糟蹋」它。
五轮「糟蹋」实验
打开手机相机或微信扫一扫,对准这张二维码。**先扫一下确认能扫出来**,这是你的「基线」。
然后开始动手:
**第 1 关:贴 Logo** 在二维码正中央贴一块不透明贴纸,或者用马克笔涂黑一小片。 扫一下——还能扫出来吗?(H 级能扛,但你应该能感觉到识别稍微变慢了一点。)
**第 2 关:画一朵花** 用细马克笔在二维码上随便画几笔,模拟「有人在上面签字、画花」的场景。 ⚠️ 注意:别把**三个角的定位方框**涂掉——那是定位用的,坏了就找不着北了。 扫一下——能扫吗?
**第 3 关:撕一个角** 沿着对角线把二维码的一个角撕掉一小块(大约 10%)。 扫一下——还行?
**第 4 关:撕两个角** 再撕掉一个相对的角。这时候大概有 20% 的方块没了。 扫——还能?恭喜,H 级真的扛得住。
**第 5 关:涂黑定位方框** 把左上角那个大方框用记号笔涂黑。 扫一下——扫不出来了。 为什么?因为定位图案本身不算「内容数据」,不在纠错的保护范围里。它一坏,扫描器根本「找不到这张图在哪」。
这个实验告诉你的三件事
flowchart TD
A[动手实验] --> B[Logo 能贴]
A --> C[涂抹能扫]
A --> D[缺角能扫]
A --> E[定位方框坏了就废]
B --> F[纠错码能识别'遮住的是什么']
C --> F
D --> F
E --> G[定位图案是基础设施<br/>不是纠错能救的]
- **纠错是真实的**:你亲手贴上去的黑色方块,扫描器真的能「猜出来」原来是什么。这不是玄学,是前面说的里德-所罗门码在算。
- **但纠错不是万能的**:三个角的定位方框是「地图」,地图没了,再聪明的纠错也找不到路。
- **H 级的 30% 是怎么来的**:你撕两个角还能扫出来,差不多就是这个数。前面那张表的数字不是拍脑袋——是你亲手上撕出来的。
给运营同学的一句话
下次老板让你「把二维码做漂亮点,中间加上 logo」——你不用再问「这能行吗」,直接选 H 级,然后告诉老板:「放心,logo 最多能占 30%,我有数。」
**要点:** 纠错等级不是抽象参数,是你能亲眼「撕出来」的数字;但定位图案是另一个故事——它是寻路的地图,纠错码管不到它。
学习笔记
二维码纠错码核心要点
一、纠错码的底层思想:冗余
- 朴素冗余:把同样信息多抄几份作为备份(公告栏抄三遍通知)。
- 聪明冗余:用原始数据「算」出关联但更紧凑的「陪练」信息,不重复原内容。
- 二维码的纠错码属于聪明冗余。
- 流程:原始数据 → 算出纠错码 → 组合成二维码方块 → 部分方块丢失 → 用剩余纠错码反推原始数据。
二、里德-所罗门码的工作原理
- 二维码实际使用的纠错码方案。
- 最简形态是校验位:身份证前 17 位按规则加权求和除以 11,余数决定第 18 位。
- 校验位能「发现」错位,但无法反推正确值。
- 抗错能力弱,只能扛一两个错误,遇大面积缺角即失效。
- 里德-所罗门码相对校验位的升级点:
- 多算几份「陪练数据」,每份都和原始数据有数学关联。
- 能定位丢失的是哪几个位置。
- 定位后能用剩余原始数据加陪练数据做运算,反推原文。
- 生活化类比:5 人名字 + 一个共同「暗号计算规则」;暗号由 5 人名字共同决定,反过来也能定出每个位置应是谁。
三、四个纠错等级 L、M、Q、H
- 命名来源:Low、Medium、Quartile、High 的首字母。
| 等级 | 名称 | 容错率(约) | |------|------|--------------| | L | Low 低 | 7% | | M | Medium 中 | 15% | | Q | Quartile 四分之一 | 25% | | H | High 高 | 30% |
- 容错率为约数,规范精确值约为 7.5%、15%、25%、30%,业界普遍用整数记忆。
- 各档典型场景:
- M 级:餐厅点餐、电影院取票、商场活动页(最常见)。
- H 级:户外广告牌、产品包装(曲面印刷 + 运输磨损)、T 恤或海报。
- Q 级:工业产品标签(折中档)。
- L 级:卡片很小但内容很多的场景。
四、纠错等级与容量的取舍
- 纠错陪练数据也要占方块;方块总数固定(如 25×25 共 625 个),纠错越强 → 留给内容的方块越少。
- 版本 2(25×25)、字母数字模式下的容量参考:
| 纠错等级 | 大约可装字符数 | |----------|----------------| | L | 约 47 个 | | M | 约 38 个 | | Q | 约 29 个 | | H | 约 20 个 |
- 同一尺寸从 L 升到 H,容量近乎腰斩(47 → 20)。
- 选档原则:先评估环境会坏到什么程度,再看要装多少内容。
- 中央贴 Logo → 必选 H。
- T 恤、海报、户外广告 → 选 Q 或 H。
- 产品包装 → 选 H。
- 餐厅点餐、办公 → 选 M。
- 卡片小但内容多 → 选 L,必要时换更大尺寸。
- 装不下 H 时的备选:升一档「版本」,换更大的二维码尺寸。
五、动手实验验证
- 用 H 级生成一张 A4 二维码作为「耐造」样本,先确认基线可扫。
- 五轮破坏实验:
- 中央贴 Logo 或涂黑一小片 → 仍能扫(识别略慢)。
- 细马克笔涂画几笔(避开三个角定位方框)→ 仍能扫。
- 沿对角线撕掉一个角(约 10%)→ 仍能扫。
- 再撕一个相对的角(约 20%)→ 仍能扫。
- 涂黑左上角定位方框 → 扫不出。
- 实验得出的三点结论:
- 纠错码能反推出被遮盖的方块,30% 容错可亲眼验证。
- 三个角的定位图案不在纠错保护范围,坏了扫描器找不到图。
- 纠错等级的数字是真实工程参数,不是拍脑袋的估值。
第 5 关 · 手机是怎么读懂二维码的:扫描识别的基本流程
知道一次扫码动作背后大致发生了什么
识别定位:扫码如何找到二维码
识别定位:扫码如何找到二维码
想象你在一个拥挤的火车站接人——背景里有上百张脸、行李箱、广播大屏、咖啡杯,但你只用扫一眼就能认出你朋友。为什么?因为你认得他脸上那几个「标志特征」:发际线的轮廓、眼镜的形状、下巴的弧度。扫码 App 从一张复杂的画面里找到二维码的过程,几乎就是这个「在人海中找朋友」的过程。
你打开手机相机,对准一张贴在公告栏上的海报。海报上可能有大段文字、商标、底纹、装饰图案,旁边可能还贴着别的通知、过期的宣传单、别人随手写的电话号码。摄像头的画面里,真正的二维码也许只占四分之一,剩下的全是干扰。扫码 App 面对的**第一个问题**不是「读数据」,而是「先把二维码从这一堆东西里认出来、框出来」。
它怎么找?靠的是上一模块学过的、三个角上永远不变的「回」字方块——位置探测图形。这个图形之所以被设计成三个角而不是四个、而且是「外黑 7×7、中白 5×5、内黑 3×3」这个特定结构,**首要目的**就是让扫码器在混乱的画面里能快速锁定它。
具体怎么扫?大致是这样一条流水线:
flowchart LR A[摄像头采集画面] --> B[转灰度图] --> C[二值化黑白] --> D[逐行扫描找 1:1:3:1:1 比例] --> E[定位到三个角的回字方块] --> F[算出位置大小和朝向] --> G[把二维码区域框出来]
每一步展开看:
**第一步到第三步:把画面简化成黑白图。** 摄像头拍下的是一张几百万像素的彩色照片,但颜色对二维码完全没用——二维码只有黑和白。所以 App 先把彩色图转成灰度图(每个像素的 R、G、B 按公式合成一个 0–255 的亮度值),再二值化:比某个亮度阈值暗的标黑,比阈值亮的标白。这一步把「彩色明暗图」砍成「纯黑白图」,每个像素就一个 0 或 1。这一步砍掉了颜色和灰度两个维度,画面里就只剩下「黑和白」两种信息。
**第四步:逐行扫描找 1:1:3:1:1 比例。** 这是整套识别里最关键的一步。App 从画面第一行像素开始,一行一行地扫,每扫到一段连续的黑白交替,就量一下每段黑色、白色区域的宽度。如果黑-白-黑-白-黑这五段的宽度比正好是 1:1:3:1:1(中间那段最宽,恰好是两侧的两倍多),那就几乎可以确认:扫到了定位图案的某一行。
为什么这种比例这么好用?因为它太精确了——背景里的文字、装饰、底纹、自然纹理,几乎不可能恰好呈现 1:1:3:1:1 这种严格的五段比例。所以扫到这种比例,就**几乎可以排除**背景干扰;反过来,如果连续多行都扫到这种比例、而且这些行的水平位置也一致,就能确定一个完整的「回」字方块被找到了。
**第五步到第七步:三个一起找,定位二维码。** 三个角各跑一遍同样的扫描,三个「回」字方块都被找到。三个点齐了之后,App 就拿到了三个关键信息:
- 二维码在画面里的**位置**(左上角像素坐标)
- 二维码占多大(两个角之间的距离就是边长)
- 二维码是斜的还是正的(三个点构成一个三角形,三角形的形态反推出旋转角度)
到这一步为止,App 已经从「一张海报的照片」变成了「一个被框出来的、方向已知的二维码区域」。读取 0/1 数据、纠错、还原内容,是后面几步的事。
为什么这种设计这么有效?回到开头的类比:你能在火车站一眼认出朋友,是因为他脸上有**几个同时满足**的特征——独特、稳定、不容易变。定位图案也一样:
- **独特**:1:1:3:1:1 这种比例在自然画面里几乎不会出现。
- **稳定**:三个角永远不变,不管二维码里装什么数据。
- **不脆弱**:即使部分被遮挡或光线不均,从完整部分也能反推整体。
- **几何够用**:三个点确定一个平面,足够反推位置、尺寸、朝向。
**要点:** 扫码 App 在一张复杂的画面里,第一步不是读数据,而是靠三个角的「回」字方块(1:1:3:1:1 比例)从背景中**快速锁定**二维码——三个点确定一个平面,让 App 把二维码的位置、大小、朝向一次性算清楚。
方向校正:处理倾斜与倒置
方向校正:处理倾斜与倒置
想象你拍了一张挂在歪墙上的画作——你能看到画框的四个边,但画本身是斜的。要把照片「正过来」,你会去找画面里那些**原本应该是直线的地标**——地板的缝、墙角的线、画框本身的边缘——然后把整张图旋转到这些地标对齐。扫码器把倾斜的二维码「拉正」,用的就是同一招,但它的「地标」是三种刻在二维码内部的小图案。
上一节讲了扫码 App 怎么用三个角的大「回」字方块把二维码从整个画面里框出来。但是「框出来」只是第一步——框出来的二维码可能还是斜的、倒的、歪的、或者**被透视拉伸变形了**。想象一下贴在矿泉水瓶身上的二维码:瓶身是弯的,斜着拍出来一定是个梯形、四个角不再各占九十度。这一节就讲扫码 App 怎么把这些「不规整」的二维码「拉正」成一张规整的网格。
为什么需要校正?
你可能会想:二维码不是正方形吗?三个角都找到了,转一下不就行了?问题在于实际场景里要复杂得多:
- **倾斜**:用户从侧面扫、二维码贴在斜面上的广告牌——拍出来整体是斜的。
- **倒置**:完全倒过来 180° 也要能扫。
- **透视变形**:贴在圆柱形瓶身、被压在门下角、斜放在桌面上——二维码不再是个正方形,而是个梯形或更不规则的四边形。
- **弯曲变形**:贴在曲面上——二维码内部小方块之间的距离不再均匀。
光靠三个角的位置探测图形还不够。还需要更多「地标」。
校正图形:变形二维码的「校准锚点」
二维码除了三个大角上的位置探测图形,还有**几个小一号的「回」字方块**散落在内部几个固定位置——这就是**校正图形**。其中最关键的一个在右下角附近,其他几个在某些版本上还会按规则出现在内部某些交叉点上。
它们长得很像位置探测图形,但尺寸更小(5×5 而不是 7×7),而且和周围白色边框连在一起。它的作用是:**当二维码被透视拉伸或贴在曲面上时,校正图形能告诉扫码器「这里原本应该是一个规整的网格」。**
打个比方:你在一张白纸上画了一个九宫格,每一格的交叉点都画了一个「+」字。然后你把纸揉皱——九个「+」字的位置全乱了。但你仔细看还是能认出每个「+」字原本应该在哪儿,于是可以反推出「纸被揉成了什么形状」,从而把网格「算回来」。校正图形在扫码里做的就是这件事——它是个**内部的坐标锚点**,帮助扫码器反推出整个二维码的网格被扭曲成了什么样。
定时图形:数格子用的「尺子」
另一个关键地标是**定时图形**——一条连接两个位置探测图形的、由黑白相间小方块组成的线。横的、竖的各一条,从左上角出发,沿着第 6 行和第 6 列往里走,整条线都是**黑白黑白黑白…严格 1:1 交替**的。
这条线的作用是**数格子、定大小**。上一节里,扫码器只找到了三个角的「回」方块,但还**不知道每个小方块(模块)到底占多少像素、整个二维码一共有多少个模块**。有了这条定时图形,扫码器沿它数一数「一黑一白一黑一白…一共 28 个交替」,就能反推出整张二维码的边长有多少个模块、每个模块的像素尺寸应该是多少,从而**精确定位**每个格子的位置。
打个比方:你拿到一张模糊的街景照,看不清里面的小细节,但你能数到一排路灯正好 14 根、每根之间间隔一样——这样你就能反推出「哦,每根路灯大概占照片这么宽」,进而算出整个街道的尺度。定时图形就是扫码 App 的「路灯」——用已知等距的参照物去测出整个图的比例尺。
怎么知道哪个方向是「上」?
最后还有一个关键问题:识别出来的二维码,到底哪边是「上」?倒过来也得能扫,所以扫码器必须自己判断「原本应该是哪边朝上」。
诀窍藏在两处细节里:
- **暗模块**:在二维码固定的位置上,**永远有一个深色小方块**(周围数据再怎么变、纠错再怎么补,它都不会变),专门起到「方向锚点」的作用;
- **校正图形的分布位置**:大号位置探测图形永远在左上、右上、左下三个角,而小一号的校正图形在右下角附近——这种「大小搭配」在结构上**不对称**。
三个大回字方块自己看是看不出方向(三个长得一模一样)。但加上暗模块和校正图形的位置,整张二维码就有了**方向线索**——三个大角中,靠近暗模块的那个一定是左下、靠近校正图形的那个一定是右下,剩下两个一上一下。这样扫码器就能确定「这张二维码的『上』是这一边」,然后把它旋转到正确朝向。
把这一节的流程串起来
flowchart LR A[三个大回字方块已框出] --> B[扫描定时图形 数出模块总数和单模块大小] B --> C[定位校正图形 反推网格被扭曲的形状] C --> D[通过暗模块和校正图形位置判断上下方向] D --> E[把二维码旋转 拉伸 反变形为正方形] E --> F[每个模块的位置精准对齐 待读]
到这里,扫码器手里就不再是「画面里一个斜的、变形的二维码区域」,而是**一个规规整整的、方向正确的、每个模块位置都精确对齐的网格**。下一节要做的「把方块读成 0/1」才有意义——因为只有网格对齐了,才能准确判断「这个方块到底是黑的还是白的」。
**要点:** 扫码器在找到三个角之后,还需要借助**校正图形**(反推网格变形)、**定时图形**(数清模块数和大小)、**暗模块位置**(判断上下方向)这三种辅助地标,把斜的、倒的、变形的二维码「拉正」成一个规整、方向正确的网格,才能进入下一步读数据。
模块译码与纠错还原
经过定位和校正两步,扫码器手里已经是一张规规整整、方向正确、每个格子都精确对齐的网格。现在它要做的,就是「读出」里面的内容——把一张黑白格子图,翻译回一段有意义的信息。这正是模块 2 里「信息 → 二维码」那条路的**反向**:从二维码回到信息。
认黑白:每个方块对应 0 或 1
最基本的规则其实你已经猜到了——**黑块代表 1,白块代表 0**。但这里有一个细节:编码方在画二维码之前,会先给整张图加一层「花纹」,叫**掩码**。
为什么要加花纹?想象如果原始数据恰好有连续一大片「白」——扫起来一长条都没反差,扫码器在判断每个方块颜色时就容易出错。所以编码时会按一套规则(共有 8 种花纹),给整张图叠加一种棋盘式变化,把大块同色打散。
扫的时候,扫码器必须先把「花纹」**减掉**,才能看到真实的 0/1。它怎么知道用的是哪种花纹?——读出**格式信息**就明白了。
读元信息:先看「封面」再读「正文」
和很多文件一样,二维码也有一小块**「封面」**专门存放元信息。但要分清楚两类东西:
**格式信息**(所有二维码都有,靠近左上和右上两个角)只包含两件事:
- **纠错级别**:L / M / Q / H(也就是模块 2 提过的「救援队」大小);
- **掩码种类**:用 0~7 哪个花纹叠过。
**版本信息**(**仅在 Version 7 及以上**——也就是 45×45 以上的较大二维码中才有)单独放在二维码另一处位置,存的是版本号本身。
那小尺寸的二维码(Version 1~6,也就是 21×21 到 41×41)怎么办?它们没有版本信息块——不过没关系,扫码器已经从图像整体尺寸直接推算出了它是第几版。
扫码器在「翻译」之前必须先拿到这两层「封面」,否则它不知道该减哪种花纹、也不知道这张图一共有多少个格子。
数格子:按特定顺序读
元信息确认之后,就按**从右下角开始的 Z 字形蛇形走位**一行行往里读——每次读两列、换方向、再读两列。功能区(定位、校正、定时、格式信息、版本信息)自动跳过。
这块细节不用记太深,只需要知道:**读格子是有顺序的,不是乱扫的**——所以即使看上去位置是「打散」的,扫码器依然有办法把信息准确拼回去。
纠错还原:「救援队」上场
现在扫码器手里有了「数据 + 纠错码」。模块 2 讲过,编码时除了原始数据,还额外准备了一支「救援队」——纠错码。它本身不是数据,但和数据有**数学上的关联**。
扫的时候,扫码器会做这件事:
- **核对**:用纠错码去「验算」读出来的数据,看是否对得上;
- **对得上**:数据完整,直接进入下一步;
- **对不上**:调用纠错算法,根据「数据 + 纠错码」的整体结构,**反推出哪几个格子读错了,或者直接补回缺失的格子**——前提是损坏的格子数没超过该纠错级别能承受的上限。
这就是为什么——
- 一张 **H 级**(纠错码约占总码字的 30%)的二维码,被 logo 盖住中间一大块,依然能扫出来;
- 一张 **L 级**(纠错码只占约 7%)的二维码,盖住一小块可能就扫不动了。
这里要避免一个常见误解:**H 级并不是说「这张二维码能放的数据只有正常版本的 30%」**。准确的理解是——H 级意味着**最多能恢复约 30% 的码字**(也就是允许约 30% 的格子被遮盖或损坏),L 级最多只能恢复约 7%。纠错级别越高,**「救援队」越强**(能承受更多损坏),**留给数据的空间相对越少**——这是个典型的**此消彼长**。
还原成原始信息
纠错完成、确认数据干净之后,扫码器再按模块 2 提过的规则,把 0/1 序列翻译回字符——
- 先看**模式指示**(这一段是数字、字母、汉字还是混合?);
- 再看**字符计数**(这一段一共多长?);
- 然后**分组读出**,每 8 位拼回一个字节;
- 最后用对应的字符集(UTF-8 等)显示出来。
那个 `https://example.com` URL、那段文字、那个联系人、那张支付订单号,就回到了你手机的屏幕上。
与模块 2 编码流程对照
把整节串起来,对照模块 2 的编码流程:
flowchart LR A[对齐好的网格] --> B[读出格式信息和版本信息] B --> C[按 Z 字走位读数据位和纠错位] C --> D[用掩码规则还原真实 0/1] D --> E[用纠错码校验和修复] E --> F[按模式指示还原为字符] F --> G[屏幕上显示 URL 或文字]
至此,二维码就完成了从「贴在墙上的一张图」到「手机里能跳转的链接」的完整旅程。
**要点:** 扫码的「译码 + 纠错」本质上是模块 2 编码流程的**逆过程**——先把黑白格子按掩码规则还原成 0/1,再用纠错码验算和修复缺失的格子,最后按编码时的模式把 0/1 翻译回字符。**纠错级别越高,纠错码占比越大、能恢复的码字越多,但留给数据的空间相对越少。**
整体流程:扫码的四步流水线
前 3 块你分别学了「定位」「校正」「译码纠错」三步。这一块要把它们串成一条完整的流水线——**这一步的目标,就是让你能在朋友面前,从头到尾讲清楚「一次扫码到底发生了什么」**。
一次扫码的完整旅程
想象你举着手机,对准奶茶店柜台上那张优惠券二维码。整个过程在零点几秒内发生——但拆开看,它严格按**四步流水线**走,少任何一步都不行:
flowchart LR
A[举起手机打开扫码] --> B[定位:找到三个角并框出二维码]
B --> C[校正:拉正方向并对齐网格]
C --> D[译码:把方块读成 0/1 序列]
D --> E[纠错:验算并修复损坏的格子]
E --> F[屏幕上跳出链接或文字]
拆开看每一步在做什么
**第 1 步 · 定位**:摄像头拍下整张画面,扫码 App 在画面里**找到那三个角的「回」字方块**,圈出二维码所在的矩形范围。这一步要是没成功,后面三步都没法启动——因为根本不知道该去处理画面里的哪一块。
**第 2 步 · 校正**:把框出来的矩形**摆正**——不管二维码是斜着贴、倒着贴、还是贴在曲面上,都要拉成一个规整的、每个格子大小一致的方形网格。这一步靠的是另外两类辅助图案(校正图形和定时图形),告诉扫码器「网格边界在哪、每个格子多宽」。
**第 3 步 · 译码**:按特定顺序**读出每个格子的颜色**(黑 = 1,白 = 0),先剥掉编码时叠上的「掩码花纹」,再翻译回原始的二进制数据流。
**第 4 步 · 纠错**:用编码时预埋的「救援队」(纠错码)**验算读出来的数据**,对不上的话就反推哪里出错、修复缺失的格子——前提是损坏没超过这一级纠错能承受的上限。
走完这四步,0/1 序列被按字符集还原成文字、URL 或其他内容,推送到手机屏幕上。
一句话能讲清的版本
如果你只想用一句话向朋友解释,可以这么说:
> 扫码就是「**先找位置,再摆正方向,然后翻译内容,最后兜底纠错**」——四步流水线依次跑过,一张贴在墙上的黑白格子图就变成手机里能跳转的链接了。
为什么这四步缺一不可
每一步都对应一种「现实里可能出问题」的情况:
- **没有定位**:画面里有成百上千个东西,扫码器根本不知道哪个是你想扫的;
- **没有校正**:二维码歪着贴、贴着曲面,格子大小不一,根本读不出每个方块的边界;
- **没有译码**:就算格子规规矩矩摆在那里,它也不知道怎么把黑白变成 0/1;
- **没有纠错**:贴歪了、被指甲刮花、被 logo 盖住一角,数据就全废了。
四步组合起来,才让二维码在真实世界里「**怎么贴都能扫、有点损伤也能扫**」。这正是二维码比一维条形码强大的根本原因——条形码只有一维信息,容错能力几乎为零;二维码则在二维平面上预埋了多层保护机制。
讲给别人听的小技巧
向朋友解释时,最有效的路径是「**先说结论,再拆步骤**」:
- 先抛结论:「扫码不是『拍一张照就读出文字』那么简单,它是一条四步流水线」;
- 再按顺序讲四步的名字(定位 → 校正 → 译码 → 纠错),每步用一句生活化的类比(比如「定位就像在地图上找到店铺」「纠错就像考试时的备用答题卡」);
- 结尾强调「所以二维码被弄脏一小块也能扫出来——因为有纠错这一步兜底」。
这样讲下来,朋友不仅记住了四步名字,更记住了「**为什么需要这四步**」——也就是二维码设计的精妙之处。
**要点:** 一次完整的扫码,是「**定位 → 校正 → 译码 → 纠错**」四步流水线——前三步让扫码器**找得到、读得出**格子,第四步让它在格子**不完美**的情况下也能还原出原始信息;四步组合起来,才让二维码在现实里「怎么贴都能扫、有点损伤也能扫」。
学习笔记
手机扫描二维码的基本流程
一、识别定位:从画面中框出二维码
三个角的位置探测图形
二维码三个角落(左上、右上、左下)各有一个「回」字方块,结构固定为外黑 7×7、中白 5×5、内黑 3×3。右下角没有。它的首要目的是让扫码器在混乱画面里快速锁定二维码。
定位流水线
flowchart LR A[摄像头采集画面] --> B[转灰度图] --> C[二值化黑白] --> D[逐行扫描找 1:1:3:1:1 比例] --> E[定位到三个角的回字方块] --> F[算出位置大小和朝向] --> G[把二维码区域框出来]
- **转灰度 + 二值化**:颜色对二维码无用,先把彩色图按亮度公式合成 0–255 的灰度,再按阈值切成纯黑或纯白,每个像素只剩 0 或 1。
- **逐行扫描找 1:1:3:1:1**:遇到「黑-白-黑-白-黑」五段宽度比为 1:1:3:1:1 时,几乎可确认是定位图案的一行——这种比例在自然画面里极罕见。
- **三个角齐了之后**,可反推三件事:① 二维码的**位置**(左上角像素坐标);② 二维码的**大小**(两角间距离即边长);③ 二维码的**旋转角度**(三点构成三角形,形态反推朝向)。
四个特征同时满足
四个特征同时满足:① **独特**——1:1:3:1:1 在自然画面几乎不出现;② **稳定**——三个角永远不变;③ **不脆弱**——部分被遮挡或光线不均时,从完整部分可反推整体;④ **几何够用**——三个点确定一个平面,足够反推位置、尺寸、朝向。
二、方向校正:把不规整的二维码拉正
实际场景里二维码可能倾斜、倒置、被透视拉伸(贴在圆柱瓶身)、或弯曲变形。光靠三个角的位置探测图形不够,需要更多「地标」。
校正图形:内部的网格锚点
二维码内部固定位置有几个比位置探测图形**更小**的「回」字方块(5×5 而不是 7×7),其中最关键的一个在右下角附近。它们和白色边框连在一起。当二维码被透视拉伸或贴在曲面上时,校正图形告诉扫码器「这里原本应该是规整网格的一部分」——扫码器借助它反推出网格被扭曲成了什么样,再算回规整网格。
定时图形:数格子的尺子
定时图形是一条连接两个位置探测图形的黑白相间线,横竖各一条,从左上角出发沿第 6 行和第 6 列往里走,整条线严格 1:1 黑白交替。
扫码器沿它数「一黑一白……一共 28 个交替」,可反推整张二维码的边长有多少个模块、每个模块的像素尺寸多少,从而精确定位每个格子的边界。
判断方向:暗模块
二维码固定位置上永远有一个**深色小方块**(暗模块),周围数据和纠错都不会改变它。它专门起「方向锚点」的作用——让扫码器判断哪边原本应该朝上,保证倒置时也能正确识别。
定位和校正完成后
定位和校正完成后,扫码器手里是一张规整、方向正确、每个格子精确对齐的网格。接下来把黑白格子翻译回有意义的信息——这是「信息 → 二维码」的反向过程。
但编码时给整张图叠了一层掩码(共有 8 种花纹)
但编码时给整张图叠了一层**掩码**(共有 8 种花纹),目的是打散大块同色区域,避免扫描时一长条无反差。扫码器必须先**减掉**这层花纹才能看到真实 0/1;通过读出**格式信息**来知道用的是哪种花纹。
元信息:先看「封面」再读「正文」
- **格式信息**(所有二维码都有,靠近左上和右上两个角)只存两件事:① **纠错级别**(L / M / Q / H);② **掩码种类**(0~7)。
- **版本信息**仅在 **Version 7 及以上**(45×45 以上的较大二维码)才有,存在二维码另一处,存的就是版本号。
- 小尺寸二维码(Version 1~6,21×21 到 41×41)没有版本信息块——扫码器已从图像整体尺寸直接推算出它是第几版。
读格子之前必须先拿到这两层「封面」,否则不知道该减哪种花纹、也不知道一共有多少格子。
按从右下角开始的 Z 字形蛇形走位一行行往里读
按**从右下角开始的 Z 字形蛇形走位**一行行往里读,每次读两列、换方向、再读两列。功能区(定位、校正、定时、格式信息、版本信息)自动跳过。
纠错还原
扫码器拿到「数据 + 纠错码」后做三步:
- **核对**:用纠错码验算读出的数据。
- **对得上**:数据完整,进入下一步。
- **对不上**:调用纠错算法,根据整体结构反推哪几个格子读错了,或补回缺失的格子——前提是损坏格子数没超过该纠错级别能承受的上限。
各纠错级别的容错能力:
- **H 级**:纠错码约占总码字的 30%,最多能恢复约 30% 的码字。
- **L 级**:纠错码约占 7%,最多能恢复约 7%。
- 纠错级别越高,**「救援队」越强**(能承受更多损坏),但**留给数据的空间相对越少**——此消彼长。
注意:H 级不是说「二维码能放的数据只有正常版本的 30%」,而是说**最多能恢复约 30% 的码字**(允许约 30% 格子被遮盖或损坏)。
还原成原始信息
纠错完成、数据干净后,扫码器按**模式指示**(这一段是数字、字母、汉字还是混合)把 0/1 序列翻译回字符。
四、整体流程:四步流水线
一次完整扫码严格按四步流水线走:
flowchart LR A[定位] --> B[校正] --> C[译码] --> D[纠错] --> E[屏幕上跳出链接或文字]
| 步骤 | 做什么 | 解决什么问题 | |------|--------|--------------| | **定位** | 找到三个角的「回」字方块,圈出二维码矩形范围 | 画面里有成百上千个东西,不知道该处理哪一块 | | **校正** | 把框出的矩形摆正,对齐每个格子 | 歪贴、倒贴、贴曲面时格子大小不一、方向不正 | | **译码** | 按顺序读出每个格子的颜色,剥掉掩码,翻译为 0/1 | 不知道怎样把黑白变成 0/1 | | **纠错** | 用纠错码验算,修复损坏的格子 | 弄脏、刮花、被 logo 盖住时数据可能不完整 |
四步缺一不可:组合起来才让二维码在真实世界里「**怎么贴都能扫、有点损伤也能扫**」。这也是二维码比一维条形码强大的根本原因——条形码只有一维、容错能力几乎为零,二维码则在二维平面上预埋了多层保护机制。
一句话总结
扫码就是「**先找位置,再摆正方向,然后翻译内容,最后兜底纠错**」——四步流水线依次跑过,黑白格子图变成手机里的链接。