目录
- 一、引言
- 二、核心特性一览
- [三、四种 OCR 模式详解](#三、四种 OCR 模式详解)
- [3.1 截图 OCR](#3.1 截图 OCR)
- [3.2 批量 OCR](#3.2 批量 OCR)
- [3.3 后台 OCR](#3.3 后台 OCR)
- [3.4 HTTP 服务模式](#3.4 HTTP 服务模式)
- 四、技术架构深度剖析
- [4.1 整体架构](#4.1 整体架构)
- [4.2 PP-OCRv6 推理流水线](#4.2 PP-OCRv6 推理流水线)
- [4.3 GPU 自动检测与降级](#4.3 GPU 自动检测与降级)
- [五、为什么项目这么大?3.4GB 依赖逐层拆解](#五、为什么项目这么大?3.4GB 依赖逐层拆解)
- 六、快速上手
- 七、从源码编译
- [八、HTTP API 调用指南](#八、HTTP API 调用指南)
- 九、关键设计决策
- 十、性能测试数据
- 十一、常见问题
- [十二、后续瘦身思路:从 3.4GB 到 ~500MB](#十二、后续瘦身思路:从 3.4GB 到 ~500MB)
- [12.1 方案一:裁剪编译 Paddle Inference](#12.1 方案一:裁剪编译 Paddle Inference)
- [12.2 方案二:迁移到 ONNX Runtime](#12.2 方案二:迁移到 ONNX Runtime)
- [12.3 方案对比与路线图](#12.3 方案对比与路线图)
- 十三、总结
一、引言
在日常工作中,我们经常遇到需要从图片或 PDF 中提取文字的场景------截图识别、扫描件转文本、发票信息提取等等。市面上的 OCR 工具要么需要联网(数据安全存疑),要么收费昂贵,要么识别精度堪忧。
TurboOCR 是我开发的一款 Windows 离线 OCR 工具,基于百度飞桨 PP-OCRv6 模型和 Paddle Inference 推理引擎,具备以下特点:
- 完全离线:所有推理在本地完成,数据不出本机
- GPU 加速:支持 NVIDIA CUDA/cuDNN 推理,毫秒级响应
- 开箱即用:下载解压直接运行,无需安装任何运行时环境
- 开源免费:Apache 2.0 协议,代码完全开放

二、核心特性一览
| 特性 | 说明 |
|---|---|
| 🎯 三档模型 | tiny (~6MB) / small (~31MB) / medium (~138MB),按需切换 |
| ⚡ GPU 加速 | CUDA/cuDNN 自动检测,不兼容时自动降级 CPU |
| 🖥️ 离线运行 | 全部本地推理,无需联网 |
| 📋 四种 OCR 模式 | 截图 / 批量 / 后台 / HTTP API |
| 📄 PDF 支持 | 内置 QPdfDocument 渲染,多页并行 |
| 📝 智能排版 | 8 种解析器,自动识别段落结构 |
| 🌐 HTTP API | REST 接口,Python/JS/任何语言调用 |
| 📊 历史记录 | SQLite 持久化,点击回溯 |
| 🔍 二维码识别 | ZXing + OpenCV 预检 |
| 🌍 多语言 UI | 中/英运行时切换 |
三、四种 OCR 模式详解
3.1 截图 OCR
全局热键 Ctrl+Q 唤起框选截图,松开鼠标即完成识别。这是最常用的模式------看到屏幕上任何文字,框一下,结果直接出现在主窗口并自动复制到剪贴板。

工作流程:
主窗口 OCR引擎 截图模块 全局热键 用户 主窗口 OCR引擎 截图模块 全局热键 用户 #mermaid-svg-3059wUczjkrbfPfu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3059wUczjkrbfPfu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3059wUczjkrbfPfu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3059wUczjkrbfPfu .error-icon{fill:#552222;}#mermaid-svg-3059wUczjkrbfPfu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3059wUczjkrbfPfu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3059wUczjkrbfPfu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3059wUczjkrbfPfu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3059wUczjkrbfPfu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3059wUczjkrbfPfu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3059wUczjkrbfPfu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3059wUczjkrbfPfu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3059wUczjkrbfPfu .marker.cross{stroke:#333333;}#mermaid-svg-3059wUczjkrbfPfu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3059wUczjkrbfPfu p{margin:0;}#mermaid-svg-3059wUczjkrbfPfu .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3059wUczjkrbfPfu text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-3059wUczjkrbfPfu .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-3059wUczjkrbfPfu .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-3059wUczjkrbfPfu .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-3059wUczjkrbfPfu .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-3059wUczjkrbfPfu #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-3059wUczjkrbfPfu .sequenceNumber{fill:white;}#mermaid-svg-3059wUczjkrbfPfu #sequencenumber{fill:#333;}#mermaid-svg-3059wUczjkrbfPfu #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-3059wUczjkrbfPfu .messageText{fill:#333;stroke:none;}#mermaid-svg-3059wUczjkrbfPfu .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3059wUczjkrbfPfu .labelText,#mermaid-svg-3059wUczjkrbfPfu .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-3059wUczjkrbfPfu .loopText,#mermaid-svg-3059wUczjkrbfPfu .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-3059wUczjkrbfPfu .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-3059wUczjkrbfPfu .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-3059wUczjkrbfPfu .noteText,#mermaid-svg-3059wUczjkrbfPfu .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-3059wUczjkrbfPfu .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3059wUczjkrbfPfu .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3059wUczjkrbfPfu .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-3059wUczjkrbfPfu .actorPopupMenu{position:absolute;}#mermaid-svg-3059wUczjkrbfPfu .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-3059wUczjkrbfPfu .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-3059wUczjkrbfPfu .actor-man circle,#mermaid-svg-3059wUczjkrbfPfu line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-3059wUczjkrbfPfu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Ctrl+Q 触发全屏遮罩 用户框选区域 传入截图像素数据 PP-OCRv6 检测+识别 返回识别结果 显示文本 + 复制到剪贴板
3.2 批量 OCR
切换到批量页面,拖入多个图片或 PDF 文件,后台并行处理。支持多线程工作队列,充分利用多核 CPU。

并行架构:
cpp
// 批量 OCR 使用 QThread 工作队列实现并行处理
class BatchWorker : public QThread {
Q_OBJECT
public:
void run() override {
while (!queue_.isEmpty()) {
auto task = queue_.dequeue(); // 从共享队列取任务
auto result = engine_->predict(task.image); // OCR 推理
emit taskDone(task.id, result); // 发射完成信号
}
}
private:
QQueue<BatchTask> queue_;
OcrEngine* engine_;
};
每个 Worker 线程独立持有 OcrEngine 实例,避免推理时的锁竞争。QMutex 仅保护任务队列的出队操作,推理过程完全并行。
3.3 后台 OCR
在设置中开启"后台模式"后,Ctrl+Q 截图不再弹出主窗口,而是静默完成识别,结果自动复制到剪贴板,托盘弹出通知。适合不打断工作流的快速提取文字场景。

后台模式的实现基于全局热键 + Windows RegisterHotKey API:
cpp
// 注册全局热键 (src/core/config_manager.cpp)
BOOL success = RegisterHotKey(
nullptr, // 窗口句柄
HOTKEY_ID, // 热键 ID
modifiers, // 修饰键 (MOD_CONTROL)
virtualKey // 虚拟键码 ('Q')
);
// 热键触发后,通过 QLocalServer 传递给已有实例
// 避免重复初始化 OCR 引擎(3.4GB 加载开销巨大)
3.4 HTTP 服务模式
在开发者页面一键启动 HTTP 服务器(默认端口 19527),暴露 3 个 REST 端点:

| 端点 | 方法 | 说明 |
|---|---|---|
/api/ocr/image?parser=single_para |
POST | 图片 OCR,body 为图片二进制 |
/api/ocr/pdf?parser=single_para |
POST | PDF OCR,body 为 PDF 二进制 |
/api/ocr/qrcode |
POST | 二维码/条形码识别 |
/api/health |
GET | 健康检查 |
这意味着任何语言都能调用 TurboOCR------Python 脚本、Node.js 服务、浏览器插件,只要发 HTTP 请求即可。
四、技术架构深度剖析
4.1 整体架构
┌─────────────────────────────────────────────────────────────┐
│ TurboOCR GUI │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ 截图 OCR │ │ 批量 OCR │ │ 设置页面 │ │ 开发者页面 │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └──────┬────────┘ │
│ │ │ │ │ │
│ ┌─────┴─────────────┴─────────────┴──────────────┴────────┐ │
│ │ Core 核心模块 │ │
│ │ ┌────────┐ ┌───────┐ ┌──────┐ ┌──────┐ ┌───────────┐ │ │
│ │ │配置管理 │ │日志系统│ │历史记录│ │PDF渲染│ │GPU检测 │ │ │
│ │ └────────┘ └───────┘ └──────┘ └──────┘ └───────────┘ │ │
│ │ ┌────────┐ ┌───────┐ ┌──────┐ ┌──────────────────────┐ │ │
│ │ │截图捕获 │ │主题管理│ │国际化 │ │HTTP 服务器(QtHttpSvr)│ │ │
│ │ └────────┘ └───────┘ └──────┘ └──────────────────────┘ │ │
│ └──────────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┴──────────────────────────────┐ │
│ │ OcrEngine 推理引擎封装 (QMutex) │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ PaddleOCR C++ Pipeline │ │ │
│ │ │ DetPredictor → ClsPredictor → RecPredictor │ │ │
│ │ └────────────────────────┬────────────────────────────┘ │ │
│ └───────────────────────────┼──────────────────────────────┘ │
└──────────────────────────────┼────────────────────────────────┘
│
┌──────────────────────────────┼────────────────────────────────┐
│ 3rdparty 依赖层 │
│ ┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │Paddle Infr.│ │ OpenCV │ │ ZXing │ │ Qt 6.8.3 │ │
│ │ (2.9 GB) │ │ (79 MB) │ │ (15 MB) │ │ (30 MB) │ │
│ └────────────┘ └──────────┘ └──────────┘ └──────────────┘ │
│ ┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Protobuf │ │ oneDNN │ │ MKL-ML │ │ 其他 (~20) │ │
│ │ (87 MB) │ │ (1.6 MB) │ │ (95 MB) │ │ (100 MB) │ │
│ └────────────┘ └──────────┘ └──────────┘ └──────────────┘ │
└──────────────────────────────────────────────────────────────┘
4.2 PP-OCRv6 推理流水线
PP-OCRv6 采用经典的 检测 → 方向分类 → 识别 三阶段流水线:
输入图片 (CV Mat)
│
▼
┌──────────────┐
│ 文本检测 │ DenseBox 检测头 → 文本框坐标
│ DetPredictor │ PP-OCRv6_tiny/small/medium_det
└──────┬───────┘
│ 文本框列表 [(x1,y1),(x2,y2)...]
▼
┌──────────────┐
│ 方向分类 │ 180° 文本方向校正 (可选)
│ ClsPredictor │ 仅在 medium 模型启用
└──────┬───────┘
│ 校正后文本行图像
▼
┌──────────────┐
│ 文本识别 │ CRNN + CTC 解码 → 文字内容
│ RecPredictor │ PP-OCRv6_tiny/small/medium_rec
└──────┬───────┘
│ 识别结果 (文本 + 置信度)
▼
┌──────────────┐
│ 后处理 │ TBPU 排序 → 段落聚合 → 格式化输出
│ PostProcess │ 8 种解析器按需选择
└──────────────┘
复杂度分析:
| 阶段 | tiny 模型 | small 模型 | medium 模型 |
|---|---|---|---|
| 检测 | ~1.7 MB | ~9.8 MB | ~62 MB |
| 识别 | ~4.4 MB | ~21 MB | ~76 MB |
| 总参数 | ~6 MB | ~31 MB | ~138 MB |
| 推理时间 (CPU) | ~50 ms | ~150 ms | ~500 ms |
| 推理时间 (GPU) | ~10 ms | ~25 ms | ~80 ms |
注:推理时间为单张 1080p 截图的端到端耗时,测试环境 i7-12700H / RTX 3060 Laptop。
4.3 GPU 自动检测与降级
TurboOCR 启动时执行三级检测:
cpp
// src/core/gpu_checker.cpp --- 三级 GPU 兼容性检测
bool GpuChecker::isCompatible() {
// 1. 检测 nvidia-smi 是否可用 (最基本的驱动检测)
bool hasDriver = detectNvidiaDriver();
// 2. 检查注册表中的 CUDA 版本
QString cudaVersion = readCudaRegistryKey();
// 3. 尝试加载 cuDNN DLL (最终确认)
bool hasCudnn = tryLoadCudnnLibrary();
// 任一失败 → 禁用 GPU 选项,强制 CPU
compatible_ = hasDriver && !cudaVersion.isEmpty() && hasCudnn;
return compatible_;
}
当检测到 GPU 不兼容时,设置页面 GPU 选项自动置灰,确保程序不会崩溃。这套机制解决了 Paddle Inference 在老显卡、虚拟机、未装驱动环境下的兼容性问题。
五、为什么项目这么大?3.4GB 依赖逐层拆解
很多同学看到 3.4GB 的依赖包会感到惊讶。下面逐层拆解每一部分,你会发现这个体积是合理且必要的。
5.1 体积分布
| 组件 | 大小 | 占比 | 为什么这么大? |
|---|---|---|---|
| Paddle Inference | 2.9 GB | 85% | 核心推理引擎,包含所有算子实现 |
| ├─ phi.dll | 1.3 GB | 38% | PHI 算子库 (Paddle High-level Inference),包含 2000+ 算子 Kernel |
| ├─ CUDA/cuDNN DLLs | 1.36 GB | 40% | NVIDIA GPU 推理运行时 |
| ├─ paddle_inference.dll | 100 MB | 3% | 推理引擎主体 |
| ├─ mklml.dll | 89 MB | 2.6% | Intel 数学核心库 (CPU 加速) |
| └─ mkldnn.dll | 46 MB | 1.3% | oneDNN 深度学习加速 |
| OpenCV | 79 MB | 2.3% | 图像预处理 (opencv_world3410.dll) |
| MKL-ML | 95 MB | 2.8% | Intel MKL 矩阵运算库 |
| ONNX/Protobuf | 87 MB | 2.6% | 模型序列化格式 |
| 其他 14 个库 | 130 MB | 3.8% | ZXing, Abseil, glog, yaml-cpp 等 |
| OCR 模型 | 176 MB | 5.2% | PP-OCRv6 三档模型权重文件 |
| Qt 框架 | ~30 MB | 0.9% | Qt6 Widgets/Core/Gui 等 DLL |
| 合计 | ~3.4 GB | 100% |
5.2 为什么 Paddle Inference 如此庞大?
核心原因:它是一个通用的深度学习推理引擎,而非专门的 OCR 推理器。
#mermaid-svg-8Bit70G87mmKF65n{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8Bit70G87mmKF65n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8Bit70G87mmKF65n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8Bit70G87mmKF65n .error-icon{fill:#552222;}#mermaid-svg-8Bit70G87mmKF65n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8Bit70G87mmKF65n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8Bit70G87mmKF65n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8Bit70G87mmKF65n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8Bit70G87mmKF65n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8Bit70G87mmKF65n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8Bit70G87mmKF65n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8Bit70G87mmKF65n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8Bit70G87mmKF65n .marker.cross{stroke:#333333;}#mermaid-svg-8Bit70G87mmKF65n svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8Bit70G87mmKF65n p{margin:0;}#mermaid-svg-8Bit70G87mmKF65n .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8Bit70G87mmKF65n .cluster-label text{fill:#333;}#mermaid-svg-8Bit70G87mmKF65n .cluster-label span{color:#333;}#mermaid-svg-8Bit70G87mmKF65n .cluster-label span p{background-color:transparent;}#mermaid-svg-8Bit70G87mmKF65n .label text,#mermaid-svg-8Bit70G87mmKF65n span{fill:#333;color:#333;}#mermaid-svg-8Bit70G87mmKF65n .node rect,#mermaid-svg-8Bit70G87mmKF65n .node circle,#mermaid-svg-8Bit70G87mmKF65n .node ellipse,#mermaid-svg-8Bit70G87mmKF65n .node polygon,#mermaid-svg-8Bit70G87mmKF65n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8Bit70G87mmKF65n .rough-node .label text,#mermaid-svg-8Bit70G87mmKF65n .node .label text,#mermaid-svg-8Bit70G87mmKF65n .image-shape .label,#mermaid-svg-8Bit70G87mmKF65n .icon-shape .label{text-anchor:middle;}#mermaid-svg-8Bit70G87mmKF65n .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8Bit70G87mmKF65n .rough-node .label,#mermaid-svg-8Bit70G87mmKF65n .node .label,#mermaid-svg-8Bit70G87mmKF65n .image-shape .label,#mermaid-svg-8Bit70G87mmKF65n .icon-shape .label{text-align:center;}#mermaid-svg-8Bit70G87mmKF65n .node.clickable{cursor:pointer;}#mermaid-svg-8Bit70G87mmKF65n .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8Bit70G87mmKF65n .arrowheadPath{fill:#333333;}#mermaid-svg-8Bit70G87mmKF65n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8Bit70G87mmKF65n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8Bit70G87mmKF65n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8Bit70G87mmKF65n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8Bit70G87mmKF65n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8Bit70G87mmKF65n .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8Bit70G87mmKF65n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8Bit70G87mmKF65n .cluster text{fill:#333;}#mermaid-svg-8Bit70G87mmKF65n .cluster span{color:#333;}#mermaid-svg-8Bit70G87mmKF65n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8Bit70G87mmKF65n .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8Bit70G87mmKF65n rect.text{fill:none;stroke-width:0;}#mermaid-svg-8Bit70G87mmKF65n .icon-shape,#mermaid-svg-8Bit70G87mmKF65n .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8Bit70G87mmKF65n .icon-shape p,#mermaid-svg-8Bit70G87mmKF65n .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8Bit70G87mmKF65n .icon-shape .label rect,#mermaid-svg-8Bit70G87mmKF65n .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8Bit70G87mmKF65n .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8Bit70G87mmKF65n .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8Bit70G87mmKF65n :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Paddle Inference 2.9GB
PHI 算子库 1.3GB
CUDA 运行时 1.36GB
CPU 数学库 135MB
推理框架主体 100MB
卷积算子 Conv2D/3D
RNN 算子 LSTM/GRU
Transformer 算子 Attention/LayerNorm
激活函数 50+ 种
2000+ 其他算子
cuDNN 9.0 ~755MB
cuBLAS 11.x ~605MB
cuRAND/cuSOLVER ~10MB
MKL-ML BLAS
oneDNN 图优化
PHI 算子库(1.3GB) 之所以这么大,是因为它包含了 PaddlePaddle 框架中所有 2000+ 种算子的 CPU 和 GPU 实现。虽然 OCR 只用到了其中约 50 种(卷积、归一化、CTC、Softmax 等),但 Paddle Inference 的预编译包不拆分算子------这是为了保证任意 Paddle 模型都能运行。
CUDA/cuDNN(1.36GB) 来自 NVIDIA 的官方运行时库。cuDNN 9.0 的单个 DLL 就超过 500MB,包含高度优化的卷积算法实现。这些 DLL 是为数据中心的 Volta/Ampere/Hopper 多代 GPU 架构编译的,涵盖的指令集远超消费级显卡所需。
5.3 为什么选择静态预编译而非包管理器?
| 方案 | 优点 | 缺点 |
|---|---|---|
| vcpkg/conan | 自动管理依赖版本 | Paddle Inference 不通过包管理器分发;MSVC 工具集必须严格匹配 (v142) |
| Git LFS | 版本控制一体化 | 带宽昂贵,二进制文件每次更新都要重新上传 3.4GB |
| GitHub Releases (当前方案) | 免费、无带宽限制、源码干净 | 需要额外下载步骤 |
最终选择 GitHub Releases 分发预编译包 ,是因为它完美平衡了源码仓库的整洁和用户下载的便利。setup_deps.py 一个脚本搞定下载和校验。
六、快速上手
下载即用(推荐)
- 前往 Releases 页面
- 下载
TurboOCR-v0.3.0-portable.zip(1.96 GB) - 解压到任意目录
- 如果有 NVIDIA 显卡,额外下载
TurboOCR-v0.3.0-portable-cuda.zip,将其中的 DLL 放入解压目录 - 双击
TurboOCR.exe运行
✅ 无需安装 VC++ Redistributable --- CMake post-build 已自动打包 MSVC 运行时 DLL。
使用方式
| 操作 | 快捷键/方式 |
|---|---|
| 截图 OCR | Ctrl+Q 框选 |
| 批量 OCR | 切换到"批量"页面,拖入文件 |
| 后台 OCR | 设置中开启,Ctrl+Q 静默识别 |
| HTTP API | 开发者页面启动服务,端口 19527 |
七、从源码编译
环境要求
| 工具 | 版本 | 说明 |
|---|---|---|
| Visual Studio | 2022+ | 需要 MSVC v142/v143/v145 工具集 |
| CMake | 3.16+ | 构建系统 |
| Qt | 6.8.3 msvc2022_64 | GUI 框架(动态链接) |
| Python | 3.8+ | 运行 setup_deps.py |
编译步骤
bash
# 1. 克隆仓库
git clone https://github.com/lazyboooooy/TurboOCR.git
cd TurboOCR
# 2. 下载预编译依赖
python setup_deps.py --tag v0.3.0
# 3. 配置 CMake (从 VS Developer Command Prompt 运行)
cmake -B build -DCMAKE_PREFIX_PATH="D:/Qt/6.8.3/msvc2022_64"
# 4. 编译 (Release 模式)
cmake --build build --config Release
# 5. 运行
./build/Release/TurboOCR.exe
注意 :必须从 VS Developer Command Prompt 启动,确保
cl.exe在 PATH 中。CMake 已配置/MT(静态 CRT),预编译依赖统一使用 v142 工具集以保证最大兼容性。
依赖包说明
Release 中的依赖分三个包(因 GitHub 单文件 2GB 限制):
| 包名 | 大小 | 内容 |
|---|---|---|
deps-paddle-core.zip |
1.8 GB | Paddle Inference (不含 CUDA DLL) |
deps-paddle-cuda.zip |
879 MB | CUDA/cuDNN DLL |
deps-other.zip |
217 MB | OpenCV, ZXing, Protobuf 等 + PP-OCRv6 模型 |
setup_deps.py 会自动下载全部三个包并解压到正确位置。
八、HTTP API 调用指南
启动 HTTP 服务后(默认 127.0.0.1:19527),任何语言都能调用:
Python 示例
python
import requests
# 图片 OCR
with open("screenshot.png", "rb") as f:
resp = requests.post(
"http://127.0.0.1:19527/api/ocr/image?parser=single_para",
data=f.read(),
headers={"Content-Type": "application/octet-stream"}
)
result = resp.json()
print(result["text"]) # 完整识别文本
for item in result["items"]:
print(f" [{item['score']:.3f}] {item['text']}") # 逐行 + 置信度
cURL 示例
bash
# 健康检查
curl http://127.0.0.1:19527/api/health
# 图片 OCR
curl -X POST http://127.0.0.1:19527/api/ocr/image \
--data-binary @screenshot.png
# PDF OCR
curl -X POST http://127.0.0.1:19527/api/ocr/pdf \
--data-binary @document.pdf
# 二维码识别
curl -X POST http://127.0.0.1:19527/api/ocr/qrcode \
--data-binary @barcode.png
响应格式
json
{
"text": "完整文本内容",
"items": [
{
"text": "第一行文字",
"score": 0.998,
"box": [10, 20, 200, 50]
}
],
"count": 1,
"total_ms": 123.4
}
九、关键设计决策
9.1 单实例锁
OCR 引擎初始化耗时约 3-5 秒(加载 3.4GB 模型和依赖)。如果用户双击 exe 启动多个实例,每个都独立加载引擎,内存将直接耗尽。
cpp
// src/main.cpp --- QSharedMemory 单实例锁
QSharedMemory sharedMemory("TurboOCR_SingleInstance");
if (!sharedMemory.create(1)) {
// 已有实例在运行 → 通过 QLocalSocket 发送激活信号
QLocalSocket socket;
socket.connectToServer("TurboOCR_LocalServer");
socket.waitForConnected(1000);
socket.write("ACTIVATE"); // 通知已有实例弹出窗口
socket.waitForBytesWritten(1000);
return 0; // 自身退出
}
// 否则创建 QLocalServer 成为主实例
QLocalServer localServer;
localServer.listen("TurboOCR_LocalServer");
9.2 MSVC 运行时自动打包
传统方案要求用户安装 VC++ Redistributable,这对非技术用户不友好。CMake post-build 步骤自动从 VS 安装目录复制 CRT 和 OpenMP 运行时 DLL:
cmake
# CMakeLists.txt 片段 --- 自动复制 MSVC 运行时
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND powershell -NoProfile -Command "
$vsBase = Resolve-Path 'C:/Program Files/Microsoft Visual Studio/
18/Community/VC/Redist/MSVC/*/x64' | Select-Object -First 1;
Copy-Item (Join-Path $vsBase 'Microsoft.VC145.CRT/*.dll') '${OUTDIR}';
Copy-Item (Join-Path $vsBase 'Microsoft.VC145.OpenMP/*.dll') '${OUTDIR}'
"
)
9.3 Qt 动态链接
选择动态链接 Qt(而非静态),主要考虑:
- LGPL 合规:动态链接允许用户替换 Qt DLL,满足 LGPLv3 要求
- 体积控制:静态链接 Qt 会使 exe 膨胀至 50MB+
- 更新便利:Qt 安全补丁无需重新编译应用
代价是需要 windeployqt 或多条 copy 命令打包 Qt DLL 和插件(platforms、sqldrivers、imageformats 等)。
十、性能测试数据
以下测试基于 i7-12700H / 32GB RAM / RTX 3060 Laptop 6GB / Windows 11:
| 场景 | tiny (CPU) | small (CPU) | medium (CPU) | medium (GPU) |
|---|---|---|---|---|
| 1080p 截图 (单文本框) | 48 ms | 142 ms | 487 ms | 78 ms |
| 1080p 截图 (多文本框) | 95 ms | 280 ms | 920 ms | 150 ms |
| 4K 截图 | 210 ms | 610 ms | 2.1 s | 340 ms |
| 10 页 PDF | 3.2 s | 9.5 s | 31 s | 5.1 s |
| 二维码识别 | 18 ms | 18 ms | 18 ms | 18 ms |
二维码识别使用 ZXing-C++ 独立路径,不经过 Paddle Inference,因此三档模型耗时相同。
关键结论:
- tiny 模型已经足够好:对于清晰截图的文字识别,tiny (6MB) 的精度与 medium (138MB) 差距极小,但速度快 10 倍
- GPU 加速显著:medium 模型在 GPU 上推理时间仅为 CPU 的 1/6
- PDF 多页受益于并行:10 页 PDF total time ≠ 单页 × 10,得益于 QThread 并行
十一、常见问题
Q1:为什么不用 Tesseract / EasyOCR / PaddleOCR-json?
| 方案 | 问题 |
|---|---|
| Tesseract | 不支持中文混合排版,精度远逊于 PP-OCRv6 |
| EasyOCR | Python 依赖,部署体积更大(需打包 Python 解释器 + PyTorch) |
| PaddleOCR-json | 跨进程通信开销、Python 运行时依赖 |
TurboOCR 选择直接用 C++ 调用 Paddle Inference API,零中间层,在性能和部署便利性之间取得最佳平衡。
Q2:macOS / Linux 支持吗?
当前仅支持 Windows,主要是因为:
- Paddle Inference 预编译包是 Windows 版本
- 使用了 Windows 特定 API:
RegisterHotKey(全局热键)、注册表读取(GPU 检测) - 构建配置目前仅针对 MSVC 工具链
CMake 构建系统理论上跨平台,欢迎贡献 macOS/Linux 适配。
Q3:CUDA 版本必须匹配吗?
是的。预编译的 CUDA DLL 基于 CUDA 12.0 + cuDNN 9.0。如果你的驱动不支持 CUDA 12.0,程序会自动检测并降级到 CPU 推理,不影响使用。
十二、后续瘦身思路:从 3.4GB 到 ~500MB
当前 TurboOCR 便携包体积为 2.75GB (含 CUDA),或 1.96GB(纯 CPU)。其中不可裁剪的硬成本约占一半,其余有显著优化空间。下面分析两条可行的技术路线。
不可裁剪的硬成本
| 组件 | 大小 | 可缩减? | 说明 |
|---|---|---|---|
| CUDA/cuDNN DLL | 1.36 GB | ❌ | NVIDIA 官方运行时,用户若需 GPU 推理则必须携带 |
| PP-OCRv6 模型权重 | 176 MB | ⚠️ 有限 | 可只保留 tiny (~6MB) + small (~31MB),省去 medium (~138MB) |
结论:GPU 版本无论如何不会低于 1.5GB,CPU 版本的优化目标是 400-500MB。
12.1 方案一:裁剪编译 Paddle Inference
目前使用的 Paddle Inference 是官方预编译包,包含了 PaddlePaddle 框架的全部 2000+ 算子。但 PP-OCRv6 实际只用到了约 50 种算子。
从源码裁剪编译的步骤:
bash
# 1. 克隆 PaddlePaddle 源码
git clone https://github.com/PaddlePaddle/Paddle.git
cd Paddle
# 2. 配置 CMake,仅启用 OCR 需要的算子
cmake -B build -G "Ninja" ^
-DCMAKE_BUILD_TYPE=Release ^
-DWITH_GPU=OFF ^ # CPU 版本先关 GPU
-DWITH_MKLDNN=ON ^ # 保留 oneDNN 加速
-DWITH_MKL=ON ^ # 保留 MKL 加速
-DWITH_ONNXRUNTIME=OFF ^ # 不需要 ONNX
-DWITH_PYTHON=OFF ^ # 不需要 Python 绑定
-DWITH_TESTING=OFF ^ # 关闭测试
-DWITH_CONTRIB=OFF ^ # 关闭贡献算子
-DON_INFER=ON ^ # 仅推理(不训练)
-DWITH_ENFORCE_OP_CROP=ON ^ # ⭐ 自动裁剪未使用的算子
-DOP_CROP_WHITELIST="conv2d;batch_norm;relu;pool2d;softmax;ctc_..." # 白名单
# 3. 编译 (仅推理库,约 10-20 分钟)
cmake --build build --target paddle_inference
预期效果:
| 组件 | 裁剪前 | 裁剪后 | 缩减 |
|---|---|---|---|
| phi.dll (算子库) | 1.3 GB | ~50 MB | 仅保留白名单算子 |
| paddle_inference.dll | 100 MB | ~30 MB | 剥离训练相关逻辑 |
| mkldnn.dll | 46 MB | 46 MB | 保留(CPU 加速必须) |
| mklml.dll | 89 MB | 89 MB | 保留(数学运算必须) |
| CPU 推理核心合计 | ~1.6 GB | ~215 MB | 缩减 86% |
#mermaid-svg-m3znoFyt5rQpJmlS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-m3znoFyt5rQpJmlS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-m3znoFyt5rQpJmlS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-m3znoFyt5rQpJmlS .error-icon{fill:#552222;}#mermaid-svg-m3znoFyt5rQpJmlS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-m3znoFyt5rQpJmlS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-m3znoFyt5rQpJmlS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-m3znoFyt5rQpJmlS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-m3znoFyt5rQpJmlS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-m3znoFyt5rQpJmlS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-m3znoFyt5rQpJmlS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-m3znoFyt5rQpJmlS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-m3znoFyt5rQpJmlS .marker.cross{stroke:#333333;}#mermaid-svg-m3znoFyt5rQpJmlS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-m3znoFyt5rQpJmlS p{margin:0;}#mermaid-svg-m3znoFyt5rQpJmlS .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-m3znoFyt5rQpJmlS .cluster-label text{fill:#333;}#mermaid-svg-m3znoFyt5rQpJmlS .cluster-label span{color:#333;}#mermaid-svg-m3znoFyt5rQpJmlS .cluster-label span p{background-color:transparent;}#mermaid-svg-m3znoFyt5rQpJmlS .label text,#mermaid-svg-m3znoFyt5rQpJmlS span{fill:#333;color:#333;}#mermaid-svg-m3znoFyt5rQpJmlS .node rect,#mermaid-svg-m3znoFyt5rQpJmlS .node circle,#mermaid-svg-m3znoFyt5rQpJmlS .node ellipse,#mermaid-svg-m3znoFyt5rQpJmlS .node polygon,#mermaid-svg-m3znoFyt5rQpJmlS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-m3znoFyt5rQpJmlS .rough-node .label text,#mermaid-svg-m3znoFyt5rQpJmlS .node .label text,#mermaid-svg-m3znoFyt5rQpJmlS .image-shape .label,#mermaid-svg-m3znoFyt5rQpJmlS .icon-shape .label{text-anchor:middle;}#mermaid-svg-m3znoFyt5rQpJmlS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-m3znoFyt5rQpJmlS .rough-node .label,#mermaid-svg-m3znoFyt5rQpJmlS .node .label,#mermaid-svg-m3znoFyt5rQpJmlS .image-shape .label,#mermaid-svg-m3znoFyt5rQpJmlS .icon-shape .label{text-align:center;}#mermaid-svg-m3znoFyt5rQpJmlS .node.clickable{cursor:pointer;}#mermaid-svg-m3znoFyt5rQpJmlS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-m3znoFyt5rQpJmlS .arrowheadPath{fill:#333333;}#mermaid-svg-m3znoFyt5rQpJmlS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-m3znoFyt5rQpJmlS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-m3znoFyt5rQpJmlS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m3znoFyt5rQpJmlS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-m3znoFyt5rQpJmlS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m3znoFyt5rQpJmlS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-m3znoFyt5rQpJmlS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-m3znoFyt5rQpJmlS .cluster text{fill:#333;}#mermaid-svg-m3znoFyt5rQpJmlS .cluster span{color:#333;}#mermaid-svg-m3znoFyt5rQpJmlS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-m3znoFyt5rQpJmlS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-m3znoFyt5rQpJmlS rect.text{fill:none;stroke-width:0;}#mermaid-svg-m3znoFyt5rQpJmlS .icon-shape,#mermaid-svg-m3znoFyt5rQpJmlS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m3znoFyt5rQpJmlS .icon-shape p,#mermaid-svg-m3znoFyt5rQpJmlS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-m3znoFyt5rQpJmlS .icon-shape .label rect,#mermaid-svg-m3znoFyt5rQpJmlS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m3znoFyt5rQpJmlS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-m3znoFyt5rQpJmlS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-m3znoFyt5rQpJmlS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 算子白名单裁剪
2000+ → 50 种
仅保留 OCR 路径
剥离训练逻辑
不可裁
Paddle 全量编译 1.6GB
裁剪后 ~215MB
PHI 算子库 1.3GB
phi.dll ~50MB
推理引擎 100MB
inference.dll ~30MB
MKL/oneDNN 135MB
MKL/oneDNN 135MB
挑战:
OP_CROP_WHITELIST需要精确列出 PP-OCRv6 用到的所有算子,遗漏任何一个都会导致运行时 crash- 白名单需要逆向分析模型结构和推理图才能完整获取
- 每次升级 PP-OCR 模型可能需要调整白名单
- 从源码编译 PaddlePaddle 对构建环境和网络要求较高(CMake 3.18+、Python、大量第三方依赖)
12.2 方案二:迁移到 ONNX Runtime
ONNX Runtime 是微软开源的跨平台推理引擎,设计理念与 Paddle Inference 完全不同------轻量化、模块化、无历史包袱。它的基础运行时仅 ~10MB。
迁移流程:
PP-OCRv6 Paddle 模型
│
▼
┌──────────────────────┐
│ 1. 模型导出 │ paddle.jit.save → inference model
│ Paddle → ONNX │ paddle2onnx --model_dir=./det_model
└────────┬─────────────┘
│ model.onnx
▼
┌──────────────────────┐
│ 2. ONNX 图优化 │ onnxruntime_tools 自动融合算子
│ Graph Optimize │ Conv+BN+ReLU → ConvBnRelu Fused
└────────┬─────────────┘
│ model_optimized.onnx
▼
┌──────────────────────┐
│ 3. TurboOCR 集成 │ C++ 调用 Ort::Session::Run()
│ onnxruntime.dll │ 替换 PaddlePredictor
└──────────────────────┘
核心代码改动(C++ 侧):
cpp
// 当前方案:Paddle Inference API
auto predictor = paddle_infer::CreatePredictor(config);
predictor->Run(inputs, &outputs);
// ONNX Runtime 替换方案:
Ort::Session session(env, L"model.onnx", session_options);
auto output = session.Run(Ort::RunOptions{nullptr},
input_names.data(), &input_tensor, 1,
output_names.data(), 1);
预期效果:
| 组件 | Paddle Inference | ONNX Runtime | 缩减 |
|---|---|---|---|
| 推理引擎 DLL | 100 MB (paddle_inference) | 10 MB (onnxruntime) | 90% |
| 算子库 | 1.3 GB (phi.dll) | 0 (内置于引擎) | 100% |
| 加速库 | MKL-ML 89MB + oneDNN 46MB | 可选 (onnxruntime 自带轻量实现) | 0-100% |
| CPU 推理核心合计 | ~1.6 GB | ~10-150 MB | 缩减 91%+ |
ONNX Runtime 的 MKL/oneDNN 加速是通过插件机制按需加载的,用户可以选择不带加速库用纯 CPU 实现,或按需下载。
CPU 版本体积估算(ONNX Runtime 路线):
| 组件 | 大小 |
|---|---|
| onnxruntime.dll | 10 MB |
| PP-OCRv6 模型 (ONNX 格式) | ~40 MB (三档合计) |
| OpenCV | 79 MB → 可换轻量替代 |
| 其他 3rdparty | 130 MB → 部分可去除 |
| Qt 框架 | 30 MB |
| CPU 便携包合计 | ~300-400 MB |
GPU 版本额外成本:
| 组件 | 大小 |
|---|---|
| onnxruntime CUDA EP | 50 MB |
| CUDA/cuDNN DLL | 1.36 GB (不可裁剪) |
| GPU 便携包合计 | ~1.7-1.8 GB |
12.3 方案对比与路线图
| 维度 | 裁剪 Paddle Inference | 迁移 ONNX Runtime |
|---|---|---|
| CPU 推理核心 | ~215 MB | ~10-150 MB |
| 开发工作量 | 中等(逆向白名单 + 一次编译) | 较大(模型导出 + 全链路改造) |
| 推理性能 | 与当前一致 | 持平或略优(ONNX 图融合优化) |
| GPU 支持 | 需额外配置 CUDA 编译 | onnxruntime CUDA EP 开箱即用 |
| 跨平台能力 | Paddle 支持 Linux/macOS/Windows | 更强(ONNX Runtime 原生全平台) |
| 模型格式兼容性 | 仅 Paddle 模型 | 任意框架 → ONNX |
| 维护成本 | 每次升级模型需重新编译白名单 | 低(ONNX 标准格式) |
| 上游依赖风险 | 依赖百度 Paddle 团队持续维护 | 微软 + 社区,活跃度更高 |
推荐路线图:
#mermaid-svg-8rCoyN5M8MGcCEUz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8rCoyN5M8MGcCEUz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8rCoyN5M8MGcCEUz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8rCoyN5M8MGcCEUz .error-icon{fill:#552222;}#mermaid-svg-8rCoyN5M8MGcCEUz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8rCoyN5M8MGcCEUz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8rCoyN5M8MGcCEUz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8rCoyN5M8MGcCEUz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8rCoyN5M8MGcCEUz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8rCoyN5M8MGcCEUz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8rCoyN5M8MGcCEUz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8rCoyN5M8MGcCEUz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8rCoyN5M8MGcCEUz .marker.cross{stroke:#333333;}#mermaid-svg-8rCoyN5M8MGcCEUz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8rCoyN5M8MGcCEUz p{margin:0;}#mermaid-svg-8rCoyN5M8MGcCEUz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8rCoyN5M8MGcCEUz .cluster-label text{fill:#333;}#mermaid-svg-8rCoyN5M8MGcCEUz .cluster-label span{color:#333;}#mermaid-svg-8rCoyN5M8MGcCEUz .cluster-label span p{background-color:transparent;}#mermaid-svg-8rCoyN5M8MGcCEUz .label text,#mermaid-svg-8rCoyN5M8MGcCEUz span{fill:#333;color:#333;}#mermaid-svg-8rCoyN5M8MGcCEUz .node rect,#mermaid-svg-8rCoyN5M8MGcCEUz .node circle,#mermaid-svg-8rCoyN5M8MGcCEUz .node ellipse,#mermaid-svg-8rCoyN5M8MGcCEUz .node polygon,#mermaid-svg-8rCoyN5M8MGcCEUz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8rCoyN5M8MGcCEUz .rough-node .label text,#mermaid-svg-8rCoyN5M8MGcCEUz .node .label text,#mermaid-svg-8rCoyN5M8MGcCEUz .image-shape .label,#mermaid-svg-8rCoyN5M8MGcCEUz .icon-shape .label{text-anchor:middle;}#mermaid-svg-8rCoyN5M8MGcCEUz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8rCoyN5M8MGcCEUz .rough-node .label,#mermaid-svg-8rCoyN5M8MGcCEUz .node .label,#mermaid-svg-8rCoyN5M8MGcCEUz .image-shape .label,#mermaid-svg-8rCoyN5M8MGcCEUz .icon-shape .label{text-align:center;}#mermaid-svg-8rCoyN5M8MGcCEUz .node.clickable{cursor:pointer;}#mermaid-svg-8rCoyN5M8MGcCEUz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8rCoyN5M8MGcCEUz .arrowheadPath{fill:#333333;}#mermaid-svg-8rCoyN5M8MGcCEUz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8rCoyN5M8MGcCEUz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8rCoyN5M8MGcCEUz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8rCoyN5M8MGcCEUz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8rCoyN5M8MGcCEUz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8rCoyN5M8MGcCEUz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8rCoyN5M8MGcCEUz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8rCoyN5M8MGcCEUz .cluster text{fill:#333;}#mermaid-svg-8rCoyN5M8MGcCEUz .cluster span{color:#333;}#mermaid-svg-8rCoyN5M8MGcCEUz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8rCoyN5M8MGcCEUz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8rCoyN5M8MGcCEUz rect.text{fill:none;stroke-width:0;}#mermaid-svg-8rCoyN5M8MGcCEUz .icon-shape,#mermaid-svg-8rCoyN5M8MGcCEUz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8rCoyN5M8MGcCEUz .icon-shape p,#mermaid-svg-8rCoyN5M8MGcCEUz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8rCoyN5M8MGcCEUz .icon-shape .label rect,#mermaid-svg-8rCoyN5M8MGcCEUz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8rCoyN5M8MGcCEUz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8rCoyN5M8MGcCEUz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8rCoyN5M8MGcCEUz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 短期快速
中长期彻底
v0.3.0 当前
CPU: 1.96GB / GPU: 2.75GB
v0.4.0 选择路线
Paddle 裁剪编译
CPU: ~450MB / GPU: ~1.8GB
ONNX Runtime 迁移
CPU: ~300MB / GPU: ~1.7GB
同时探索 ONNX 导出
PP-OCRv6 → ONNX
短期策略:先做 Paddle 裁剪编译,快速将 CPU 版从 1.96GB 降到 450MB 左右(去掉 phi.dll 的 1.3GB 冗余算子,省出的 1.5GB 全部来自 Paddle Inference 的瘦身)。
长期策略:逐步迁移到 ONNX Runtime,彻底解除对 Paddle 预编译包的依赖,同时获得跨平台能力和更小的部署体积。ONNX 格式的模型还可以被其他推理引擎(OpenVINO、TensorRT)直接加载,为未来硬件加速留下扩展空间。
十三、总结
TurboOCR 解决了 Windows 平台上"开箱即用的离线 OCR"这一需求空白。它不依赖 Python 运行时,不需要联网,不需要安装任何额外组件------下载、解压、双击,三步完成。
项目 3.4GB 的体积看似庞大,但经过拆解可以发现,其中 85% 来自 Paddle Inference 的通用推理引擎------这正是支持 PP-OCRv6 全系列模型、CPU/GPU 双后端、高精度文字识别能力的代价。通过 GitHub Releases 分发预编译包,源码仓库保持轻量(仅 ~1MB),用户按需下载。
亮点回顾:
- 🎯 三档模型覆盖精度/速度全场景
- ⚡ GPU 自动检测 + 自动降级,兼容性拉满
- 📋 四种 OCR 模式,覆盖交互式使用到编程调用
- 🔧 CMake 构建系统,MSVC 运行时自动打包
- 📦 GitHub Releases 分发,源码/二进制完全解耦
- 🔓 Apache 2.0 开源,商业友好
项目地址:https://github.com/lazyboooooy/TurboOCR
Copyright © 2026 TurboOCR Contributors