二维码破损三成还能扫,纠错等级是怎么设计的

二维码破损三成还能扫,纠错等级是怎么设计的
二维码 30% 的破损容忍度,是 Reed–Solomon 冗余字节换来的硬指标。

一张被咖啡渍糊掉一角、被钥匙划出几道白痕的二维码,扫码枪往往照样「嘀」一声读出完整网址。常见说法是「二维码破损三成仍可识别」,这个数字不是玄学,是 Reed–Solomon 纠错码用实打实的冗余字节换来的硬指标——不过它按码字算不按面积算,四档纠错等级之间也差着好几倍,破损的位置比破损的比例更致命。先弄明白:扫一个「残缺」的码,手机要闯几道关。

先定位,再谈纠错

摄像头拍到的是一张斜了的、透视变形的、明暗不均的照片。二维码把定位信息做成了几何冗余:三个角上的「回」字形定位图形,黑白模块宽度比恒为 1:1:3:1:5,扫描器凭这个比例在任意角度都能认出「这是码的角」;连接定位图形的条纹状定时图形给出模块网格坐标;版本不低于 2 的码还散布着若干校正图形对抗镜头畸变。再加上把数据区打散成伪随机黑白纹理的掩膜,这一整套解决的是「码在哪、歪了多少、怎么掰回来」。掰回来之后,缺失和错读的模块,交给第四道保险:纠错码字。

Reed–Solomon 的账本:每纠一个错,预付两个字节

二维码在 GF(2⁸) 上运算,每个码字是一个 8 比特符号,长度信息被摊进有限域的多项式里:只要剩余的正确码字足够,就能反推出被破坏的部分。规则很干脆——设每块数据总码字数为 n、有效数据为 k,可纠错误数
t = (n − k) ÷ 2
以最小的 Version 1-L 为例:一个块 26 个码字,19 个是数据,7 个是校验,能纠正 3 个错误符号。8 比特一个符号,意味着某个字节哪怕只错 1 个 bit 和整个字节全花掉,在 RS 眼里代价相同——这也是它对「墨点糊掉一小块」特别宽容的原因。

四档等级,本质是冗余度的四档

同一张码,校验字节占比越高,能恢复的破损越多,但装得下的数据越少:L 档约恢复 7% 码字,Version 40-L 最多存 2 953 字节;M 档约 15%;Q 档约 25%;H 档约 30%,到 Version 40-H 只剩 1 273 字节。也就是说,选 H 等于拿近一半的容量买保险。实践中海报和链接码常用 M 或 Q;要往中心压 logo 的码必须上 H——那个 logo 遮掉的面积,就是靠这 30% 的冗余扛下来的;数据量大、印刷环境又干净的产品标签则退回 L,优先保容量。

「坏三成」的真相:按码字算,还要看怎么坏

纠错码字被分成若干独立的 RS 块,这是理解破损容忍度的钥匙。错误分两种:解码器知道坏在哪,叫擦除,每个只花 1 个校验码字;不知道位置、只能盲猜,叫错误,每个要预付 2 个。模块级的破损属于后者,所以 H 档的 30% 冗余只够纠约 15% 的错误码字,剩下的安全余量来自大码分块较多、破坏被摊薄。而破损形状决定生死:同样损失 30% 面积,均匀分布的墨点让每块都轻伤,RS 逐块修复,扫得出来;一道口子恰好贯穿同一列、把集中区域的码字连根拔掉,个别块超支,整码报废。至于「撕掉一角」能不能读,取决于丢掉的是不是定位图形和数据区边缘——三个回字少一个还能靠剩下两个工作,数据区被整角切走且落在同一批块里,神仙难救。

小结:宽容是预算好的,极限也是

二维码的耐用度 = 几何冗余负责找到码 + 纠错冗余负责补内容,两者都是设计时明码标价预算出来的:L/M/Q/H 对应约 7/15/25/30% 的码字恢复率,白边静区、对比度、定位图形则是不能省的底盘。想验证到自己头上很简单:用本站 /qrcode 生成一张 H 档的码,打印出来拿打孔器挨边打几个孔、再沿中线剪一道,逐一试试哪种坏法它还能开口。

← 等额本息和等额本金,到底哪个更省钱 Base64 是加密吗?为什么它反而让数据变大 →