文档照片去阴影与边缘推理部署示意

2026 年 10 月读到一份开源项目的介绍:作者用纯 C# 做了一个文档照片去阴影的推理实现,把 GCDRNet 这一类两阶段模型(光照估计网络 GC-Net 加上阴影去除网络 DR-Net)压成两个约 21 MB 的 ONNX 文件嵌入程序集,在 RTX 3080 Ti 上跑 Vulkan 后端做到单张端到端约 9.6 毫秒,同一套代码还能编译成 WebAssembly 在浏览器里多线程跑。这类东西我们做过类似的事,知道它难的不是网络结构,而是把一个论文模型变成产线上能天天跑的函数。下面讲我们自己的判断。

一、传统算法修不好的到底是哪一段

光照不均的校正在 CV 工具箱里有好几把老钥匙:灰度世界假设做白平衡、形态学或大面积滤波估背景再做除法归一化、同态滤波把照度分量和反射分量在频域上拆开各调各的增益。这些方法各自的隐含假设都很脆:白平衡假定画面整体反射是中性灰,而档案扫描件往往是大面积米黄纸张;背景估计假定阴影边界是低频的,而百叶窗投影、手指压纸的接触阴影是高频硬边;同态滤波对周期性条纹光照还行,对局部块状遮挡几乎不动声色。

更要命的是任务目标变了。以前我们做去阴影是为了”人眼看着顺眼”,容忍度高;现在扫描件下游是 OCR,判断标准变成”字符连通域能不能分干净”。阴影边缘那一圈低频过渡带,在灰度直方图上和浅灰底色重叠,阈值化时会被并进背景,于是整段文字连成一片。这类错误不是强度问题而是拓扑问题,传统滤波拿不到”这块区域下面本来是有字的”这种信息,只有训练过成对数据的网络才有。项目介绍里那组数字正好说明了差别:同一张图,原图识别出 56 行、762 个字符,增强之后是干净的 14 行。多出来的那几十行基本都是阴影边界和透印被误判成的”文字”。

二、神经网络方案真正卡人的三件事

模型选型的痛苦通常不在精度曲线上,而在工程三件套上。

体积与分发。 视觉增强模型的性价比拐点很小。一个 20 MB 出头的两阶段网络能把扫描件可用性拉起来,而把同样的事交给通用大模型,光传输和加载就把边缘场景的预算吃光了。这里有个细节值得学:权重作为嵌入资源随程序集走,版本跟引擎解耦,现场升级不再需要单独拷模型目录。我们以前踩过”程序更新了、模型没更新,输出静默变差”的坑,嵌入分发是一次性解决它的办法。

后处理与像素搬运。 增强网络的输出要回到原来的内存布局才能喂给 OCR。真正被忽略的成本是 stride 对齐、色彩格式转换和 pad 的还原。这类模型的输入需要 pad 到 32 的倍数再裁回去,如果实现里把 pad 当成”每次调用重新分配一块大数组”,延迟会直接翻倍——注意,这是我们的经验值,原文只说明了对齐规则,没给出这层的耗时拆解。

跨端推理栈。 一旦要覆盖 Windows 工控机、macOS、浏览器、国产化环境,”绑死 CUDA 加 Python”这条路就走不通了。原文给出的后端是 Vulkan、Metal、WebAssembly 与 CPU 四选一,CPU 侧靠 AVX-512、ARM NEON 和 PackedSimd 写卷积微内核。我们的判断是:这类”一套算子、多后端”的路线,价值不在于比专用推理引擎更快,而在于把依赖面从”运行时 + Python + 驱动 + 模型服务”缩到”一个可执行文件”。故障现场少一层,运维成本就少一层。

三、9.6 毫秒该怎么读

这个数字很容易被拿去当卖点,但它有三个约束必须一起说。原文的表述是:在 RTX 3080 Ti 上,一张 1600×1152 的图,Vulkan 后端端到端(含上传下载和前后处理)约 9.6 毫秒。也就是说这是单张口径,不是批量吞吐。原文明确写了不支持批量推理(N > 1)。

这一点在做容量规划时差别巨大。文档扫描是典型的长尾串行负载:一次会话进来十几页,页与页之间有操作员翻页的空档。这种负载下,单张延迟比吞吐更重要,因为决定用户等待感的是”按下扫描到预览刷新”这一段。反过来,档案数字化外包厂是每天数万页的离线批处理,N > 1 的批量能力才有意义,此时这套方案就要重新评估,或者在服务端做请求级并发来凑。

还有两个口径要留意。第一,GPU 侧用 fp16 存储,输出与 CPU 路径存在 2 个 u8 等级以内的差异,意味着同一份验收规则不能只在一个后端上跑通就算数。第二,浏览器里没有 GPU 后端,多线程 WebAssembly 还需要 COOP / COEP 头。这两条把”客户端零部署”这个卖点划出了很明确的使用边界。

四、四种部署形态的适配判断

下面是洹拓科技给工业质检和档案数字化项目做形态选择时的判断表。成本列写的是相对量级而不是金额,因为各省机房与显卡行情差异太大,金额反而失真。

部署形态 适配条件 成本量级 典型失效场景
云端 GPU 服务 集中式扫描中心、需要多租户共用、模型可热更新 高(常驻显卡 + 带宽) 涉密档案不允许出域;单张图上传往返远超 9.6 毫秒的推理本身
工控机 / 本地 GPU 已有带独显的采集工作站,离线可用是硬要求 中(一次性硬件) 现场只有核显或国产化主机,Vulkan 驱动版本残缺
浏览器端 WASM 扫描软件不便装机、需要给外部录入员临时开放 低(复用现有 Web 服务器) 多线程需要 COOP/COEP,嵌入旧内网系统时跨域策略打不开;无 GPU 后端,大尺寸图明显变慢
移动端 / 边缘盒子 现场用手机或手持终端直接采集 低到中 手机 SoC 内存吃紧,1600×1152 以上分辨率需要先在端上做尺寸收敛

我们的偏好排序很朴素:数据敏感、量大、有固定工作站——本地 GPU;要快速发人、临时使用——浏览器端;只有当多团队共用且允许出域时才上云。

五、上线前我们坚持要量的四个指标

任何去阴影模块进入生产环境之前,这四个数没测出来就不签验收:

  1. 端到端 P95,而不是平均值。 包含采集、pad、推理、色彩回写、内存分配,逐段打点;平均值好看往往是被预热的第一张拉低的。
  2. OCR 行级错误数而非”看起来更亮”。 用行数和字符数这种可判定的量做前后对照,避免用主观观感验收。
  3. 跨后端一致性。 同一批图分别在 CPU、GPU、浏览器上跑,比对差异分布;fp16 与 SIMD 微内核带来的小偏差在阈值边界上会被放大。
  4. 极端尺寸的行为。 超宽幅图纸、超长接龙页在 pad 到 32 倍数时的内存峰值要实测,别把 OOM 留给现场。

去阴影这件事的技术含量,一半在模型,另一半在把模型变成”一个不需要解释的函数”。纯托管加多后端这条路线我们认可,因为它把可交付性放在了性能前面。但把它摆进产线时,仍然要按单张口径算延迟、按数据合规选形态、按行级指标验收。这三步都做完,那 9.6 毫秒才真正变成产能。