Loading

用 PySide6 和 PaddleOCR 做一个剪贴板 OCR 小工具

问题重述

日常看论文、网页、截图、PDF 的时候,经常会遇到一个很小但高频的问题:想把截图里的文字 OCR 出来。

通常做法有几种:

  • 打开在线 OCR 网站
  • 调用系统截图工具
  • 用浏览器插件
  • 写一个临时脚本
  • 直接丢给大模型识别

这些方法都能用,但是都不太适合作为一个“随手工具”。

我的需求比较明确:

  • 从剪贴板读取图片
  • 本地模型推理
  • 支持 GPU
  • 支持模型切换
  • UI 简单,不做多余功能
  • 依赖用 uv / pixi 管理
  • 尽量少折腾环境

于是做了一个小工具:ppocr-client

功能目标

  1. 从剪贴板读取图片
  2. 在界面中预览图片
  3. 调用 OCR 模型识别
  4. 显示文本结果和原始 JSON

模型目前支持两个PaddleOCR系列的模型:

  • PP-OCRv6(轻量)
  • PaddleOCR-VL-1.6(全能)

默认使用:

PP-OCRv6 + gpu:0

启动后会自动预热模型。预热完成后,实际推理耗时大约在 380ms 左右。(4050 Laptop 6G)

UI 设计

image

布局上分成左右两块:

  • 左侧:剪贴板图片预览
  • 右侧:识别结果

右侧再分两个 tab:

  • 文本
  • 原始 JSON

没有做菜单栏,也没有做复杂设置,目前还不需要,后面功能复杂了再加。顶部放几个必要控件:

模型选择
设备选择
读取剪贴板
识别
复制结果

OCR 后端封装

后端封装PaddleOCR:

class PaddleOcrManager:
    def recognize(self, image, model, device):
        ...

模型 pipeline 会自动缓存:

self._pipelines[(model, device_key)] = pipeline

所以第一次识别会比较慢,后续同一个进程内再次识别会快很多。

自动预热

刚开始测试 GPU 推理时,第一次耗时大约 20s 以上。

后来确认这不是单次 OCR 真正需要这么久,而是包含了:

  • PaddleOCR pipeline 初始化
  • 模型权重加载
  • CUDA context 初始化
  • cuDNN / cuBLAS 动态库加载
  • GPU predictor 创建
  • 第一次 kernel 初始化

所以加了自动预热。

应用启动 250ms 后,在后台用一张小白图跑一次当前模型:

PP-OCRv6 / gpu:0

预热不会覆盖文本框结果,只更新状态栏和耗时标签。切换模型或设备后,也会自动重新预热。

依赖管理

项目用 uvpixi 同时管理。

uv 侧需要注意的是 Paddle GPU 包。

Windows 下 paddlepaddle-gpu 没有 Python 3.13 的 wheel,因此项目约束为:

requires-python = ">=3.12,<3.13"

GPU 版 Paddle 使用 Paddle 官方 CUDA 12.6 源:

[[tool.uv.index]]
name = "paddle-cu126"
url = "https://www.paddlepaddle.org.cn/packages/stable/cu126/"
explicit = true

并固定:

paddlepaddle-gpu==3.3.1

GPU 环境问题

GPU 这块踩了几个坑。

1. CPU 版 PaddlePaddle

一开始环境里装的是:

paddlepaddle==3.3.1

这个是 CPU 版。

选择 gpu:0 后,PaddleX 会进入一些 fallback 路径,最后出现很迷惑的 oneDNN / PIR 报错:

ConvertPirAttribute2RuntimeAttribute not support

后来加了检查:

paddle.is_compiled_with_cuda()
paddle.device.cuda.device_count()

如果当前是 CPU-only PaddlePaddle,直接提示用户安装 GPU 版,而不是继续执行。

2. Python 3.13 没有 GPU wheel

paddlepaddle-gpu 在 Windows 下没有 cp313 wheel。

所以环境切到了 Python 3.12。

3. cuDNN DLL 找不到

装好 GPU 版 Paddle 后,又遇到:

cudnn64_9.dll not configured correctly

最后显式安装了 CUDA / cuDNN runtime wheels,并在应用启动时把这些目录加入 DLL 搜索路径:

.venv/Lib/site-packages/nvidia/*/bin

4. cuDNN 版本警告

一开始装到的是 cuDNN 9.5,Paddle 提示它是按 cuDNN 9.9 编译的。

最后升级到:

nvidia-cudnn-cu12==9.9.0.52

警告消失。

模型缓存

PaddleX 默认缓存目录是:

~/.paddlex

为了符合项目习惯,改成了:

~/.kozbox/ppocr-client/

其中模型文件在:

~/.kozbox/ppocr-client/paddlex-cache/official_models/

Paddle 自己的缓存放在:

~/.kozbox/ppocr-client/paddle-home/.cache/paddle/

这样不会污染用户目录下其它 Paddle 项目。

坏缓存处理

下载模型时如果中断,可能留下一个“目录存在但文件不完整”的模型目录。

PaddleX 看到目录存在就直接复用,最后报:

No valid PaddlePaddle model found

所以做了一个简单处理:

  • 检查模型目录里是否存在 inference.json / inference.pdmodel
  • 检查是否存在 inference.pdiparams
  • 如果目录不完整,就重命名为 .corrupt-<timestamp>
  • 然后重新下载

这样不用手动去删半截模型目录。

最终效果

现在默认配置是:

PP-OCRv6 + gpu:0

启动后自动预热。

实测热启动后的推理耗时大约:

380ms

这个耗时比较符合预期。

第一次启动还是比较慢,因为要初始化和加载权重,但后续会快很多。

备忘

以后如果遇到 GPU 相关问题,先检查:

import paddle

print(paddle.__version__)
print(paddle.is_compiled_with_cuda())
print(paddle.device.cuda.device_count())

如果 is_compiled_with_cuda()False,说明装的是 CPU 版 Paddle。

如果 CUDA 可见但提示 cudnn64_9.dll 找不到,检查:

.venv/Lib/site-packages/nvidia/cudnn/bin

是否存在,并确认该目录已经加入当前进程 PATH / DLL search path。

总结

这个工具(包括套用PaddleOCR框架)本身不复杂。真正花时间的部分是 Windows 下 GPU 推理环境的细节:

  • Python ABI
  • Paddle GPU wheel 来源
  • CUDA runtime
  • cuDNN DLL
  • PaddleX 缓存
  • 首次预热

最终结果还算满意:剪贴板图片进来,本地 CPU/GPU 识别,结果直接复制出去。

posted @ 2026-07-06 23:16  kozumi  阅读(51)  评论(0)    收藏  举报