OCR(Optical Character Recognition)传统是云端能力——图片传上去,服务端跑大模型,结果传回来。本工具反其道而行:模型权重 + 推理引擎全部塞进浏览器,原图永不离开你的电脑。这条路怎么走通的?
一句话架构
图片字节 → DBNet 检测网络 → 文本框坐标列表
→ CRNN + CTC 识别网络(逐框)→ 字符序列
→ 联动 UI 显示
两个神经网络都是用 PaddleOCR PP-OCRv4 mobile 训练,导出成 ONNX 格式,由 ONNX Runtime Web 在浏览器 WebAssembly 后端推理。整套流水线总共 27 MB 静态资源,首次下载后浏览器缓存。
第一段:检测(DBNet)
任务:输入一张完整截图,输出”哪里有文字”——一组矩形(或多边形)坐标。
PP-OCRv4 检测用的是 DBNet(Differentiable Binarization Network),架构是:
MobileNetV3 backbone → FPN(特征金字塔)→ 二值化分支
输出一张和原图同尺寸的概率图,每个像素值 0-1 表示”这里属于某个文字区域的中心”。后处理用 OpenCV 的轮廓检测把概率图变成多边形坐标。
关键参数:
- 输入分辨率 640 × N(短边 640,长边按比例)
- det_db_thresh 0.3:像素被算作文本中心的阈值
- det_db_box_thresh 0.6:整个框被保留的阈值
- det_db_unclip_ratio 1.5:把多边形向外扩张的倍数(避免裁掉笔画末端)
工具页加 ?debug=1 能直接看到这张概率图的热力图,对调试漏检很有帮助。
第二段:识别(CRNN + CTC)
任务:输入一个裁剪好的文本框小图(高度 32 px),输出字符序列。
PP-OCRv4 识别用的是经典的 CRNN(Convolutional Recurrent Neural Network):
MobileNetV3 → 双向 LSTM → 全连接层 → CTC 解码
CTC(Connectionist Temporal Classification)是关键——它解决了”输入特征序列长度不等于输出字符长度”的问题。具体做法:
- 把图片宽度切成 N 个 token(每个 token 对应几个像素列)
- 每个 token 独立预测字符概率(含一个特殊”空白”符号
-) - 解码规则:相邻重复字符合并(
hheelloo→hello),删除-
这样模型不需要标注”第 5 个字符在哪一列”,只要给它一张图和正确的字符串,它自己能学出来。
字符表 6622 字 + 1 个 blank,对应 6623 维 softmax 输出。
为什么用两阶段而不是端到端
学术界一直在做端到端 OCR(输入完整图,直接输出全部文本),但工业实践里两阶段更稳:
| 维度 | 两阶段 | 端到端 |
|---|---|---|
| 训练数据 | 检测 / 识别可独立扩充 | 必须配对完整标注 |
| 错误隔离 | 漏检 vs 错字可分别归因 | 黑盒,难调试 |
| 长文本 | 框大小可任意 | 受输入分辨率限制 |
| UI 联动 | 天然有 box 坐标 | 需额外注意力图 |
| 模型体积 | mobile 版 15 MB | 端到端通常 50 MB+ |
代价是检测错了识别就跟着错——但失败模式可解释,运维更容易。
为什么不上 WebGPU
ONNX Runtime Web 支持三个后端:
| 后端 | 速度 | 兼容性 |
|---|---|---|
| WASM (SIMD) | 1× 基线 | Chrome / Firefox / Safari 全部 |
| WebGL | 2-3× | 主流,但精度有损 |
| WebGPU | 3-5× | Chrome / Firefox 已稳定,iOS Safari 仍 flag 内 |
截至 2026 年初,iOS Safari WebGPU 还在功能开关后面。如果切到 WebGPU 后端,iPhone 用户会全员降级到 WASM——还多一段 fallback 逻辑。为了兼容性放弃了 3-5× 加速,等 iOS 全量推开再说。
27 MB 都装了什么
| 文件 | 大小 | 作用 |
|---|---|---|
det_model.onnx | 4.5 MB | DBNet 检测网络权重 |
rec_model.onnx | 10.3 MB | CRNN 识别网络权重 |
dict.txt | 26 KB | 6622 字符表 |
ort-wasm-simd.wasm | 12 MB | ONNX Runtime SIMD 版 |
加起来约 27 MB。首次下载后浏览器 HTTP 缓存——下次访问只校验 ETag,不重新传输。25 MB 这个大小放本地软件不算什么,但放浏览器初次访问比较显眼,好在只一次。
iOS Safari 的特殊兜底
WebAssembly 在 iOS Safari 里有一个长期 bug:模块化 Worker(type: "module")在某些情况下会丢失主线程消息状态。早期版本工具页在 iOS 上识别会卡死或返回空结果。
修复路径(见 commit 1648cba):
- 降级到经典 Worker:
new Worker(url)不带type: "module" - recognize 自动重试:单帧识别失败重试一次,避开偶发的状态丢失
- 诊断面板:
?debug=1显示推理步骤耗时,定位卡在哪一段
iOS 16 以下偶发,iOS 17+ 几乎不见。Android Chrome、桌面端从未触发过。
准确率天花板
通用印刷体可达 92-95%,但下面几类永远过不去:
- 手写体行草:< 50%,模型训练集没有这种数据
- 艺术字 / Logo:不稳定,字体扭曲超出训练分布
- 小于 16 px 的字:检测网络分辨率限制,根本看不见
- 字典外字符:罕见汉字、化学符号、emoji 会被替换成形近字
要更高需要垂直模型——发票字段、身份证号、车牌——百度/阿里云的付费 OCR 在这些场景能做到 99%+,但他们的模型几个 GB,浏览器扛不动。本工具定位是通用、隐私、零成本,不是医疗/金融级精度。
怎么验证真的不上传
打开 OCR 工具,按 F12 → Network 面板:
- 勾选 “Disable cache”
- 刷新页面,看到 5 个对
/libs/paddle-ocr/*的同源请求(首次 27 MB) - 拖入一张图片识别
- 整个识别过程应该 0 个新出站请求
如果你看到任何对外 IP 或域名的请求,那是有问题。我们的承诺是:图片字节、识别结果永远只在浏览器内存里,刷新页面立即释放。
用得对、用得省
- 大批量同质图片(如几百张同款发票)→ 还是去用百度云 OCR + 字段抽取,本地通用模型不划算
- 临时几张敏感截图 → 这工具是最优解,不上传 + 离线
- 需要导出 JSON/坐标信息 → 当前版本不支持,仅复制文本
- PDF 文件(文字层)→ 用 PDF 提取文字,比 OCR 快百倍且无错
- PDF 文件(扫描件)→ 先 PDF 转图片 再丢这里
OCR 不是魔法。理解检测 + 识别两段流水线,知道字典 6622 字的边界、知道 16 px 是检测下限,遇到识别失败就能立刻判断是哪一环出了问题。