TurboOCR:基于PP-OCRv6的极速Windows离线OCR工具,深度解析3.4GB依赖背后的技术架构

目录

  • 一、引言
  • 二、核心特性一览
  • [三、四种 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 协议,代码完全开放

项目地址:https://github.com/lazyboooooy/TurboOCR


二、核心特性一览

特性 说明
🎯 三档模型 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 一个脚本搞定下载和校验。


六、快速上手

下载即用(推荐)

  1. 前往 Releases 页面
  2. 下载 TurboOCR-v0.3.0-portable.zip(1.96 GB)
  3. 解压到任意目录
  4. 如果有 NVIDIA 显卡,额外下载 TurboOCR-v0.3.0-portable-cuda.zip,将其中的 DLL 放入解压目录
  5. 双击 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,因此三档模型耗时相同。

关键结论:

  1. tiny 模型已经足够好:对于清晰截图的文字识别,tiny (6MB) 的精度与 medium (138MB) 差距极小,但速度快 10 倍
  2. GPU 加速显著:medium 模型在 GPU 上推理时间仅为 CPU 的 1/6
  3. 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

许可证:Apache License 2.0

Copyright © 2026 TurboOCR Contributors

相关推荐
We0 AI1 小时前
2026 年的 B2B 官网竞争,已经不只是页面竞争了
人工智能·aigc·#ai建站
冬奇Lab1 小时前
每日一个开源项目(第160篇):Destructive Command Guard - 在 AI Agent 运行 rm -rf 之前拦截它
人工智能·安全·开源
IvorySQL1 小时前
PG 日报|SQL/PGQ 图查询基于联接重写机制实现
数据库·人工智能·sql·postgresql·区块链·ivorysql
博图光电2 小时前
博图汽车零配件视觉检测与测量解决方案
人工智能·汽车·视觉检测
仿生狮子2 小时前
别再说“全栈”了,AI 时代团队只认这 5 种人
前端·人工智能·后端
许彰午2 小时前
95_Python内存管理与垃圾回收
开发语言·python
乒乓狂魔2 小时前
SkyWalking 也能 AI 智能化了
人工智能·skywalking
骄阳如火3 小时前
Python 性能深度剖析:从“被诟病的慢”到“Rust 重塑”的拐点
python