关于二维码,流传最广的一条说法是:毁掉大约30%的面积,它照样能扫。中间塞个logo、停车牌被蹭花还能用,靠的都是这个。
有人把这件事真的跑了一遍。他按四种纠错等级生成二维码,用受控的方式破坏,再把每一张受损图像喂给真实的解码器,每个数据点跑两百次。
![]()
结论是:这条民间说法在一种特定情况下成立,在其他所有情况下都严重误导。二维码坏在哪里,比坏了多少重要得多。
贴纸盖住15%,没事
先看大家想象中的那种损坏:一整块实心遮挡,比如箱子上贴的标签,或者咖啡杯留下的一个圈。他把数据区的一块方形盖住,每次把遮挡块挪到随机位置再尝试解码。
在纠错等级H下,用贴纸盖住符号15%的面积,它几乎每次都能扫出来。这就是那条民间说法描述的画面,它确实成立。
但换成同样总量的分散损伤,故事就完全变了。
散落的污点超过3%,直接死
同样的损伤面积,不打成一块,而是随机翻转整个符号里的单个模块——灰尘、印刷噪点、糟糕的摄像头,造成的都是这种图案。
3%的分散损伤,比15%的整块遮挡更致命。到了5%,所有等级全部阵亡。
原因在于纠错不是按像素工作的,它按码字工作,每个码字八个模块。一整块遮挡只会彻底毁掉少数几个码字;同样数量的分散模块,毁掉的码字最多能到八倍,因为每一个散点都落在不同的码字里。解码器数的不是受损面积,是受损码字,而分散正是花掉损伤预算最高效的方式。
真正让人意外的地方在1%那一列:纠错等级H——可用的最强纠错——表现反而不如等级M,44%对74%。
这不是错误。等级H需要更多空间放冗余,同样的数据量会生成更大的符号:33×33模块,而M是25×25。更大符号的1%,模块数量更多,而分散模块恰恰是摧毁码字的元凶,所以更强的码在同一个百分比下吃掉了更多损伤。
按百分比说,更强的纠错让它更脆弱;按绝对值说,H纠正的仍然更多。两句话都对,而人们引用的是百分比那一句。
0.7%,一击致命
上面破坏的都是数据区。现在说结构。
二维码并不均匀。在他测试的符号里,大约四分之一的模块——1089个中的260个——是固定家具:三个角上的大方块、连接它们的虚线、描述格式的条带。他是靠经验找出来的:用同样的尺寸生成三百个不同内容的二维码,标出每一个从未变化的模块。
这些家具没有一个受纠错保护。它们正是解码器用来找到二维码的东西。
0.7%。一条细细的模块线,二维码就彻底读不出来——而同一个码,能扛住二十倍于此的贴纸。
那条线是连接两个角方块的虚线。解码器靠它算出网格间距,没有它,就没有东西可以用来丈量符号的其余部分。数据区再多的冗余也帮不上忙,因为数据根本到不了。
他自己踩过的坑
第一轮测试,他用了一个自己其实没在用的纠错等级。
等级L和等级M的结果一模一样——不是接近,是精确到小数位相同。两百次随机试验,两个都是50.5%,这不是巧合,是信号。直接比对两个矩阵:零个模块不同。
他用的库会在同一个符号尺寸能塞下更强等级时自动提升纠错等级,这个行为合理,而且默认开启。所以请求等级L,实际悄悄给了等级M,他最弱的数据点从未被真正测量。上面所有数字都来自关闭该提升后的重跑,关掉之后,L和M在同样损伤下正常分开:47%对97%。
如果你要把二维码印在东西上
二维码会进入真实世界而不是只待在屏幕上时,用等级H——这是扛住15%贴纸和5%就死之间的差别。
不要把logo打散。中间放一整块实心图形接近最优;同样面积撒在整个符号上接近最差。
优先保护三个角和它们之间的两条虚线,高于一切。那里百分之零点几的损伤就是致命的,而那恰恰是人们裁掉、磨圆或印上东西的地方。
由此还能得出一个实用的排查顺序。当现实中的二维码扫不出来时,直觉是以为它太脏或太旧,于是重新印个更大的。数据说明这通常是错误的第一反应,因为灰尘必须分布得极其均匀,才能击败等级H符号的纠错;而一个被贴标机切掉一角的码,或者底边被安装支架裁掉的牌子,会直接干掉一个定位图案或一条定时线,让人看着几乎没坏,却彻底读不出来。
所以先检查边缘和角落,再检查表面。如果你负责放置二维码,给它四周留出安静的边距,让任何装饰都远离那三个方块,因为在那片区域,不到百分之一的损伤,就是二维码能用很多年和从来没能用之间的差别。
代码、图像和原始数据在 github.com/DimitrovK/qr-damage,想复跑可以去取。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.