☰
Stable Diffusion+ControlNet艺术二维码调参与扫码验收
2026/10/26 12:55:30 网站建设 项目流程

第一次把一张画着猫咪的二维码发给朋友,对方扫了三次才打开,第四次直接甩过来一句“你这图是不是坏了”。那会儿我刚摸到 Stable Diffusion 加 ControlNet 这条路子,满脑子都是画面好看、构图漂亮,完全没意识到二维码本身还有一套硬邦邦的物理指标:模块尺寸、静区、纠错等级、对比度,任意一项踩线,前面画得再好看也是白搭。后来我前前后后跑了大概两百多组参数,帮一个开小店的朋友做了一版能贴在门口的扫码图,才算把这里面的门道摸清楚。

这篇内容讲的就是用 Stable Diffusion 配合 ControlNet 做出既有画面感、又能稳定扫码的二维码图。它解决的核心问题是:让一张艺术化的图片在保住二维码可识别性的前提下,把视觉信息藏进去,而不是简单粗暴地在二维码旁边贴个 logo。适合三类人看——刚装好 WebUI 想找点实战项目练手的新手、做线下门店物料想提升扫码率的从业者、以及想搞清楚 ControlNet 权重到底在干什么的中级玩家。基础操作我只在关键处提一句,重点全部放在参数怎么定、坑在哪里、怎么验收。

1. 拆解思路:二维码为什么能被“画”出来

1.1 二维码的可读性本质是一笔容错预算

很多人把二维码当成一张“黑白网格图”,其实更准确的理解是:它是一份带冗余校验的数据包。二维码有 L、M、Q、H 四个纠错等级,对应的冗余比例大约是 7%、15%、25%、30%。也就是说,一张 H 级码里面差不多有三成的数据是用来“自我修复”的,扫描器即使读到一部分错误的模块,也能通过里德-所罗门纠错算法还原出原始内容。

AI 画二维码之所以可行,根子就在这里。Stable Diffusion 在 ControlNet 的约束下往图上叠加纹理、光影、笔触,本质上是在“污染”一部分模块;只要污染量没超过容错预算,扫描器依然能读出来。这件事的边界非常清晰:你是在花一笔有限的预算,买画面的表现力。预算花超了,图就废了。

我第一次失败就是把预算花光了。整张图铺满了高频纹理,深色块和浅色块犬牙交错,扫描器拿到的二值化结果一团糊,纠错算法再强也救不回来。后来我给自己定了个粗糙但好用的经验值:画面纹理的覆盖面积不要超过整张图的三分之二,三个定位角(左上、右上、左下那三个“回”字形方块)周围 2 个模块宽度内必须是干净的,中间的数据区允许你自由发挥。

1.2 三条主流路线的取舍

在动手之前,先看清楚有哪几条路可以走,选错了后面全是无用功。

第一条是纯 img2img 重绘。把二维码当底图,低重绘幅度跑一遍。优点是上手零门槛,缺点也很明显:重绘幅度低了画面几乎不变,高了二维码就散了,中间那个“刚刚好”的区间窄得可怜,而且换个提示词就得重新调,完全没有可复现性。我试过十几组,能出图的比例不到两成,果断放弃。

第二条是 ControlNet 专用权重。这是目前最主流、也最稳的做法。社区里以“qrcode”为关键词能搜到几套在 SD1.5 上训练的专用权重,其中流传最广的那一版对黑白块的响应非常直接,权重拉到 0.9 以上基本能把二维码结构锁死。它的代价是画面容易被“格子化”,尤其是在权重过高的时候,出图会呈现出明显的马赛克感,需要靠提示词和后处理去柔化。

第三条是分层合成。先生成一张纯艺术图,再把二维码以低透明度、特定混合模式叠加上去,最后用蒙版把定位角贴回原样。这条路可控性最高,画面质量也最好,因为艺术图完全不受二维码干扰;缺点是它本质上不是“AI 画出来的二维码”,而是“AI 图 + 二维码”的合成,画面里没有那种模块与笔触交融的巧妙感。

我最终采用的是第二条为主、第三条收尾的混合策略:用 ControlNet 出主体画面,再用分层合成的手法把定位角和静区修补回去。这个组合把两边的优点都吃到了,后面第 5 章会详细讲。

1.3 软硬件与工具选型

硬件这块没什么好纠结的。SD1.5 加 ControlNet 在 8GB 显存的卡上跑 512×512 完全够用,出图速度大概两三秒一张,批量试错毫无压力。如果你手上是 6GB 的卡,把--medvram加上,速度会慢一些但不影响出图。想上 SDXL 的话显存最好 12GB 起步,而且 SDXL 生态里的二维码专用权重明显少,调参经验也不如 1.5 成熟,我个人的建议是新手先在 1.5 上把逻辑跑通。

软件侧我用的是 WebUI 加 ControlNet 扩展这套组合,原因是参数面板直观,改一个值立刻能看到效果,适合摸参数。ComfyUI 我也搭过一套工作流,节点连线的方式对批量生产和流程固化更友好,但学习曲线陡,第一次接触容易在节点连错上浪费半天。如果你只是想出几张图玩玩,WebUI 足够;如果你打算做成一条产线,比如给不同门店批量出图,那 ComfyUI 或者 API 脚本才是正解。

底模的选择经常被忽略,但它对成品率影响极大。写实风用写实类底模,插画风用二次元或扁平插画类底模,千万别拿一个二次元模型去生成“大理石纹理的二维码”,出来的东西又糊又花。我踩过这个坑,换底模之后同样的参数成品率直接翻倍。

提示:不要在同一个会话里反复切换底模试参数。不同底模对 ControlNet 权重的敏感度差异很大,混着试会让你对参数的判断完全失准。一个底模跑完一组参数,记下结果,再换下一个。

2. 关键参数:真正决定成败的那几个旋钮

2.1 ControlNet 权重与引导区间

ControlNet 的权重(Control Weight)是整件事里最敏感的一个参数。它决定了模型在多大程度上“听二维码的话”。

权重低于 0.6,模型基本放飞自我,二维码结构松散,扫不出来是常态;权重 0.7 到 0.9 是我实测下来成品率最高的区间,画面有表现力,结构也还在;权重超过 1.1,画面开始明显格子化,纹理被压平,虽然扫码成功率很高,但视觉上就是“一张上了色的二维码”,失去了 AI 生成的意义。

更精细的控制在引导区间(Guidance Start / End)。默认是 0 到 1,也就是全程约束。我的做法是把起点设在 0.1 左右、终点设在 0.75 到 0.85 之间。这么调的道理是:采样前期(0 到 0.1)让模型自由铺大色块和构图,中期(0.1 到 0.8)用二维码结构强力约束,后期(0.8 到 1.0)放开约束让模型把细节磨平、把噪点收干净。如果全程死锁到 1.0,最终图往往会显得脏、边缘毛糙,因为最后几步本来该做的是降噪细化,却被结构约束硬拽着走。

还有一个容易被忽略的开关:Control Mode。三个选项里,“平衡”是默认值,“更看重提示词”会削弱 ControlNet 的影响,“更看重 ControlNet”则相反。做二维码时我一般直接用“更看重 ControlNet”,因为我更怕结构丢失,宁可画面稍微硬一点,后期还能靠提示词修。

2.2 采样器、步数与 CFG

采样器这块不用迷信。DPM++ 2M Karras 是我用得最顺的,收敛快、细节稳,20 到 28 步就能出结果。Euler a 出图更“活”,画面更有随机感,但结构稳定性差一截,适合你已经把权重调到很稳、只想在画面风格上做变化的阶段。DPM++ SDE Karras 细节最丰富,缺点是同一组参数下每次结果差异较大,不适合需要复现的场景。

步数我一般设 25。低于 20 步时二维码边缘容易出现半成品的灰边,那些灰边在二值化的时候会变成随机噪点,直接吃掉容错预算。高于 35 步收益极小,纯属浪费时间。

CFG Scale 建议压在 5 到 7 之间。CFG 拉高会让模型更“听话”,画面饱和度飙升、对比度变大,看起来似乎更清晰,实际上暗部细节被压死,二维码的深色模块和浅色模块之间的过渡区被抹平,反而更难扫。我早期喜欢把 CFG 开到 9,觉得画面“有冲击力”,结果扫码率惨不忍睹。降到 6 之后画面柔和了,识别率反而上去了。

2.3 分辨率与模块尺寸的换算

这是最需要动手算一算的部分,也是最多人拍脑袋决定的地方。

二维码的尺寸不是一个抽象数字,它由“模块数 × 每模块像素”决定。模块数取决于你编码的内容长度和纠错等级。举个具体例子:一段二十来个字符的短链接,用 H 级纠错,大概落在版本 4 附近,也就是 33×33 个模块。加上四周各 4 个模块的静区(quiet zone,这是硬性要求,不能省),整张图是 41×41 个模块。

如果你出图尺寸是 512×512,那么每个模块分到 512 ÷ 41 ≈ 12.5 个像素,非常宽裕,随便画都不容易糊。但如果你的内容比较长,比如带了一串参数,模块数涨到 57×57,加静区是 65×65,512 ÷ 65 ≈ 7.9 个像素,还算能接受。再长一点,模块数到 77×77,加静区 85×85,512 ÷ 85 ≈ 6 个像素,这就进入危险区了——SD 在这个尺度上随便加一层纹理,就足以把一个模块吃掉。

所以我的第一条铁律是:能短则短。链接能压缩就压缩,参数能砍就砍,二维码版本每降一级,你的画面自由度就多一分。第二条是:出图分辨率往上提。768×768 出图再缩到 512 给 ControlNet,虽然 ControlNet 内部会做缩放,但最终成图的模块边缘会更干净。第三条是:模块像素低于 8 的时候,把 ControlNet 权重往上加 0.05 到 0.1,用结构强度换清晰度。

内容长度大致版本模块数(含静区)512 画布下每模块像素建议
短链接约 20 字符版本 441×41约 12.5随便画,容错充足
中等链接约 50 字符版本 649×49约 10.4正常参数即可
长链接带参数版本 1065×65约 7.9权重加 0.05,纹理收敛
超长文本版本 15 以上85×85 以上低于 6建议改短内容,否则不建议做艺术化

2.4 提示词怎么写才不浪费算力

提示词在这里的作用和普通出图不太一样。普通出图你是在“描述画面”,做二维码你是在“描述材质和光影”,因为结构已经被 ControlNet 锁死了。

我的模板大致是:主体描述 + 材质 + 光照 + 风格 + 质量词。比如做一张木质风格的,我会写“a wooden board with carved patterns, warm sunlight from the left, deep shadows in the grooves, cinematic lighting, high detail”。注意“deep shadows in the grooves”这类描述很重要,它在暗示模型把暗部做实,而实暗部正是二维码需要的高对比度。

负面提示词里我必加几个词:blurry、low contrast、washed out、grey haze、gradient。前三个好理解,重点是后两个——渐变是二维码的天敌,因为它会让模块边缘从黑到白平滑过渡,二值化时判定全凭运气。

另外一个反直觉的点:不要在提示词里写“qrcode”“barcode”“text”这类词。它们会让模型去“画一个二维码的样子”,而不是“在一个二维码上画画”,结果往往是在已经正确的结构上再叠一层图案,双重污染,必糊。

注意:提示词里出现“pixel”“mosaic”“grid”这类词也要谨慎。它们和二维码的模块网格会产生共振,出图会变得方方正正,画面表现力大打折扣。

3. 从零到一张能扫的图:完整实操流程

3.1 先用代码把底图生成好

底图质量直接决定上限。我的做法是用脚本生成,而不是用在线工具,因为脚本能精确控制版本、纠错等级、模块像素和边框宽度。

import qrcode from qrcode.constants import ERROR_CORRECT_H def make_qr(content, out_path, box_size=12, border=4): qr = qrcode.QRCode( version=None, # 自动选择最小可用版本 error_correction=ERROR_CORRECT_H, # 30% 冗余,给画面留预算 box_size=box_size, # 每个模块的像素数 border=border, # 静区宽度,单位是模块,4 是标准值 ) qr.add_data(content) qr.make(fit=True) img = qr.make_image(fill_color="black", back_color="white").convert("RGB") img.save(out_path) print("version:", qr.version, "modules:", qr.modules_count, "size:", img.size) make_qr("https://example.com/s/abc123", "qr_base.png", box_size=12)

几个参数值得说明。error_correction我固定用 H,因为它给画面留的冗余最多。有人担心 H 级会让版本变大、模块变多,反而更难扫,这个担心有一定道理,但在内容较短时版本差异只有一两级,H 带来的冗余收益远大于模块增加的损失。

box_size设 12 是为了让底图足够大。若最终模块数是 33,底图就是 (33+8)×12 = 492 像素,接近 512。这样缩放时不会引入插值模糊。如果你的模块数比较多,把 box_size 调小到 8 或 10。

border千万别改成 0 或 1。静区是扫码器定位二维码边界的依据,省掉它,很多扫码器会直接判定“这不是码”。我见过有人为了让画面更满把静区裁掉,结果就是扫不出来,还以为是模型的问题。

生成完之后,先别急着进 SD。用手机扫一遍底图,确认它能扫、扫得快。这一步是基准线,后面所有失败都可以拿它对照。

3.2 WebUI 里的参数落位

进入 img2img 页面,把底图拖进去。重绘幅度(Denoising strength)设在 0.65 到 0.8 之间。这个值为什么不能太低?因为低于 0.5 时模型几乎不改变原图,你只能得到一张“加了点噪点的二维码”;高于 0.85 时原图信息被冲掉太多,ControlNet 得独自扛下所有结构约束,画面会变硬。

往下拉到 ControlNet 面板,上传同一张底图。预处理器选none(因为你上传的已经是干净的二维码图,不需要再预处理),模型选二维码专用权重。控制权重 0.85,引导起点 0.1,终点 0.8,控制模式选“更看重 ControlNet”,缩放模式选“裁剪后缩放”或“仅缩放”,两者差别不大,但别选“缩放并填充”,那个会加白边,静区宽度就变了。

然后在最上面填提示词。我的建议是第一次先填最朴素的描述,例如“a watercolor painting of a mountain lake, soft brush strokes, natural lighting”,跑一张看看结构还在不在。如果扫得出来,再逐步加风格词;如果扫不出来,先降重绘幅度或加权重,别急着改提示词。

第一张图出来后,一定要做这两件事:一是用手机原生相机扫,二是用一个第三方扫码工具扫。原生相机对二维码的判定相对宽松,第三方工具更严格,两个都过才算真的过关。我第一次就是只用原生相机测,自己觉得没问题,发给别人全都不行。

3.3 批量跑图与种子管理

单张试参数效率太低,真正调参靠的是批量。我的做法是固定一个提示词,把 ControlNet 权重从 0.7 到 1.0 按 0.05 的步长扫一遍,每个权重出 2 张,一共 14 张,横向对比。

WebUI 自带 X/Y/Z 脚本可以干这事,把 ControlNet 权重填进 X 轴、随机种子填进 Y 轴就行。如果你的 ControlNet 扩展版本不支持在脚本里调权重,那就用 API 脚本跑。

import requests, base64, json, io from PIL import Image def to_b64(path): with open(path, "rb") as f: return base64.b64encode(f.read()).decode() url = "http://127.0.0.1:7860/sdapi/v1/img2img" payload = { "init_images": [to_b64("qr_base.png")], "prompt": "a watercolor painting of a mountain lake, soft brush strokes, natural lighting", "negative_prompt": "blurry, low contrast, washed out, gradient, grey haze", "denoising_strength": 0.72, "steps": 25, "cfg_scale": 6, "width": 512, "height": 512, "sampler_name": "DPM++ 2M Karras", "alwayson_scripts": { "ControlNet": { "args": [{ "input_image": to_b64("qr_base.png"), "module": "none", "model": "your_qrcode_model_name", "weight": 0.85, "resize_mode": 1, "guidance_start": 0.1, "guidance_end": 0.8, "control_mode": 1, "pixel_perfect": True, }] } } } for w in [0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00]: payload["alwayson_scripts"]["ControlNet"]["args"][0]["weight"] = w r = requests.post(url, json=payload).json() img = Image.open(io.BytesIO(base64.b64decode(r["images"][0]))) img.save(f"out_w{int(w*100)}.png")

这段代码里args的字段顺序会随 ControlNet 扩展版本变化,跑之前先去http://127.0.0.1:7860/docs看一眼你本地版本的定义,或者干脆用一次 UI 出图后抓一下请求体。别硬套别人的脚本,字段错位是最常见的报错来源。

批量跑完,文件名里带上权重,扫一遍挑出能扫的,再在能扫的那几张里挑好看的。这个顺序很重要——先保证功能,再挑美感,反过来会陷入“这张好看但扫不出”的纠结。

3.4 验收环节别偷懒

二维码的验收不是“我扫出来了”这么简单。我给自己定的验收清单是四条:

第一条,至少三台不同品牌、不同年份的手机,用原生相机各扫一次。老手机的摄像头解析力差、对焦慢,是最诚实的测试仪。

第二条,缩放测试。把图缩到原尺寸的 60% 再扫,模拟打印在小物料上的场景。很多图在屏幕上看没问题,一缩小就废。

第三条,打印测试。如果是线下物料,一定要打出来扫。屏幕是发光的,纸是反光的,两者的对比度表现完全不同。我做过一张深色背景的图,屏幕上扫得飞快,打印出来之后因为纸张吸墨、深色区域糊成一片,直接失效。

第四条,弱光测试。把屏幕亮度调到 40% 再扫。这一条最容易被跳过,但线下场景里灯光条件千奇百怪,能过这一关的图才算真的稳。

4. 常见问题与排查实录

4.1 六种典型失败与对应解法

扫不出来,但图看起来挺清楚。这种情况九成是模块边缘不够锐利。SD 出图天然带一层柔化,肉眼看不出来,二值化时就出问题了。解法是把图丢进任意图像工具,转灰度、拉一下对比度曲线,把暗部压到接近纯黑、亮部提到接近纯白,再扫一次。很多时候这一步就能救回来。

能扫,但要凑得很近。这是模块像素不足的典型症状。要么缩短内容降低版本,要么把出图分辨率提到 768 再缩放。

扫出来是乱码或者跳到别的链接。说明纠错算法在“硬猜”,猜错了。这是因为污染量刚好卡在容错临界点,纠错能力被消耗殆尽。解法是把 ControlNet 权重加 0.05,或者把重绘幅度降 0.05,让结构更硬一点。

三个定位角变形了。这是最致命的,定位角一旦破坏,扫码器连“这是二维码”都判断不出来。解法是后处理阶段把原图的三个角贴回去,具体做法第 5 章讲。

画面很漂亮但整体发灰。CFG 太低或者底模本身偏灰。把 CFG 提到 6.5,或者在负面提示词里加强washed out、low contrast的权重。

同一组参数,这次能扫下次不能。你用的是带随机性的采样器(比如 Euler a 或 DPM++ SDE)。换成 DPM++ 2M Karras,固定种子,结果就能复现。

4.2 一张速查表

现象最可能原因优先调整项调整方向
完全扫不出结构丢失ControlNet 权重上调 0.05~0.1
扫出但很慢边缘柔化后处理对比度拉曲线,压暗提亮
需要很近才扫到模块像素不足内容长度 / 分辨率缩短内容或提分辨率
跳到错误链接纠错临界重绘幅度下调 0.05
定位角破坏局部污染过重后处理贴回蒙版贴原图角
画面发灰发闷CFG 偏低CFG Scale提到 6~7
结果不可复现采样器随机性采样器换 DPM++ 2M Karras

提示:排查时一次只改一个参数。我早期图省事,同时改权重和重绘幅度,结果两组参数都有效果,但根本分不清是谁起了作用,白白浪费了一晚上的卡时。

5. 进阶玩法:分层合成与局部重绘

5.1 分层法:把功能区和艺术区分开处理

这是我目前最推荐的路线,成品率比纯 ControlNet 高出不少。

具体做法是:先用 ControlNet 正常生成一张图,然后在图像工具里建两层。底层是 AI 生成的图,上层是原始二维码,把上层的混合模式设成“正片叠底”或“叠加”,不透明度压到 15% 到 25%,让原二维码以一种极淡的方式“压”在画面上,起到强化结构的作用。这一步相当于给扫码器补了一份参考坐标。

接着处理定位角。用矩形选区把三个定位角(连同周围 2 个模块的静区)框出来,把上层的不透明度提到 100%,或者直接把原图对应区域复制过来覆盖掉。这样三个角恢复成绝对干净的纯黑白,扫码器定位毫无压力,而中间的数据区仍然是艺术画面。

最后做一次整体对比度微调。转灰度看一眼,如果暗部不够实,加一个曲线调整层,把 20% 以下的灰度值压到 5% 以内。

这套流程的好处是:画面质量由 AI 决定,结构可靠性由后处理兜底,两者互不干扰。缺点是多了几步手工操作,不适合大规模批量。如果你要做几十上百张,得把这几步写成脚本。

5.2 局部重绘修掉“坏点”

有时候整张图其他都好,就某个角落糊成一团。这时候不用整张重跑,用局部重绘(Inpaint)单独修那一块就行。

操作上,把糊掉的区域涂上蒙版,重绘幅度设在 0.3 到 0.4,ControlNet 保持启用,提示词写清楚那个区域应该是什么(比如“clean stone texture”),跑一次基本就能修好。关键是重绘幅度不能高,高了会把那块的结构也一起改掉,反而更糟。

我遇到过一个典型场景:画面右侧一块石头纹理生成得特别碎,正好压在几个数据模块上。整张重跑五次都没解决,局部重绘一次就搞定了,前后不到两分钟。

5.3 把整套流程脚本化

如果你需要给不同门店批量出图,每次内容不一样、风格不一样,那就得把流程串起来。我的做法是用 Python 把“生成底图 → 调 API 出图 → 后处理贴角 → 对比度增强 → 输出”串成一条链。

from PIL import Image, ImageEnhance def post_process(ai_path, qr_path, out_path, corner_ratio=0.22): ai = Image.open(ai_path).convert("RGB") qr = Image.open(qr_path).convert("RGB").resize(ai.size, Image.LANCZOS) w, h = ai.size cw, ch = int(w * corner_ratio), int(h * corner_ratio) # 左上、右上、左下三个定位角贴回原图 for box in [(0, 0, cw, ch), (w - cw, 0, w, ch), (0, h - ch, cw, h)]: ai.paste(qr.crop(box), box) # 对比度增强,压暗提亮 ai = ImageEnhance.Contrast(ai).enhance(1.25) ai.save(out_path, quality=95) post_process("out_w85.png", "qr_base.png", "final.png")

corner_ratio这个比例要按你的二维码版本调。版本 4 的码,定位角占整图的比例大概是 0.2 左右;版本越高,这个比例越小。贴多了会把数据区也盖住,贴少了定位角修不干净。建议先在一张图上试,用眼睛确认三个“回”字形完全清晰再批量跑。

6. 实操心得与几个容易被忽略的细节

折腾这么久,有几条经验是文档里不会写、但实际影响很大的。

第一,别迷信“权重越高越稳”。我见过太多人把权重拉到 1.2 甚至 1.5,图是能扫,但画面完全失去了生成的意义,就是一张上了色的格子图。真正的技术含量在于找到那个“刚刚能扫”的临界点,再往回退 0.05,留一点安全边际。

第二,颜色对扫码的影响比想象中大。深蓝配浅黄、深绿配米白这类组合,在屏幕上看着对比强烈,实际扫码时因为摄像头对某些波长的响应差异,识别率会掉。最稳的永远是深色接近黑、浅色接近白。做彩色版的话,深色那一端的明度要压到 25% 以下。

第三,中间的数据区可以“花”,边缘的静区必须“净”。静区是扫码器判断边界的依据,只要静区干净,中间稍微乱一点纠错算法还能扛。反过来,静区被污染了,扫码器连框都找不到,中间再规整也没用。所以构图的时候,尽量把画面的主体元素往中间放,四边留白。

第四,测试的时候别只用自己的手机。我用自己手机测了二十张全部通过,换了一台老机型测,通过率掉到六成。原因很简单,老机型摄像头解析力低、对焦慢,对边缘锐度的要求高得多。所以我现在的验收标准里,“老机型能扫”是硬指标。

第五,如果你想做的是那种“远看是画、近看是码”的效果,画面主体最好是有明确结构的物体——建筑、山体、人脸、几何图形都行,纯抽象的色彩泼溅反而不好用,因为它缺乏可以被模块边界“借用”的线条。模块的方格需要一个视觉上合理的理由来解释它为什么存在,这个理由越自然,成品看起来越不违和。

第六,别一次性投入太多时间在某一张图上。我早期会为了一张图反复调两三个小时,后来发现同样的时间够我跑五十张不同参数的图,从中挑一张好的。批量试错永远比精雕单张效率高,尤其是在你还没摸清参数区间的时候。

最后分享一个我最近在用的偷懒办法:把最终成图丢进任意一个二维码检测库跑一遍,拿到它的解码结果和纠错纠正次数。纠正次数这个数值特别有用,它直接告诉你“这张图离失效还有多远”。纠正次数为 0 或个位数,说明结构很稳;超过二十次,说明已经贴着红线了,换个场景打印或者换台设备大概率就废了。用这个数值做筛选,比人眼反复扫码靠谱得多,也快得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询