
做 OCR,真正困难的往往不是"把模型跑起来"。
PaddleOCR、ONNX Runtime、OpenVINO、TensorRT、OpenCV DNN......今天已经有很多成熟方案。只要环境允许,几行代码就可以完成一次文字识别。
但真正进入工业现场和产品部署后,问题会迅速变成另一副模样:
Windows 7 的老工控机怎么办? 客户不允许安装 Python 怎么办? NVIDIA、Intel、AMD 不同硬件怎么统一? Linux、ARM64、Windows 能不能共用一套接口? Java 项目能不能彻底摆脱 JNI? 浏览器里能不能直接运行 OCR? 能不能不依赖 OpenCV、ONNX Runtime,自己掌控整个推理链路?
围绕这些问题,我陆续开源了 5 个 PP-OCR 项目:
lw.PPOCR.Inference
lw.PPOCR.OpenCVDNN
lw.OpenCVDNN.PPOCR
lw.PPOCR.C
lw.PPOCR.Java
名字看起来有些接近,但它们实际上对应的是 5 种完全不同的工程场景。
如果把它们放在一起看,就会发现,这并不是 5 个重复的 OCR Demo,而是一条从"使用通用推理框架"逐步走向"自研专用推理 Runtime"的技术路线。
一张表看懂 5 个项目
| 项目 | 核心技术 | 是否依赖第三方推理 Runtime | 主要定位 | 典型场景 |
|---|---|---|---|---|
| lw.PPOCR.Inference | C++ + 多后端抽象 | 是 | 一套 API 统一多种推理后端 | CPU/GPU、多硬件、多客户环境 |
| lw.PPOCR.OpenCVDNN | C++ + OpenCV 5 DNN | 是 | 跨平台生产级 CPU OCR | Windows、Linux、ARM64、Docker、HTTP |
| lw.OpenCVDNN.PPOCR | C++ + OpenCV 5 DNN | 是 | Windows 7 / .NET 3.5 工业部署 | 老工控机、旧产线、离线设备 |
| lw.PPOCR.C | 纯 C 自研 Runtime | 否 | 极轻量、无通用推理 Runtime | Native、WASM、ARM、LoongArch、嵌入式 |
| lw.PPOCR.Java | 纯 Java 自研 Runtime | 否 | 无 JNI 的纯 Java OCR | JVM、Java 服务、桌面程序 |
如果只记一句话:
前 3 个项目解决的是"怎么把成熟 Runtime 用好",后 2 个项目解决的是"能不能连 Runtime 本身也自己做"。
一、lw.PPOCR.Inference:一套接口,统一多个推理后端
项目地址:
这是整个系列里"后端覆盖面"最广的项目。
它并不绑定某一种推理框架,而是把:
OpenCV DNN
ONNX Runtime
DirectML
OpenVINO
TensorRT
隔离成不同 Runtime,再通过统一的 C ABI 对外提供 OCR 服务。
架构可以简单理解为:
应用程序
│
Stable C ABI
│
PP-OCR Core
│
┌──────────┼──────────┐
│ │ │
OpenCV ORT OpenVINO
│ │
DirectML TensorRT
它解决的核心问题不是"哪个 Runtime 最快",而是:
当不同客户拥有不同 CPU、GPU 和操作系统时,上层业务代码能不能保持不变?
例如:
普通办公电脑可以用 OpenCV DNN;
Intel CPU 环境可以使用 OpenVINO;
Windows 通用 GPU 可以使用 DirectML;
NVIDIA GPU 可以切换 TensorRT。
但对上层程序来说,OCR 接口仍然是一套。
这类架构特别适合产品化项目,因为真正麻烦的往往不是第一次开发,而是后续几年里不断遇到新的硬件和部署环境。
二、lw.PPOCR.OpenCVDNN:把 OpenCV DNN 做成真正能部署的 OCR
项目地址:
如果并不需要 5 种 Runtime,只想要一个:
简单、可靠、CPU 可运行、跨平台、部署成本低
的 PP-OCR,那么 OpenCV DNN 是非常实用的选择。
于是有了 lw.PPOCR.OpenCVDNN。
它的推理链非常简单:
PP-OCR
↓
OpenCV 5 DNN
↓
CPU
但项目重点并不是"调用一下 OpenCV"。
真正投入精力的是 OCR 产品化过程中容易被忽略的部分:
vbnet
C ABI
HTTP API
Docker
Docker Compose
Windows Service
Linux systemd
API Key
并发控制
请求队列
超时保护
运行日志
访问日志
ASan / UBSan
CodeQL
SBOM
供应链检查
所以它更接近一个:
可以直接进入生产环境的 PP-OCR CPU 服务。
如果业务环境是:
Windows、Linux、ARM64、服务器、Docker、HTTP 服务,
那么这个项目比一个简单 Demo 更接近实际需要。
三、lw.OpenCVDNN.PPOCR:专门解决 Windows 7 工业现场
项目地址:
很多做互联网软件的人可能觉得 Windows 7 已经成为历史。
但工业软件领域并不是这样。
大量:
工控机
产线终端
视觉检测设备
测量设备
老业务系统
仍然在 Windows 7 上稳定运行。
而且这些设备常常还有几个典型限制:
不能轻易升级操作系统;
不能随便安装 VC Runtime;
不能部署 Python;
没有 CUDA;
主程序甚至还运行在 .NET Framework 3.5。
换掉整套设备的成本,远远高于继续维护现有系统。
因此这个项目从一开始的目标就很明确:
不是追最新技术,而是让现代 PP-OCR 能在老工业设备上稳定工作。
它使用 OpenCV 5 DNN 进行 CPU 推理,同时围绕:
Windows 7 SP1
x86 / x64
.NET Framework 3.5
C ABI
离线部署
静态运行库
做专门工程化。
所以:
lw.PPOCR.OpenCVDNN
更偏向:
跨平台生产部署。
而:
lw.OpenCVDNN.PPOCR
更偏向:
老 Windows 工业现场。
看似只交换了几个单词的位置,实际上服务的是两类完全不同的用户。
四、lw.PPOCR.C:如果连 ONNX Runtime 都不想要呢?
项目地址:
做到这里,问题开始发生变化。
前面的项目无论如何精简,背后仍然依赖:
OpenCV
ONNX Runtime
OpenVINO
TensorRT
这些通用推理 Runtime。
于是产生了一个新的问题:
对于结构相对固定的 PP-OCR 模型,真的必须带一个完整的通用推理框架吗?
这就是 lw.PPOCR.C 的出发点。
它不是 OpenCV wrapper。
也不是 ONNX Runtime wrapper。
它直接用纯 C 实现自己的推理 Runtime。
包括:
objectivec
模型加载
Shape 推导
Tensor 管理
Workspace Planner
算子执行器
Conv
ConvTranspose
MatMul
Pooling
Resize
Activation
DET
CLS
REC
DB Postprocess
CTC Decode
然后针对不同 CPU 架构继续做 SIMD 加速:
javascript
SSE2
AVX2
FMA
ARM NEON
LoongArch LSX
WebAssembly SIMD
整个推理链由项目自己控制。
也就是说:
过去是:
PP-OCR
↓
ONNX
↓
ONNX Runtime / OpenCV
↓
CPU
现在变成:
PP-OCR
↓
LWM
↓
lw.PPOCR.C
↓
CPU
这一步的意义非常大。
因为一旦模型执行权完全掌握在自己手中,就可以进一步做:
objectivec
权重预打包
Tensor 生命周期优化
Workspace 复用
Graph-level NHWC
PACKED16
算子融合
DET 专用 Conv
REC 专用 MatMul
AVX2 微内核
平台专用调度
而不需要等待第三方 Runtime 是否愿意针对某一个 PP-OCR 模型做优化。
这也是目前 5 个项目中,技术路线最深入的一个。
五、lw.PPOCR.Java:纯 Java,也可以完全摆脱 JNI
项目地址:
当 lw.PPOCR.C 走通自研 Runtime 后,自然而然又出现了另一个问题:
Java 能不能也不用 ONNX Runtime,不用 OpenCV,不用 JNI?
这就是 lw.PPOCR.Java。
传统 Java OCR 常见结构是:
Java
↓
JNI
↓
C / C++
↓
ONNX Runtime / OpenCV
而 lw.PPOCR.Java 希望做到:
Java
↓
Pure Java Runtime
↓
LWM Model
↓
PP-OCR
也就是说:
没有 JNI;
没有 native DLL;
没有 OpenCV native library;
没有 ONNX Runtime;
没有 Paddle Runtime。
它与 lw.PPOCR.C 共享 LWM 模型格式。
因此可以形成这样一套关系:
sql
PP-OCR
│
Offline Convert
│
LWM Model
/ \
/ \
▼ ▼
lw.PPOCR.C lw.PPOCR.Java
Pure C Pure Java
Java 侧同时提供:
Scalar Backend
以及在较新 JDK 上可选的:
JDK Vector API Backend
用来做 SIMD 加速。
因此,对很多 Java 项目来说,可以得到一个很干净的部署形态:
diff
JVM
+
JAR
+
LWM Model
不需要再额外维护:
.dll
.so
JNI
opencv_java
onnxruntime
这对于 Java 服务端、桌面应用和对 native dependency 敏感的环境来说,非常有意义。
六、5 个项目实际上形成了两条技术路线
如果把它们重新整理一下,会发现整体结构非常清楚。
第一条是:
工程部署路线
lw.PPOCR.Inference
│
│ 多 Runtime 统一
▼
OpenCV / ORT / OpenVINO / TensorRT
│
▼
lw.PPOCR.OpenCVDNN
│
│ 收敛到 OpenCV CPU
▼
lw.OpenCVDNN.PPOCR
│
▼
Windows 7 / .NET 3.5 / 工业设备
这一条路线主要回答:
OCR 怎么更容易落地?
第二条是:
自研 Runtime 路线
PP-OCR
│
LWM
┌─────┴─────┐
│ │
▼ ▼
lw.PPOCR.C lw.PPOCR.Java
Pure C Pure Java
这一条路线回答的是:
OCR 能不能不依赖通用推理框架?
七、到底应该选哪一个?
如果你的环境是:
不同客户拥有不同 CPU/GPU,希望一套 API 适配多个推理框架
看:
lw.PPOCR.Inference
如果需求是:
Windows / Linux / ARM64 + CPU OCR + Docker + HTTP
看:
lw.PPOCR.OpenCVDNN
如果现场还是:
Windows 7 / .NET Framework 3.5 / 老工控机
看:
lw.OpenCVDNN.PPOCR
如果追求:
Pure C、低依赖、WASM、ARM、LoongArch、自定义 SIMD
看:
lw.PPOCR.C
如果主要运行在:
JVM,而且希望彻底摆脱 JNI 和 native DLL
看:
lw.PPOCR.Java
八、为什么还要自己做 Runtime?
有人可能会问:
OpenCV、ONNX Runtime、OpenVINO 已经非常成熟,为什么还要自己实现?
答案其实并不是为了"重新发明 ONNX Runtime"。
通用 Runtime 必须解决的是:
尽可能多的模型都能运行。
而专用 Runtime 可以解决的是:
把一类明确的模型做到更轻、更小、更可控。
PP-OCR 的模型结构相对确定。
当模型范围明确以后,就可以做很多更激进的优化:
减少中间 Tensor
精确规划内存生命周期
提前 Pack 权重
减少 Layout 转换
融合算子
固定 Shape 微内核
按 OCR Graph 特化
按 CPU ISA 特化
通用 Runtime 的优势是"什么都能跑"。
专用 Runtime 的优势则是:
只做好一件事,但把这件事做到足够轻。
这两条路线并不矛盾。
因此我同时保留了:
成熟 Runtime 路线,
以及:
自研 Runtime 路线。
九、OCR 真正的工程难点,往往不在模型
这几个项目一路做下来,一个越来越明显的体会是:
模型只是整个 OCR 产品的一部分。
真正决定项目能不能长期使用的,还有:
ABI 稳定性
线程安全
模型校验
内存管理
错误恢复
并发策略
日志
服务化
部署
CI
性能回归
旧系统兼容
不同 CPU ISA
供应链
发布流程
模型能够推理,只代表:
它能跑。
真正做到:
能部署、能维护、能升级、能长期运行
才是工程上的另一半工作。
十、从 OpenCV 到纯 C,再到纯 Java
回头看这 5 个项目,大致经历了这样一个过程:
一套 API
统一多个 Runtime
↓
只保留 OpenCV
降低部署复杂度
↓
针对 Windows 7
解决工业旧系统
↓
去掉 OpenCV / ORT
Pure C Runtime
↓
进一步扩展
Pure Java Runtime
所以,这 5 个仓库并不是 5 次重复开发。
而是不断缩小依赖边界、扩大部署边界的结果。
目前这套项目已经覆盖:
javascript
Windows
Linux
ARM64
LoongArch
WebAssembly
Java
OpenCV
ONNX Runtime
DirectML
OpenVINO
TensorRT
以及
Pure C Runtime
Pure Java Runtime
接下来,lw.PPOCR.C 会继续围绕图级布局优化、SIMD 微内核、内存规划、模型执行效率以及更低版本 Windows 兼容进行探索。
lw.PPOCR.Java 也会继续研究 JDK Vector API 在纯 Java AI 推理中的性能空间。
如果你也在做 OCR 部署,或者对:
"不用 ONNX Runtime,自己做一个轻量 OCR Runtime"
这条路线感兴趣,欢迎交流。
项目地址
bash
lw.PPOCR.C
https://github.com/lxw112190/lw.PPOCR.C
lw.PPOCR.Java
https://github.com/lxw112190/lw.PPOCR.Java
lw.PPOCR.Inference
https://github.com/lxw112190/lw.PPOCR.Inference
lw.PPOCR.OpenCVDNN
https://github.com/lxw112190/lw.PPOCR.OpenCVDNN
lw.OpenCVDNN.PPOCR
https://github.com/lxw112190/lw.OpenCVDNN.PPOCR
联系与支持
作者:天天代码码天天
如果你正在使用这些项目,或者在 PP-OCR 部署、C/C++ 推理、Java OCR、SIMD 优化、Windows/Linux 工业部署等方面遇到问题,欢迎一起交流。
QQ Group:天天代码码天天 群号:264292622
如果这些开源项目对你的工作有所帮助,也欢迎 Star、Fork、提交 Issue 或 PR,一起把项目继续完善下去。