拍一页孩子的作业,手机和手挡住了光,纸上多了一大片阴影。
拍一本摊开的书,靠近装订线的位置弯了起来,文字也跟着变形。
整理讲义和笔记,照片倒是拍了不少,但有的偏暗、有的发灰,放到一起看,实在不够舒服。
这些事情都不大,却经常遇到。所以这次,我把之前做文档去阴影的想法往前推进了一步,做了一款可以直接在 Windows 上使用的桌面软件:
文档修复工具箱 · DocRes Vulkan。
它把弯曲展平、去阴影、去模糊、外观增强、黑白二值化放在了一个界面里,支持单张处理、文件夹批量处理,还能把结果整理成多页 PDF。
界面用 C# WinForms 编写,神经网络通过 C++ Vulkan 在本机 GPU 上运行。同时整理了可直接运行的部署包和完整的 VS2022 源码工程,方便使用,也方便继续研究。

软件实际运行界面:左侧原图,右侧修复结果
先看一个实际效果
下面这张图片来自 DocRes 官方项目的示例。原图纸面上有很明显的阴影,左侧和中间部分较暗。

DocRes 官方去阴影示例原图
使用本工具的 Vulkan 后端,选择"去阴影",处理上限设为 512,得到下面的结果:

本工具实际生成的 Vulkan 去阴影结果
可以看到,大块阴影得到了明显改善,纸面的明暗更均匀,彩色笔迹也保留了下来。
这组图片是实际处理结果。不同照片的阴影、曝光和文字大小不同,效果也会有差异,大家可以先拿自己的图片试一张,再决定批量处理的参数。
五种功能,可以单独用,也可以组合
软件基于 DocRes 官方开源项目(github.com/ZZZHANG-jx/... 是 CVPR 2024 的文档图像修复研究,官方实现支持展平、去阴影、外观增强、去模糊和二值化等任务。
在桌面工具里,这些能力对应五个选项:
| 功能 | 适合的情况 |
|---|---|
| 弯曲展平 | 书页弯曲、页面内容随纸张发生变形 |
| 去阴影 | 手、手机或环境光造成纸面局部发暗 |
| 外观增强 | 纸面颜色和整体观感需要进一步整理 |
| 去模糊 | 尝试改善模糊文档中的文字与边缘 |
| 二值化 | 把页面转换成黑白图,方便打印或后续处理 |
如果只是光照不好,可以单独去阴影;如果希望保留彩色批注,就先看去阴影和外观增强的结果。
软件也提供了官方组合:
弯曲展平 → 去阴影 → 外观增强。
对于问题比较多的页面,还可以自定义勾选步骤。界面会按"展平 → 去阴影 → 去模糊 → 外观增强 → 二值化"的顺序执行,二值化放在最后。
建议先选最需要的一两项。每增加一个步骤,都会增加计算量,处理效果也需要结合原图判断。
普通用户怎么使用?
完整解压部署包,双击 Run.cmd 或 DocRes.WinForms.exe 就能打开。
运行环境是 Windows x64、.NET Framework 4.8,以及支持 Vulkan 的显卡和驱动。部署包带有模型和运行库,无需配置 Python、CUDA、OnnxRuntime 或 Vulkan SDK。精简版 Windows、N 版或 Server 系统还需具备 OpenCV 运行所依赖的 Media Foundation 等系统组件。
模型和图像处理都在本机执行,运行时不需要在线下载模型,也不需要把文档上传到服务器。
第一次使用,可以按下面的流程操作:
- 选择"单张图片",导入一张照片。
- 选择修复任务,比如"去阴影"。
- 选择 GPU,处理上限先保留默认的 512。
- 点击"开始修复",在界面中查看原图和结果。
- 到输出目录查看图片和 PDF,确认效果后再处理整批资料。
处理上限会影响速度、显存和细节。对于小字很多的页面,降低上限可能损失细线和文字细节;增加上限则会增加计算量和显存需求。
输出图片保留原图宽高,并不代表网络始终按原图分辨率进行修复。 例如,去阴影会在设定尺寸预测校正信息,再恢复到原图;去模糊和二值化超过上限时,会先按比例缩小处理,再恢复尺寸。
所以这个参数最好结合自己的资料试一下,不必一上来就调到最大。
几十张照片,也能一起整理
单张确认效果后,切换到文件夹模式,就可以批量处理。需要时可以勾选"包含子目录"。
批量模式会保留子目录结构,记录每张图片的完成或失败状态。输出名带有原图内容和任务参数的摘要,修改原图或处理配置后,会生成对应的新结果。
勾选"跳过已有结果",再次执行相同任务时,就能复用已经完成的图片,适合分几次整理一大批资料。
默认目录也做得比较直接:
bash
./输出 修复图片和 PDF
./工作区 任务记录,可选的中间图片和提示图
./cache GPU 管线缓存
这些路径都相对软件 exe 所在目录解析。整个软件文件夹换个位置,内置模型和默认目录依然可以按相对路径找到。
图片可以保存为 PNG 或 JPEG。准备打印黑白文档时,建议二值化结果使用 PNG,避免 JPEG 压缩重新引入灰阶和边缘杂点。
从图片到 PDF,少一步来回折腾
处理完成后,软件可以同时生成多页 A4 PDF,一张图片对应一页,保持宽高比,并根据图片方向选择横页或竖页。
也可以使用"另选图片合成 PDF",把已经整理好的图片按文件名顺序合并。建议提前用 001、002、003 这样的名称整理页码。
PDF 按页面逐张写入,不需要把整批图片都长期留在内存里。独立的 PNG/JPEG 结果也会保留。
当前导出的是图片型 PDF,适合阅读、归档和打印,暂未加入 OCR 文字层,因此不能直接搜索或复制页面中的文字。
背后的技术:任务提示 + Vulkan 推理
这部分留给喜欢看实现的朋友。
DocRes 的一个特点,是把原图和不同任务的提示图一起送入网络。本版主网络的输入由三通道 BGR 图像和三通道任务提示组成,总共六个通道。
这里的提示是图像信息。例如,去阴影使用背景相关提示,去模糊使用边缘相关提示。程序根据用户选择的任务准备输入,再按该任务解释网络输出。
一次完整处理大致是:
读取图片、校正 EXIF 方向
↓
按任务生成提示图、调整处理尺寸
↓
上传张量,执行 Vulkan 神经网络
↓
取回输出,重建原尺寸结果
↓
保存图片、生成 PDF、记录任务
神经网络算子由 C++ Vulkan 后端执行;提示图生成、形态学处理、坐标平滑和图像重采样由 CPU 上的 OpenCV 完成。
其中,"弯曲展平"还会先使用 MBD 模型取得页面分割信息,再通过 DocRes 预测坐标变化,把原图重新采样到展平后的页面。
当前实现采用 FP32 推理,并对同一输入做过官方 PyTorch FP32 数值对照。DocRes 在所测 256×256 输入上的最大绝对误差约为 1.43×10⁻⁶。这是网络数值对齐检查,实际文件的最终结果还会受到解码、缩放和前后处理的影响。
Vulkan 提供了跨厂商 GPU 计算的基础,但不同显卡仍需分别验证。目前的功能与耗时记录来自本机 RTX 4060 Laptop GPU,不把这个结果直接当作所有设备的表现。
实际运行要多久?
下面是本机 RTX 4060 Laptop GPU、Vulkan FP32 的短测记录,使用各任务对应的官方示例,连续运行两次,取第二次会话已准备好的数据。
| 任务 | 网络处理尺寸 | 网络 Run 耗时 | 阶段总耗时 |
|---|---|---|---|
| 去阴影 | DocRes 512×512 | 约 686 ms | 约 930 ms |
| 外观增强 | DocRes 512×512 | 约 686 ms | 约 1002 ms |
| 去模糊 | DocRes 200×200 | 约 110 ms | 约 111 ms |
| 二值化 | DocRes 512×280 | 约 378 ms | 约 392 ms |
| 弯曲展平 | DocRes 256×256 + MBD 448×448 | 约 169 + 42 ms | 约 426 ms |
这里的 Run 包含数据上传、网络执行、同步和下载;阶段总耗时还包含提示生成与结果重建。表中不包含最终图片编码、落盘、PDF 和界面预览,且各行图片和任务不同,不适合互相比较快慢。
首次处理某个尺寸还需要准备 GPU 管线,可能等待几十秒。已有记录中,DocRes 256×256 首次无缓存准备约为 42 秒;同进程后续同尺寸处理会复用,重新启动时也会尝试使用磁盘缓存。
显存方面,512×512 DocRes 的中间张量工作区约为 1544 MiB,还要加上权重、传输缓冲、其他模型和驱动开销。这个数字是其中一部分内存,并非整卡显存占用。
日常使用可以先选"均衡"资源模式。资源模式通过在图片之间安排等待来调节连续处理节奏,单次 GPU 推理仍可能满负荷执行。
最近也补上了手机照片的小细节
有些手机照片看起来是竖图,文件内部保存的却是横向像素,查看器通过 EXIF 方向标记把它转正。如果软件只读取像素而忽略标记,选图后就会横过来。
最新 r1.1 已统一处理 EXIF 的旋转和镜像方向,让预览、推理和 PDF 使用一致的方向。同时修复了部分照片受 DPI 标记影响而放大裁切的问题。
这些细节未必显眼,但会直接影响软件拿到手之后是否好用。
想继续开发,也准备好了完整工程
源码提供完整 VS2022 解决方案,包含 C# WinForms 和 C++ Vulkan 核心项目。
WinForms 使用 .NET Framework 4.8 ,界面保留标准 .Designer.cs,可以继续在设计器里调整布局。安装对应的 .NET 桌面开发、C++ 桌面开发组件和 .NET 4.8 目标包后,打开解决方案,选择 Release | x64,将 DocRes.WinForms 设为启动项目即可编译运行。
工程带有正常构建所需的 Vulkan/OpenCV 头文件、库和离线模型。普通编译无需配置 Python 或重新导出模型;修改模型导出流程或重新编译 Shader 时,再使用相应开发工具。
目前整理的 r1.1 部署包约 226 MiB ,完整源码包约 229 MiB。模型、上游代码和第三方组件的来源与许可声明也随工程保留。
如果你也喜欢折腾 C# 桌面程序、图像处理和 GPU 推理,欢迎一起交流:
QQ群:天天代码码天天
群号:264292622
最后也说一下使用预期:严重模糊、过曝或被遮挡的内容,无法保证恢复正确。处理作业、公式和重要资料时,建议保留原图,放大核对文字细节。
我希望这样的工具,既能方便整理一份讲义、一本笔记,也能让开源模型更容易被普通人用起来。