PP-OCRv6 ONNX Runtime Inference
Pure ONNX Runtime implementation of PP-OCRv6. Zero PaddlePaddle. Bit-exact accuracy. 3× faster.
Why this exists
PaddleX works great — but it pulls in a 2 GB+ dependency chain (PaddlePaddle + dozens of packages). If all you need is PP-OCRv6 inference with ONNX Runtime, you shouldn't have to install the entire Paddle ecosystem.
This repo gives you a single-file, drop-in module that matches PaddleX output bit-for-bit on the same ONNX Runtime backend — while being 3× faster than PaddlePaddle native inference.
| PaddleX (Paddle) | PaddleX (ORT) | This repo (Pure ORT) | |
|---|---|---|---|
| Inference engine | PaddleInference | ONNX Runtime | ONNX Runtime |
| Requires PaddlePaddle | ✓ Yes (~2 GB) | ✓ Yes (~2 GB) | ✗ No |
| Package footprint | ~2 GB | ~2 GB | ~200 MB |
| Avg latency (M4) | 877 ms | 291 ms | 282 ms |
| vs Paddle native | baseline | 3.0× faster | 3.1× faster |
| Accuracy vs PaddleX | — | bit-exact | bit-exact |
Table of Contents
- Quick Start
- Benchmarks
- Precision Validation
- API Reference
- Pipeline Architecture
- Project Structure
- Model Variants
- Advanced: GPU / CoreML
Quick Start
1. Install dependencies
pip install onnxruntime opencv-python-headless numpy pyclipper
That's it. No PaddlePaddle. No PaddleX.
2. Download models
# Detection model (ONNX)
wget -c https://paddle-model-ecology.bj.bcebos.com/paddlex/official_inference_model/paddle3.0.0/tmp/PP-OCRv6_tiny_det_onnx.tar
tar xf PP-OCRv6_tiny_det_onnx.tar
# Recognition model (ONNX)
wget -c https://paddle-model-ecology.bj.bcebos.com/paddlex/official_inference_model/paddle3.0.0/tmp/PP-OCRv6_tiny_rec_0515_onnx.tar
tar xf PP-OCRv6_tiny_rec_0515_onnx.tar
After extraction, your directory should look like:
PP-OCRv6_tiny_det_onnx/
├── inference.onnx
└── inference.yml
PP-OCRv6_tiny_rec_0515_onnx/
├── inference.onnx
└── inference.yml
3. Run inference
import cv2
from ppocrv6_onnx import PPOCRv6Onnx, OCRResult
det_model = "PP-OCRv6_tiny_det_onnx/inference.onnx"
rec_model = "PP-OCRv6_tiny_rec_0515_onnx/inference.onnx"
char_dict = "models/rec_char_dict.txt" # included in this repo
with PPOCRv6Onnx(det_model, rec_model, char_dict) as ocr:
img = cv2.imread("your_image.png")
results: list[OCRResult] = ocr(img)
for r in results:
print(f"{r.text} ({r.score:.3f})")
4. Try the demo
python demo.py
Benchmarks
Tested on Apple M4, 8 diverse images (Chinese, English, Japanese, handwriting, magazine, vertical text).
| Image | Lines | Pure ORT | PaddleX (ORT) | PaddleX (Paddle) |
|---|---|---|---|---|
| boarding pass | 30 | 162 ms | 163 ms | 527 ms |
| ancient Chinese | 12 | 112 ms | 113 ms | 343 ms |
| handwriting (CN) | 10 | 57 ms | 56 ms | 170 ms |
| handwriting (EN) | 11 | 69 ms | 76 ms | 209 ms |
| Japanese | 28 | 429 ms | 434 ms | 1,312 ms |
| magazine | 63 | 697 ms | 707 ms | 2,106 ms |
| vertical text | 76 | 563 ms | 575 ms | 1,711 ms |
| pinyin | 38 | 216 ms | 217 ms | 619 ms |
| Average | 282 ms | 291 ms | 875 ms |
Run:
python benchmark.py
Precision Validation
Compared with PaddleX across 8 images / 268 text lines:
| Metric | Value |
|---|---|
| Text mismatches | 0 / 268 |
| Avg confidence diff | 2.5 × 10⁻⁷ |
| Max confidence diff | 1.9 × 10⁻⁶ |
| Box coordinate diff | 0.0 px |
All results bit-exact with PaddleX when using the same ONNX Runtime backend.
Verification scripts:
scripts/verify_ort_vs_paddlex.py,scripts/verify_batch.py
API Reference
PPOCRv6Onnx
class PPOCRv6Onnx:
def __init__(
self,
det_model_path: str, # Path to detection ONNX model
rec_model_path: str, # Path to recognition ONNX model
rec_char_dict_path: str, # Path to character dictionary
*,
det_thresh: float = 0.3, # Detection binarization threshold
det_box_thresh: float = 0.6, # Detection box confidence threshold
det_unclip_ratio: float = 1.5, # Box expansion ratio
rec_batch_size: int = 6, # Recognition batch size
prefer_accelerator: bool = False, # Enable CoreML / CUDA
) -> None: ...
def __call__(self, img_bgr: np.ndarray) -> list[OCRResult]:
"""Run full OCR pipeline on a BGR image."""
def detect(self, img_bgr: np.ndarray) -> tuple[np.ndarray, list[float]]:
"""Text detection only. Returns (boxes, scores)."""
def recognize(self, img_list: list[np.ndarray]) -> tuple[list[str], list[float]]:
"""Text recognition only. Returns (texts, scores)."""
def close(self) -> None:
"""Release resources. Idempotent."""
OCRResult
@dataclass(frozen=True, slots=True)
class OCRResult:
text: str # Recognized text
score: float # Confidence [0, 1]
box: list[list[int]] # 4 corners [[x0,y0],[x1,y1],[x2,y2],[x3,y3]]
Pipeline Architecture
Input Image (BGR)
│
▼
[Text Detection] DB model → Resize → Normalize → ONNX → DBPostProcess
│
▼
[Box Sorting] Top-to-bottom, left-to-right reading order
│
▼
[Region Cropping] Perspective transform for each text box
│
▼
[Text Recognition] CRNN model → Resize(H=48) → Normalize → ONNX → CTC Decode
│
▼
OCRResult(text, score, box)[]
Project Structure
ppocrv6_onnx/
├── ppocrv6_onnx.py # Main module (~870 lines, all you need)
├── demo.py # Quick-start demo script
├── benchmark.py # Performance comparison tool
├── pyproject.toml # Project metadata & dependencies
├── README.md # This file (English)
├── README_zh.md # Chinese documentation
├── LICENSE # MIT License
├── models/ # Downloaded ONNX models
│ └── rec_char_dict.txt # 7180-character dictionary (included)
├── assets/ # Demo image
├── test_images/ # Multi-lingual test suite
├── scripts/ # Verification & dev tools
└── docs/ # Methodology & guides
Model Variants
PP-OCRv6 offers three sizes. Replace URLs accordingly:
| Size | Det Model | Rec Model |
|---|---|---|
| tiny | PP-OCRv6_tiny_det_onnx.tar |
PP-OCRv6_tiny_rec_0515_onnx.tar |
| small | PP-OCRv6_small_det_onnx.tar |
PP-OCRv6_small_rec_0515_onnx.tar |
| medium | PP-OCRv6_medium_det_onnx.tar |
PP-OCRv6_medium_rec_0515_onnx.tar |
Base URL: https://paddle-model-ecology.bj.bcebos.com/paddlex/official_inference_model/paddle3.0.0/tmp/
Advanced: GPU / CoreML
# Apple Silicon CoreML acceleration
ocr = PPOCRv6Onnx(
det_model_path=...,
rec_model_path=...,
rec_char_dict_path=...,
prefer_accelerator=True, # ⬅ enable hardware acceleration
)
Note: Accelerators may produce slightly different confidence scores due to hardware-specific floating-point optimizations. Text results remain identical.
Credits
- PP-OCRv6 by Baidu PaddlePaddle team
- Differentiable Binarization — Liao et al.
- CRNN + CTC — Shi et al.
- Originally created by alex (AIwork4me/ppocrv6_onnx); this fork is maintained by John Mäkelä, National Archives of Finland
- Implementation inspired by PaddleX
License
MIT
Metadata
Release files for ppocrv6-onnx-naf 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ppocrv6_onnx_naf-0.1.0.tar.gz | 94.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ppocrv6_onnx_naf-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 183.6 kB
Release files / ppocrv6_onnx_naf-0.1.0.tar.gz
| Download URL | ppocrv6_onnx_naf-0.1.0.tar.gz |
|---|---|
| Size | 94.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
09d187760e19ffc437b0a0f4b09036e264ed049679cb45b824789ebb8788452d
|
|
BLAKE2b-256 checksum How to use checksums |
0976b51c4e1489446229130bacc310b4fb29ced3669e0999978d3fc2abc00b61
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logRelease files / ppocrv6_onnx_naf-0.1.0-py3-none-any.whl
| Download URL | ppocrv6_onnx_naf-0.1.0-py3-none-any.whl |
|---|---|
| Size | 89.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3dfa4ff5c2be746e95138b3c4d1dbd02e8193c3fc882801ab75ea873c0918f88
|
|
BLAKE2b-256 checksum How to use checksums |
71092e53dd2f4ffb99fe49ea121150ad6e2bdaac64c8df16b1d3d045c0381c4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logSecurity for ppocrv6-onnx-naf 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ppocrv6_onnx_naf-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.