二维码缺了一个角,为什么手机还能扫出来?不是魔法,是给答案准备了备份
先说结论
二维码缺了一个角还能扫出来,通常不是因为手机“猜得特别聪明”,而是因为二维码在写入真正内容时,顺手又写进了一批可以检查和修复错误的冗余信息。只要损坏主要落在数据区,且损坏没有超过纠错能力,扫描器就能根据剩下的黑白格把缺失内容算回来。
但“缺一个角”不是一个精确的技术指标。一个角如果只是数据区,可能还能恢复;如果刚好抹掉了左上、右上或左下的定位图案,损坏面积很小,扫描器甚至可能还没开始纠错,就已经找不到二维码的位置和方向了。

图 1:本文原创生成的主视觉。二维码像一段带校验线索的“黑白听写”,局部缺失不一定等于整段内容消失。
你可能见过这些场景:海报被撕掉一个角,二维码仍然能打开网页;快递单被胶带遮住一块,手机还是能识别;有人在二维码中间放了头像,扫码却没有受到太大影响。于是问题来了:二维码到底把答案藏在哪里?它为什么知道被遮住的地方应该是什么?
本文不把二维码纠错讲成一串只能背下来的公式,而是先做一次真实的本地实验,再把算法拆成日常生活中容易理解的“听写漏字”。你会看到:二维码的纠错码是什么、L/M/Q/H 四个等级意味着什么、为什么“30%”经常被误解、定位图案为什么比数据格子更重要,以及自己设计二维码时应该怎样留安全余量。
问题背景:二维码为什么不只存一份答案
最朴素的二维码可以想象成一张只写了一遍的黑白方格纸。黑格代表 1,白格代表 0,扫描器把这些格子读回来,再还原成文字、网址或其他数据。如果真的只写一遍,那么纸张被水滴盖住一块,原来的 1 和 0 就没有办法知道了。
所以二维码的设计没有只保存“答案”,而是同时加入了“检查答案是否被改动、必要时把答案补回来”的线索。这些线索不是把原文字再完整复制一遍,而是经过数学运算生成的一组校验码。它们和原始数据之间存在固定关系,扫描器可以利用这种关系反推出丢失或被读错的部分。
这和考试时在草稿纸上写下验算过程很像:最后的答案被墨水蹭掉一点时,老师不一定要凭空猜,而是可以根据前面的算式检查出哪个数字不合理。二维码的“草稿纸”就是纠错码。
二维码的规格公开后,形成了统一的编码标准。DENSO WAVE 的说明中把二维码的纠错实现描述为 Reed–Solomon Code,并列出 L、M、Q、H 四个等级;它还特别提醒,纠错能力按 codeword(码字)来表达,而不是简单按整张图的黑白面积来表达。
问题表现:缺角、遮挡和污点不是同一种坏法
先把“二维码坏了”分成四种情况,后面所有结论都会清楚很多。
数据区缺了一块
这是最容易出现“明明缺角却能扫”的情况。二维码右下角通常没有像三个角那样醒目的定位图案,更多是数据和纠错码字。扫描器先找到整体方向,再尝试恢复被遮住的码字。如果损坏没有超预算,恢复就可能成功。
中间放了一个小图标
中间遮挡看起来很危险,实际上常常比角上的定位图案更安全。二维码的黑白格不是按“从左到右、从上到下”简单存放的,数据会按照规定的路径放置,并经过交错;中间一个连续白块影响到的码字分布,未必等于同样面积的随机噪点。
随机散落很多小污点
随机污点可能比一块整齐的缺角更难处理。扫描器不仅要面对纠错问题,还要判断每个格子到底是黑还是白。相机模糊、反光和污渍会让“本来是黑格”的地方看起来像灰格,错误会从很多位置同时出现。
抹掉定位图案
二维码上通常有三个大方框:左上、右上、左下。它们叫 finder pattern(定位图案),作用像地图上的三个路标,用来告诉相机:“二维码在这里,边长大约是多少,方向是什么。”
定位图案不是普通内容。它们主要帮助扫描器完成检测、定位和几何校正。要是路标被抹掉,扫描器可能还没机会进入 Reed–Solomon 纠错阶段,就已经不知道应该从哪里读取数据了。
一次真实实验:不是画示意图,而是让本机真的去扫
为了避免“看图讲故事”,我在本机做了一个可重复实验:用 macOS 的 Core Image 生成相同内容、相同参数的二维码,再用 macOS Vision 框架的 QR detector 离线解码。实验没有上传到在线扫码网站,载荷也只是公开演示文本,不包含地址、主机名或秘密。

图 2:实验使用的完整二维码。它包含公开演示文本和 H 级纠错。
测试了四种纠错等级,并对二维码做了四类破坏:右下角逐步扩大缺口、中心遮挡、随机模块涂白、抹掉左上定位图案。这里的百分比表示“被涂白的模块面积”,不是标准所说的可恢复码字比例,这两个数字不能直接画等号。

图 3:右下角轻度缺损。在本次固定样本中,Vision 仍能恢复载荷。

图 4:缺口扩大到约 25.6% 模块面积时,本次 H 级样本仍然解码成功。这个结果只对本实验条件负责,不是所有二维码的承诺。

图 5:缺口继续扩大到约 35.7% 模块面积后,样本解码失败。纠错不是无限橡皮擦。
实验结果怎么读
本次固定载荷、固定尺寸、固定解码器的结果可以概括为:
| 破坏方式 | H 级样本结果 | 说明 |
|---|---|---|
| 右下角缺 10% 边长 | 成功 | 影响主要落在数据区,损坏面积约 1.1% |
| 右下角缺 50% 边长 | 成功 | 本次约 25.6% 模块面积,仍在此样本的可恢复范围内 |
| 右下角缺 60% 边长 | 失败 | 本次约 35.7% 模块面积,超过了可恢复范围 |
| 中心遮挡 20% 边长 | 成功 | 连续遮挡位置和数据交错方式共同影响结果 |
| 随机涂白 10% 模块 | 失败 | 错误分散且影响检测与采样,本机解码器未能恢复 |
| 抹掉左上定位图案 | 失败 | 只涂白约 1.1% 模块面积,却破坏了扫描入口 |

图 6:真实手机宽度浏览器截图,展示实验条件、载荷摘要和解码器信息。

图 7:真实截图展示“面积百分比”和“码字纠错能力”不能混为一谈。

图 8:真实截图展示逐项实测结果,PASS/FAIL 来自本机 Vision 解码输出。

图 9:真实截图展示实验表格中的二维码样本。

图 10:真实截图展示 L/M/Q/H 四种等级的对比记录。

图 11:真实截图展示报告后半部分,作为文章中的独立实验证据。
二维码里面到底有哪些区域
把一张二维码看成一座小城市,会比把它看成“很多随机黑点”更容易理解。
- 三个大方框是路标,帮助相机确认位置和方向。
- 靠近路标的一些小格子承担格式、版本和校正用途。
- 中间和剩余区域主要装数据与纠错码字。
- 最外面通常要留一圈白边,叫 quiet zone(静区),让扫描器知道二维码的边界在哪里。

图 12:二维码结构示意。颜色是为了讲解方便,并不代表真实二维码中的固定颜色。
DENSO WAVE 的版本说明显示,标准二维码从 Version 1 的 21×21 个模块开始,到 Version 40 的 177×177 个模块;版本越高,模块越多,能承载的数据也越多,但图案更密,对打印、拍摄和缩放质量的要求也会提高。
这也解释了一个常见误会:同样是“缺一个角”,小二维码和大二维码的实际影响可能完全不同。 缺口边长占二维码的比例、缺口碰到的是哪类区域、相机是否能稳定定位,都会改变结果。
Reed–Solomon 纠错:像给每组答案加上“验算线索”
Reed–Solomon 是二维码加入冗余信息的核心数学方法之一。它并不是把“原文复制一份”放到二维码后面,而是把一组数据当成数学对象,计算出一批校验码字。数据码字和校验码字之间有确定关系。
可以用听写来类比:老师读出“今天,天气晴朗,我和同学去公园玩”,你没有把整句话再抄一遍,但你知道“今天”后面通常接天气,“去公园”前面可能是“和同学”。句子的语境是额外线索,能帮助你恢复漏掉的字。
二维码的额外线索更严格:不是凭常识猜句子,而是检查哪些码字组合满足数学关系。它能纠正错误,也能在知道某些位置“不可靠”时恢复缺失信息。

图 13:把“上下文补字”类比成“纠错码补回码字”,但二维码使用的是严格的数学关系。
为什么要把数据打散
二维码的码字并不总是按视觉位置一一连续放置。编码过程会按照规则走遍模块,并对不同区块进行交错。这样做的好处是:如果纸张上出现一条横向划痕,错误不会只集中破坏某一小段连续数据,而可能被分散到多个码字组中,让纠错算法更有机会工作。
这也是为什么“看起来只是划了一条线”不能直接换算成“损坏了多少字”。视觉上的一条线,经过采样、模块判断、数据放置和交错后,影响的是一组具体码字;必须实际解码或按标准计算,才能知道是否超出预算。
L、M、Q、H 到底差在哪里
四个等级代表不同的冗余量。DENSO WAVE 给出的近似值是:L 约 7%,M 约 15%,Q 约 25%,H 约 30% 的总码字可以恢复;它同时说明,二维码工程中常用 codeword 作为单位,一个 codeword 是 8 bit。

图 14:本实验对 L/M/Q/H 的对比。色块只表示本实验样本的成功或失败,不代表普适阈值。
这里有三个必须记住的限定。
第一,“30%”不是图片面积保证
H 级的“约 30%”说的是总码字范围内的纠错能力近似,不是说你可以随便在二维码上涂掉 30% 的像素或模块。定位图案、静区和数据区承担不同职责;相同面积落在不同位置,结果可能相反。
在本次实验里,H 级右下角缺口达到约 25.6% 模块面积仍成功,但抹掉左上定位图案只损坏约 1.1% 模块面积就失败。这两个结果放在一起,正好说明“面积百分比”不能单独决定扫描结果。
第二,纠错等级越高,二维码通常越大或能装的数据越少
冗余信息不是凭空产生的。提高纠错等级,需要留下更多码字给校验线索;在同样内容下,二维码可能需要更多模块,图案会更密,或者在固定尺寸下可存的数据量下降。
这像考试时带更多草稿和验算纸:出错时更容易检查,但书包会更重,纸张也会占更多地方。
第三,扫描器也会影响结果
不同手机、不同相机、不同光线、不同缩放比例和不同解码库,对同一张损坏二维码可能给出不同结果。本文的 PASS/FAIL 是 Apple Vision 在固定图片上的实验记录,不应冒充所有 Android 手机、所有扫码应用和所有打印条件的保证。
问题根因:真正起作用的是三道保险
把整个过程拆开,二维码能“死里逃生”通常依靠三道保险:
第一道保险:找到二维码。 扫描器通过定位图案、比例关系和静区判断哪里是二维码,校正透视和旋转。
第二道保险:读准剩下的格子。 相机把黑白、灰度、反光和模糊的画面采样成模块,并根据掩膜、格式和版本信息解释这些模块。
第三道保险:修复读错或缺失的数据。 解码器把读取到的码字交给 Reed–Solomon 纠错流程,利用校验码字检查并恢复错误。
只要第一道保险断了,后面两道可能完全没有机会执行。只要第三道保险的预算用完,前面定位再准确也无法还原原文。
如何设计一个更耐损的二维码
虽然本文主要是科普,但这些原则对实际海报、标签和设备屏幕很有用。
- 不要遮挡三个定位图案。 如果一定要放 Logo,优先放在中心,且要用真实设备反复测试。
- 保留足够白边。 不要让文字、边框或其他图形紧贴二维码外沿。
- 根据环境选择纠错等级。 室内屏幕、干净纸张可以考虑 M;户外、物流、工厂等容易脏或磨损的环境可考虑 Q/H,但要接受图案更大、容量更低的代价。
- 不要只在高清原图上测试。 还要测试打印、缩印、拍照、反光、低亮度和部分遮挡。
- 把“能扫”定义成可重复。 至少用两台不同设备、多个角度和多种距离测试,不要只验证一次“刚好能打开”。
如果二维码承载的是付款、登录、设备配网或工单跳转等重要动作,还应该在业务层增加失效、签名、权限和重试机制。纠错码只能帮助恢复数据,不能证明链接安全,也不能阻止二维码被替换。
Q&A
Q:二维码缺了一个角,为什么手机还能扫?
A:因为缺角可能落在数据区,二维码中额外写入的纠错码字可以根据剩余内容恢复部分缺失数据;同时,扫描器仍然保留了足够的定位图案和几何信息。
Q:是不是 H 级就能随便遮住 30%?
A:不是。30% 是总码字纠错能力的近似表达,不是任意图片面积的通行证。遮挡定位图案、静区或造成严重反光时,可能在纠错之前就失败。
Q:为什么 Logo 放中间经常没问题,放角上却很容易失效?
A:三个角的方框是定位图案,负责让扫描器找到二维码和方向;中间通常更多是数据与纠错区。Logo 放置仍然需要根据实际尺寸和设备测试,不能只凭经验。
Q:同一张二维码,我的手机能扫,朋友的手机不能扫,谁对?
A:两者都可能正常。相机清晰度、曝光、对焦、图像增强、识别算法和二维码显示尺寸都会影响结果。工程上应把“最差目标设备”纳入验收,而不是只看一台手机。
Q:二维码能纠错,是否就不需要备份和重试?
A:仍然需要。纠错能力有上限,打印和显示还会受到缩放、反光、透视和污渍影响。重要场景应提供人工输入、备用链接或重新生成机制。
Q:Reed–Solomon 只用于二维码吗?
A:不是。它是一类通用的纠错方法,适合处理成组的符号错误和突发错误,历史上也用于光盘、通信和存储等场景。二维码只是把它放进了日常生活里,让我们用手机就能观察到“冗余信息如何救回缺失内容”。
参考资料
- DENSO WAVE:Error Correction Feature
- DENSO WAVE:Information Capacity and Versions
- DENSO WAVE:QR Code Standardization
- ISO:ISO/IEC 18004 QR Code 规范入口
二维码最有意思的地方,不是它“坏了还能扫”这么神奇,而是它告诉我们:一个系统如果提前为错误准备了可验证的备用线索,就不必要求每一个细节永远完美。 听写里漏掉几个字,句子上下文可以帮忙;二维码里丢掉几个码字,纠错关系可以帮忙。真正的工程智慧,往往不是保证永远不出错,而是让出错以后仍有机会恢复。