
最近一段时间,我一直在折腾一个看起来有点"逆潮流"的项目:
不用 Python,不用 OpenCV,不用 ONNX Runtime,也不用 OpenVINO、TensorRT、protobuf,直接用纯 C 跑 PP-OCR。
这个项目叫:
lw.PPOCR.C
经过一段时间的开发、重构和大量 CI 验证,现在终于发布了第一个 v0.2.0 预览版本:
v0.2.0-preview.1
这次更新不再只是原来以 PP-OCRv6 Tiny 为核心的小型运行时,而是第一次把:
PP-OCRv6 Tiny、Small、Medium
三套模型统一到了同一套纯 C Runtime 之上。
更重要的是,这次不仅仅是"代码支持了"。
Windows、Linux、WebAssembly、浏览器单文件 HTML、Android ARM64、Java/JNI、Node.js,以及三套模型包,都已经通过自动化测试,并通过 GitHub Actions 完成了真实 Release 发布。
为什么还要自己做一个 OCR Runtime?
现在部署 OCR,其实已经有很多成熟方案。
Python + PaddleOCR 很方便;
ONNX Runtime 很通用;
OpenVINO、TensorRT 性能也非常不错。
但实际做工程项目以后,会碰到另外一类问题。
比如客户给你一台工控机,只想要:
"拷几个 DLL 进去就能跑。"
或者需要部署到一个比较克制的 Linux ARM64 设备上,又或者要做成自己的 C++、C#、Java 软件,希望整个运行环境尽量简单。
这时候你会发现,真正麻烦的往往不是 OCR 模型本身,而是模型后面的整个运行时生态。
Python 环境、动态库、第三方依赖、版本兼容、模型格式、部署目录、安装包体积......
最后一个 OCR 功能,可能带进去一大堆东西。
所以我做 lw.PPOCR.C 时,一开始就定了一个比较明确的目标:
它不是一个通用 ONNX Runtime,而是一个专门针对 PP-OCR 模型优化的轻量级纯 C Runtime。
换句话说,我们主动放弃"什么模型都能跑",换取:
更小、更简单、更容易集成,也更容易控制。
现在真的只需要纯 C
lw.PPOCR.C 当前核心采用 C11 开发。
运行 PP-OCR 时,不依赖:
Python、OpenCV、ONNX Runtime、OpenVINO、TensorRT、protobuf。
对于工程项目来说,这一点带来的价值其实比"少几个 DLL"更大。
因为 Runtime 足够小以后,我们就可以开始真正控制整个 OCR 执行链:
objectivec
PP-OCR ONNX
↓
模型转换
↓
LWM
↓
lw.PPOCR.C
↓
DET
↓
CLS
↓
REC
↓
完整 OCR 结果
模型加载、Shape 推导、Workspace 管理、算子实现、SIMD 优化、OCR 后处理,全部掌握在自己的代码里。
目前 CPU SIMD 已经覆盖:
objectivec
Scalar
SSE2
AVX2
AArch64 NEON
LoongArch LSX
这也意味着,它不再只是为了普通 Windows x64 PC 写的 Demo,而是开始具备真正做跨平台部署 Runtime 的基础。
v0.2.0 最大变化:Tiny、Small、Medium 三模型统一
之前项目主要围绕 PP-OCRv6 Tiny。
Tiny 有一个非常大的优势:
小。
它非常适合:
手机、普通桌面软件、边缘设备、浏览器以及对资源比较敏感的场景。
但实际项目中,大家很自然会问:
能不能用 Small?
能不能跑 Medium?
所以 v0.2.0-preview.1 做的一件很重要的事情,就是让:
scss
PP-OCRv6 Tiny
PP-OCRv6 Small
PP-OCRv6 Medium
使用同一套 Runtime。
这里我特意没有在 C API 里面增加:
LW_MODEL_TINY
LW_MODEL_SMALL
LW_MODEL_MEDIUM
这样的枚举。
因为在我的设计里:
Tiny / Small / Medium 是模型包的问题,不应该变成 Runtime ABI 的问题。
原生程序只需要更换模型目录。
Runtime 并不需要知道:
"你现在跑的是 Tiny,还是 Medium。"
我觉得这个边界很重要。
它意味着以后如果继续增加新的 PP-OCR 模型,不需要不停修改公共 C API。
三套独立 Runtime Model Pack
这次 Release 直接提供三套模型包:
scss
PP-OCRv6 Tiny Runtime Pack
PP-OCRv6 Small Runtime Pack
PP-OCRv6 Medium Runtime Pack
实际发布大小大约为:
scss
Tiny 7.2 MB
Small 32.1 MB
Medium 139.6 MB
每个模型包都包含自己的模型、字典、manifest 和 SHA256 信息,并且使用独立命名空间,避免不同模型解压以后互相覆盖。
所以原生程序最终可以形成类似这样的目录:
scss
models/
├── ppocrv6-tiny/
├── ppocrv6-small/
└── ppocrv6-medium/
程序选择哪个目录,就运行哪个模型。
我个人比较喜欢这种方式。
它比在 Runtime 里面加入越来越多的"模型类型判断"干净得多。
一个 HTML,就是一个完整 OCR
这次还有一个我自己非常喜欢的功能:
Standalone HTML。
也就是:
一个 HTML 文件里面,直接包含 Runtime + WASM + 模型 + OCR 页面。
不用启动服务器。
不用安装 Python。
不用 npm install。
甚至不需要单独准备模型目录。
下载以后,直接打开 HTML 就可以做 OCR。
而且这次不是做一个 HTML 再让用户选择三个模型,而是分别提供三个独立文件:
css
Tiny HTML
Small HTML
Medium HTML
这样每个文件本身就是一个完整、确定的 OCR 产品。
实际发布后的大小也很有意思:
css
Tiny HTML ≈ 13.7 MB
Small HTML ≈ 46.9 MB
Medium HTML ≈ 190.3 MB
。
这三个数字其实也很好地说明了它们各自的定位。
Tiny 很适合手机和普通使用。
Small 我认为是非常值得尝试的增强版,大小仍然比较合理。
Medium 已经明显属于桌面优先的重量级方案。
所以 Medium 虽然也能做成单文件 HTML,但我并不打算把它宣传成移动端首选。
不是"HTML 能生成",而是真的跑了 OCR
做 WebAssembly 项目很容易出现一种情况:
编译成功了。
文件也生成了。
然后就算支持浏览器了。
这次我不太想这样做。
所以 Tiny、Small、Medium 的浏览器版本,都真正通过 Chromium 执行 OCR。
Small 和 Medium 还额外做了:
lua
创建 OCR Runtime
↓
执行真实 OCR
↓
校验行数
↓
校验完整识别文本 SHA256
↓
再次 OCR
↓
destroy
↓
重新 create
↓
再次 OCR
并且 Standalone HTML 也在浏览器里真正加载图片、执行 OCR、读取结果。
最终这些测试又在正式 v0.2.0-preview.1 的 Release Workflow 中重新执行了一遍,并全部通过。
所以这次说:
Small / Medium Browser 支持
不是指"理论上应该可以",而是已经作为 Release Gate 实际跑过。
除了 C,还把 Java、Android、Node 都接上了
虽然核心坚持纯 C,但 Runtime 最终还是要被各种业务程序调用。
目前这个 Preview 已经提供了一套比较完整的分发方式,包括:
- Windows x64 原生开发包、Linux x86_64 原生开发包;
- Android ARM64 AAR 和 Demo APK;
- Java/JNI:Windows x64、Linux x64、macOS ARM64;
- Node.js 18 / 20 / 22 WASM;
- Tiny / Small / Medium 浏览器 SDK;
- Tiny / Small / Medium 单文件离线 HTML;
- Tiny / Small / Medium Runtime Model Pack。
其中 macOS ARM64 Java/JNI 这次也真正通过了:
sql
构建
→ 打包
→ 校验
→ Java 示例编译
→ macOS 上实际 OCR
→ Release
完整链路。
Release 本身也做成了一个"测试"
这次其实还有一个变化,没有那么容易从页面上直接看出来。
以前很多项目的发布流程是:
编译
↓
压缩
↓
上传
但随着平台越来越多,这种方式很容易发布错文件。
所以 lw.PPOCR.C 现在把 Release Asset 本身也定义成了一个 Contract。
每一个正式应该发布的文件:
Windows
Linux
Web
Java
Android
Node
Runtime Model Pack
Checksum
都会进入 Release Manifest。
真正发布以前,CI 会检查:
文件是否缺失
文件名是否正确
版本号是否正确
是否出现多余文件
SHA256 是否正确
checksum 是否覆盖正确
通过以后才允许执行 GitHub Release。
这次 v0.2.0-preview.1 已经第一次完整跑通了这条真实发布链。
对我来说,这件事其实比"又增加了一个接口"更重要。
因为从这里开始,项目逐渐从:
"代码仓库"
变成:
"可以重复构建和发布的软件产品"。
为什么现在还是 Preview?
虽然这次功能已经比较完整,我还是把版本标成了:
v0.2.0-preview.1
而不是直接发布 v0.2.0。
原因也很简单。
现在还希望实际观察几个问题。
首先是 Small 和 Medium 在真实项目里的价值。
尤其是 Medium。
它的浏览器单文件已经接近 190 MB,我们技术上能够跑,并不代表每个场景都值得使用。
我反而更想看看:
Small 是否已经是性能、效果、体积之间更好的平衡点?
其次是不同设备上的实际表现。
尤其:
普通办公电脑
低功耗 x86
ARM64
国产平台
浏览器
工控环境
这些场景里的体验,比继续在 CI 里面多加几个测试更有价值。
还有一个原因就是:
目前公共 C ABI 和 LWM v0.1 格式仍然没有宣布冻结。
所以 Preview 阶段如果你拿去做正式项目,建议把 Runtime 和模型作为一套一起管理,不要混用不同 Release 的二进制、模型和字典。这个限制也已经明确写进发布文档。
谁可能会对这个项目感兴趣?
如果你平时使用 PaddleOCR,而且属于下面这些场景,我觉得可以试试看 lw.PPOCR.C:
你在做 C/C++ 工程,希望尽可能少带第三方运行库;
你需要在 Windows / Linux / ARM64 边缘设备部署 OCR;
你在做 C#、Java 等桌面软件,希望底层 OCR Runtime 足够克制;
你想把 OCR 直接打进一个离线 HTML;
你比较在意安装包大小、部署复杂度和运行时依赖;
或者,你单纯对:
"从模型格式、算子、SIMD 到完整 OCR,自己实现一套小型推理 Runtime"
这件事情感兴趣。
这个项目应该都会有一些值得看的地方。
接下来准备做什么?
v0.2.0-preview.1 发布以后,我暂时不准备马上塞入大量新功能。
反而希望这一版先跑一跑。
看看真实用户到底更喜欢:
scss
Tiny
Small
Medium
哪一个。
看看大家主要把它用在:
Windows
Linux
ARM64
Web
Java
Android
哪一种环境。
以及有没有一些我们在 CI 环境里看不到的兼容性问题。
后续比较大的 Runtime 工作,我依然对:
更系统的 Microkernel Architecture、ARM64 进一步优化以及新的 SIMD Kernel
很感兴趣。
但这些不会赶在 v0.2.0 发布前强行塞进去。
现阶段更重要的是先把这一版打磨稳定。
最后
lw.PPOCR.C 从最开始其实只是一个很简单的想法:
PP-OCR 能不能不用一整套通用推理框架,直接做成一个足够小、足够容易集成的纯 C Runtime?
做到现在,已经逐渐有了:
css
模型转换
纯 C Runtime
DET / CLS / REC
完整 OCR
SIMD
多线程
Windows / Linux
ARM64
Java
Android
Node
WASM
单 HTML OCR
Tiny / Small / Medium
自动化 Release
这一整套东西。
它当然还远没有做到"万能"。
事实上我也不希望它变成另外一个万能 Runtime。
它更希望专注做好一件事情:
用尽可能简单、透明、可控的方式,把 PP-OCR 放进真实工程。
如果你也在做 OCR 工程化部署,欢迎试试,也欢迎提 Issue、PR,或者分享你实际跑起来的数据和场景。
项目地址:
GitHub:lxw112190/lw.PPOCR.C
当前版本:
v0.2.0-preview.1
这一版,终于可以放心让大家真正下载试用了。