|
|
||
|---|---|---|
| benchmarks | ||
| cpu | ||
| data | ||
| gpu | ||
| logs/legacy | ||
| ocr_app | ||
| tests | ||
| .gitignore | ||
| README.md | ||
| ocr.py | ||
README.md
PaddleOCR-VL-1.6 本地 OCR
本项目使用 PaddleOCR-VL-1.6 实现统一的图片 OCR、批量图片 OCR 和 PDF 识别,CPU/GPU 环境完全隔离,并通过根目录唯一入口 ocr.py 调用。
PDF 默认使用 文本提取 + OCR 混合模式:优先提取 PDF 原始文本层,仅当页面没有有效文本层或文本质量不足时才加载 PaddleOCR-VL 并 OCR。
当前开发机器只有集成显卡。CPU 功能已验证;GPU 代码已实现,但必须在 NVIDIA CUDA GPU 机器上安装和测试。
目录结构
ocr-VL1.6/
├── ocr.py # 唯一用户入口,自动选择 CPU/GPU 子环境
├── ocr_app/ # CPU/GPU 共享业务代码
│ ├── cli.py # image/batch/pdf/verify 命令
│ ├── commands.py # 命令实现
│ ├── runtime.py # 设备验证、模型延迟加载
│ ├── pdf.py # 混合 PDF、断点续传、导出
│ ├── pdf_text.py # 文本层提取与质量评估
│ └── logging_utils.py # UTF-8 结构化日志
├── cpu/
│ ├── pyproject.toml # CPU 独立依赖
│ ├── uv.lock # CPU 独立锁文件
│ ├── .python-version # Python 3.13
│ └── runner.py # 统一入口的 CPU 执行器
├── gpu/
│ ├── pyproject.toml # GPU 独立依赖
│ ├── .python-version # Python 3.11
│ ├── setup_env.py # CUDA Wheel 安装脚本
│ └── runner.py # 统一入口的 GPU 执行器
├── data/
│ ├── images/ # 测试图片
│ └── documents/ # 测试 PDF
├── outputs/ # PDF 输出(git ignored)
├── benchmarks/ # 单图 Benchmark JSON
├── logs/ # UTF-8 运行日志
└── tests/ # 共享逻辑测试
根目录不再保存 Paddle 虚拟环境或 Python 项目依赖。CPU 与 GPU 分别使用 cpu/.venv 和 gpu/.venv。
安装
CPU
uv sync --project cpu
GPU
根据目标机器 CUDA/驱动和 PaddlePaddle 官方兼容表选择 Wheel:
python gpu/setup_env.py --cuda cu118 --dry-run
python gpu/setup_env.py --cuda cu118
也支持:
python gpu/setup_env.py --cuda cu126
安装成功后脚本生成 gpu/.gpu-ready。统一入口只会调用已安装的 gpu/.venv,不会从默认 PyPI 误装 GPU 包,也不会回退到 CPU。
简化统一入口
主用法只有一种:
python ocr.py <文件或目录> --device cpu|gpu
程序自动判断输入类型:
| 输入 | 自动路由 |
|---|---|
.png/.jpg/.jpeg/.bmp/.tif/.tiff/.webp |
图片 OCR + Benchmark |
.pdf |
PDF 混合文本提取/OCR |
| 目录 | 发现其中的图片和 PDF,逐个调用同一个单文件路由器 |
不支持的文件后缀会给出明确错误;目录模式会自动忽略不支持的文件。
验证环境
python ocr.py verify --device cpu
python ocr.py verify --device gpu
单张图片
python ocr.py data/images/手写01.png --device cpu
多轮 Benchmark:
python ocr.py data/images/手写01.png \
--device cpu \
--warmup 1 \
--rounds 3
图片识别结果和 Benchmark 默认一起写入:
outputs/images/<图片名_扩展名>/
单个 PDF
python ocr.py data/documents/sample.pdf --device cpu
PDF 默认使用混合模式。强制模式:
python ocr.py sample.pdf --pdf-mode text --device cpu
python ocr.py sample.pdf --pdf-mode ocr --device cpu
--mode 仍作为 --pdf-mode 的简写别名保留。
批量目录
# 扫描当前目录层级中的图片和 PDF
python ocr.py data/ --device cpu
# 递归扫描所有子目录
python ocr.py data/ --recursive --device cpu
目录模式的底层就是重复调用同一个单文件路由器,因此:
- 图片使用与单图片相同的 Benchmark 和日志逻辑
- PDF 使用与单 PDF 相同的混合路由、断点和导出逻辑
- 所有文件共享同一个延迟加载模型实例
- 电子 PDF 不会触发模型加载;首张图片或首个 OCR 页面才加载模型
- 保持串行处理,避免此前多进程造成卡顿、无响应和黑屏
递归目录的图片和 PDF 输出都会保留相对目录结构,避免不同子目录下同名文件相互覆盖。
统一输出目录
图片和 PDF 现在都会写入 --output 指定目录,默认是 outputs/:
outputs/
├── images/
│ └── <相对目录>/<图片名_扩展名>/
│ ├── result.md # Markdown 结果
│ ├── result.txt # 纯文本结果
│ ├── result.json # PaddleOCR 结构化结果
│ ├── benchmark.json # 模型/推理/导出耗时
│ └── assets/ # 识别结果中的图片资源(如有)
├── pdfs/
│ └── <相对目录>/<PDF名>/
│ ├── manifest.json
│ ├── document.md
│ ├── document.json
│ └── pages/
└── batches/
└── <目录名>-<时间戳>.json # 批量任务汇总
例如:
python ocr.py data/images/名片01.jpg --device cpu
会生成:
outputs/images/名片01_jpg/result.md
outputs/images/名片01_jpg/result.txt
outputs/images/名片01_jpg/result.json
outputs/images/名片01_jpg/benchmark.json
图片目录名包含扩展名,避免 same.png 与 same.jpg 相互覆盖。
重构前生成的 PDF 结果可能仍直接位于 outputs/<PDF名>/。这些旧结果不会自动删除;新任务统一写入 outputs/pdfs/<PDF名>/,确认不再需要后可手动迁移或清理。
目录任务再次运行时:
- 已存在的 PDF manifest 自动断点续传
- 新加入的 PDF 自动创建新任务
- 图片重新识别,并使用原子写入覆盖对应输出文件
--overwrite会强制 PDF 重新处理- 每次目录任务都会生成新的
outputs/batches/*.json汇总
旧命令前缀 image、pdf、batch 暂时兼容,例如 python ocr.py image a.png,但推荐直接传入路径。
PDF 混合模式
默认:hybrid
python ocr.py data/documents/sample.pdf --device cpu
每页流程:
读取 PDF 文本层
↓
文本质量评估
┌────┴────┐
│ │
有效文本 无效/不足
│ │
直接保存 渲染页面 → PaddleOCR-VL
└────┬────┘
↓
逐页 Markdown/JSON + 合并文档
如果整份 PDF 都具有有效文本层,模型完全不会加载。实测项目中的电子合同 PDF,单页混合处理约 0.06s,且 model_used=false。
强制文本模式
python ocr.py data/documents/sample.pdf \
--device cpu \
--pdf-mode text
所有页面只提取 PDF 文本层,不执行 OCR。扫描页可能得到空文本。
强制 OCR 模式
python ocr.py data/documents/sample.pdf \
--device cpu \
--pdf-mode ocr
所有页面都渲染后交给 PaddleOCR-VL,适合模型一致性 Benchmark。
文本层质量判定
混合模式默认要求:
| 参数 | 默认值 | 含义 |
|---|---|---|
--text-min-chars |
50 | 非空白字符最小数量 |
--text-min-printable-ratio |
0.85 | 可打印字符最低比例 |
--text-min-content-ratio |
0.60 | 字母、数字、CJK 字符最低比例 |
--text-max-replacement-ratio |
0.02 | Unicode 替换字符最高比例 |
--text-min-density |
25 | 页面文本密度最低值 |
例如某些扫描 PDF 只有页码或隐藏乱码层,混合模式会因为 too_few_characters、low_content_ratio 或 high_replacement_ratio 自动回退 OCR。
每页的判定结果会写入日志和 manifest:
{
"source_type": "ocr",
"routing_reason": "too_few_characters",
"text_layer": {
"usable": false,
"non_whitespace_chars": 8,
"printable_ratio": 1.0,
"content_ratio": 0.75
}
}
PDF 页码与恢复
# 第 1~5 页、第 8 页、第 10 页到末页
python ocr.py sample.pdf --pages "1-5,8,10-" --device cpu
# 中断后继续
python ocr.py sample.pdf --resume --device cpu
# 删除旧输出并重做
python ocr.py sample.pdf --overwrite --device cpu
--resume 会校验:
- PDF SHA-256
- PDF 处理模式
- DPI
- 文本层判定阈值
- manifest 版本
旧纯 OCR manifest(版本 1)不能直接用于新混合模式,请使用 --overwrite 重新生成。
PDF 输出
outputs/pdfs/<PDF名>/
├── manifest.json
├── document.md
├── document.json
├── pages/
│ ├── page-0001.md
│ ├── page-0001.json
│ └── ...
├── assets/
└── rendered/ # 仅 --keep-rendered 时存在
合并 Markdown 标题会标明页面来源:
## Page 1 (text)
## Page 2 (ocr)
Manifest 汇总包括:
{
"text_pages": 8,
"ocr_pages": 2,
"model_used": true,
"model_initialized_during_task": true,
"timing": {
"text_extract_total_seconds": 0.15,
"render_total_seconds": 0.8,
"ocr_total_seconds": 324.5,
"model_init_seconds": 40.0,
"task_total_seconds": 366.0
}
}
PDF 常用参数
python ocr.py sample.pdf \
--device cpu \
--pdf-mode hybrid \
--pages "1-10" \
--dpi 144 \
--threads 18 \
--keep-rendered \
--log-file logs/pdf-sample.log
DPI 建议:
| 文档 | DPI |
|---|---|
| 普通打印文字 | 120~144 |
| 小字号 | 150~200 |
| 手写/低质量扫描件 | 200~250 |
DPI 只影响需要 OCR 的页面,不影响直接提取文本层的页面。
日志
统一日志格式:
2026-07-16 15:07:45 | INFO | pid=33552 | PAGE_ROUTED page=1 source=text reason=usable_text_layer
默认目录:
logs/input/
logs/verify/
logs/legacy/
主要事件:
RUNTIME_PREPAREDMODEL_INITIALIZEDFILE_ROUTEDPAGE_ROUTEDPAGE_FINISHEDTASK_COMPLETEDIMAGE_COMPLETEDDIRECTORY_SUMMARYVERIFY_COMPLETED
日志使用 UTF-8。Windows 控制台即使显示乱码,日志文件中的中文仍正常。
测试
uv run --project cpu pytest -q
当前测试覆盖:
- 页码范围解析
- 文本标准化
- 有效文本层判定
- 空文本/短文本自动回退条件
- 根入口设备解析
当前结果:
17 passed
已验证状态
- CPU
verify:通过 - 单图统一入口:假模型端到端通过,原真实模型能力此前已验证
- 批量统一入口:假模型端到端通过
- PDF
hybrid电子文本页:真实 PDF 验证通过,未加载模型 - PDF 扫描页自动回退 OCR:假模型端到端通过
- PDF
text/ocr强制模式:通过 - GPU 环境路由:无环境时安全提示,不回退 CPU
- GPU 实机推理:尚未验证