Skip to main content

Lightweight character recognition engine based on PP-OCRv5_mobile from PaddleOCR

Project description

CharacterOCR — Lightweight Character Recognition Engine

CharacterOCR — 轻量字符识别引擎

English | 中文


English

A lightweight OCR character recognition library based on PP-OCRv5_mobile from PaddleOCR. Single-file wrapper, ready to use out of the box. Pre-trained models (~15MB) are bundled in the models/ directory — no extra downloads needed.

Supported scenarios: Chinese/English printed & handwritten text recognition, digit recognition, vertical/rotated/curved text.

Requirements

  • Python 3.8+
  • Dependencies: paddleocr, opencv-python, numpy
# CPU version
pip install paddlepaddle==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
pip install paddleocr opencv-python numpy

# GPU version (CUDA 11.8)
pip install paddlepaddle-gpu==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
pip install paddleocr opencv-python numpy

Project Structure

ocr_module_realese/
├── character_ocr/
│   ├── __init__.py                 # Package entry point
│   ├── ocr_engine.py               # Core engine (the only source file)
│   └── models/
│       ├── PP-OCRv5_mobile_det/    # Text detection model
│       └── PP-OCRv5_mobile_rec/    # Text recognition model
├── pyproject.toml                  # Package build config
├── LICENSE-2.0.txt                 # Apache License 2.0
└── README.md

Quick Start

1. Recognize a Single Image

import cv2
from character_ocr import CharacterOCR

ocr = CharacterOCR()                          # Auto-loads models on first use

img = cv2.imread("test.jpg")
results, drawn = ocr.recognize(img)           # Returns (results, annotated_image)

for r in results:
    print(f"Text: {r.text}  Score: {r.score:.2f}  BBox: {r.bbox}")

cv2.imwrite("test_result.jpg", drawn)

2. Batch Processing Multiple Images

import cv2, os
from character_ocr import CharacterOCR

ocr = CharacterOCR()
image_dir = "./images"

for filename in os.listdir(image_dir):
    if not filename.lower().endswith((".png", ".jpg", ".jpeg", ".bmp")):
        continue
    img = cv2.imread(os.path.join(image_dir, filename))
    if img is None:
        continue

    results, drawn = ocr.recognize(img)
    print(f"{filename}: {len(results)} text regions found")
    for r in results:
        print(f"  [{r.score:.2f}] {r.text!r}")

3. Recognize Only (Skip Drawing — Faster for Batch)

results = ocr.recognize_only(img)   # Returns list[OCRResult] only
for r in results:
    print(f"[{r.score:.2f}] {r.text!r}")

4. Real-Time Camera Recognition

import cv2
from character_ocr import CharacterOCR

ocr = CharacterOCR()
cap = cv2.VideoCapture(0)  # 0 = default camera

print("Press Q to quit...")
while True:
    ret, frame = cap.read()
    if not ret:
        break

    results, drawn = ocr.recognize(frame)

    cv2.putText(drawn, f"Detected: {len(results)}", (10, 30),
                cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
    cv2.imshow("OCR Camera", drawn)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

5. Camera with Frame Skipping (Lower CPU Usage)

import cv2
from character_ocr import CharacterOCR

ocr = CharacterOCR()
cap = cv2.VideoCapture(0)

frame_count = 0
skip_interval = 10          # Run OCR every 10 frames
last_results = []

while True:
    ret, frame = cap.read()
    if not ret:
        break

    if frame_count % skip_interval == 0:
        last_results, drawn = ocr.recognize(frame)
    else:
        drawn = ocr.draw(frame, last_results)  # Reuse last results

    cv2.imshow("OCR Camera", drawn)
    frame_count += 1
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

6. Global Singleton (Convenience API)

import cv2
from character_ocr import get_ocr, recognize

# Method A: get the global singleton
ocr = get_ocr()
results, drawn = ocr.recognize(cv2.imread("test.jpg"))

# Method B: one-liner
results, drawn = recognize(cv2.imread("test.jpg"))

7. Recognize Image from URL

import cv2, numpy as np, requests
from character_ocr import CharacterOCR

ocr = CharacterOCR()
url = "https://example.com/sample.jpg"
resp = requests.get(url)
img_array = np.frombuffer(resp.content, dtype=np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)

results, drawn = ocr.recognize(img)

8. ROI-based Recognition (Crop then Recognize)

import cv2
from character_ocr import CharacterOCR

ocr = CharacterOCR()
img = cv2.imread("receipt.jpg")
roi = img[100:300, 50:500]          # Crop region (y:y+h, x:x+w)

results, drawn = ocr.recognize(roi)
for r in results:
    print(f"ROI: {r.text} ({r.score:.2f})")

API Reference

OCRResult dataclass

Attribute Type Description
text str Recognized text content
score float Confidence score (0.0 ~ 1.0)
box list[list[int]] Four corner points [[x0,y0],[x1,y1],[x2,y2],[x3,y3]], order: top-left→top-right→bottom-right→bottom-left
center tuple[float, float] Quadrilateral center (cx, cy), computed from box
bbox tuple[int, int, int, int] Axis-aligned bounding box (x, y, width, height), computed from box
to_dict() dict Convert result to dictionary

CharacterOCR class

ocr = CharacterOCR(
    score_threshold=0.3,       # Drop results below this confidence
    det_limit_side_len=960,    # Max side length for detection
    rec_batch_size=1,          # Recognition batch size
)
Method Signature Description
load() -> None Explicitly load models (auto-called on first recognize)
recognize (img_bgr: np.ndarray) -> tuple[list[OCRResult], np.ndarray] Detect + recognize, returns results & annotated image
recognize_only (img_bgr: np.ndarray) -> list[OCRResult] Detect + recognize, returns results only (no drawing)
draw (img_bgr: np.ndarray, results: list[OCRResult]) -> np.ndarray Manually draw detection boxes & labels on image copy
Property Description
loaded bool — whether models are loaded

Module-level Functions

Function Description
get_ocr(**kwargs) Get global singleton CharacterOCR instance
recognize(img_bgr) Recognize using global singleton, equivalent to get_ocr().recognize(img_bgr)

Command Line

python character_ocr/ocr_engine.py test.jpg
# Prints recognition results and saves annotated image as test_result.jpg

Model Info

Bundled PP-OCRv5_mobile models (~15MB total):

Model Directory Purpose
PP-OCRv5_mobile_det models/PP-OCRv5_mobile_det/ Text detection (locating text regions)
PP-OCRv5_mobile_rec models/PP-OCRv5_mobile_rec/ Text recognition (reading text content)

If models/ is missing or the path contains non-ASCII characters, the engine will auto-download from HuggingFace.

Notes

  • Input must be OpenCV BGR color image (np.ndarray, shape (H, W, 3), dtype uint8)
  • For grayscale images, convert first: cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
  • Non-ASCII characters in the model path may cause fallback to auto-download
  • Adjust score_threshold (default 0.3): increase for higher precision (e.g. 0.5), decrease for higher recall (e.g. 0.1)

中文

基于 PaddleOCR PP-OCRv5_mobile 的轻量级 OCR 字符识别库,单文件封装,开箱即用。模型文件(约 15MB)已随库附带在 models/ 目录中,无需额外下载。

支持场景: 中英文印刷体/手写体识别、数字识别、竖排文字、旋转文字、弯曲文字等。

环境要求

  • Python 3.8+
  • 依赖包:paddleocr, opencv-python, numpy
# CPU 版
pip install paddlepaddle==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
pip install paddleocr opencv-python numpy

# GPU 版 (CUDA 11.8)
pip install paddlepaddle-gpu==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
pip install paddleocr opencv-python numpy

目录结构

ocr_module_realese/
├── character_ocr/
│   ├── __init__.py                 # 包入口
│   ├── ocr_engine.py               # 核心引擎(唯一源码文件)
│   └── models/
│       ├── PP-OCRv5_mobile_det/    # 文字检测模型
│       └── PP-OCRv5_mobile_rec/    # 文字识别模型
├── pyproject.toml                  # 包构建配置
├── LICENSE-2.0.txt                 # Apache 2.0 许可证
└── README.md

快速上手

1. 读取单张图片并识别

import cv2
from character_ocr import CharacterOCR

ocr = CharacterOCR()                          # 首次调用自动加载模型

img = cv2.imread("test.jpg")
results, drawn = ocr.recognize(img)           # 返回 (结果列表, 标注图像)

for r in results:
    print(f"文字: {r.text}  置信度: {r.score:.2f}  位置: {r.bbox}")

cv2.imwrite("test_result.jpg", drawn)

2. 批量处理多张图片

import cv2, os
from character_ocr import CharacterOCR

ocr = CharacterOCR()
image_dir = "./images"

for filename in os.listdir(image_dir):
    if not filename.lower().endswith((".png", ".jpg", ".jpeg", ".bmp")):
        continue
    img = cv2.imread(os.path.join(image_dir, filename))
    if img is None:
        continue

    results, drawn = ocr.recognize(img)
    print(f"{filename}: 检测到 {len(results)} 个文字区域")
    for r in results:
        print(f"  [{r.score:.2f}] {r.text!r}")

3. 只识别不绘图(提升批量处理性能)

results = ocr.recognize_only(img)   # 只返回 list[OCRResult]
for r in results:
    print(f"[{r.score:.2f}] {r.text!r}")

4. 摄像头实时识别

import cv2
from character_ocr import CharacterOCR

ocr = CharacterOCR()
cap = cv2.VideoCapture(0)  # 0 = 默认摄像头

print("按 Q 键退出...")
while True:
    ret, frame = cap.read()
    if not ret:
        break

    results, drawn = ocr.recognize(frame)

    cv2.putText(drawn, f"Detected: {len(results)}", (10, 30),
                cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
    cv2.imshow("OCR Camera", drawn)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

5. 摄像头——间隔帧识别(降低 CPU 占用)

import cv2
from character_ocr import CharacterOCR

ocr = CharacterOCR()
cap = cv2.VideoCapture(0)

frame_count = 0
skip_interval = 10          # 每 10 帧识别一次
last_results = []

while True:
    ret, frame = cap.read()
    if not ret:
        break

    if frame_count % skip_interval == 0:
        last_results, drawn = ocr.recognize(frame)
    else:
        drawn = ocr.draw(frame, last_results)  # 复用上一次结果

    cv2.imshow("OCR Camera", drawn)
    frame_count += 1
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

6. 使用全局单例(快捷调用)

import cv2
from character_ocr import get_ocr, recognize

# 方式 A:获取全局单例
ocr = get_ocr()
results, drawn = ocr.recognize(cv2.imread("test.jpg"))

# 方式 B:一行调用
results, drawn = recognize(cv2.imread("test.jpg"))

7. 读取 URL 图片

import cv2, numpy as np, requests
from character_ocr import CharacterOCR

ocr = CharacterOCR()
url = "https://example.com/sample.jpg"
resp = requests.get(url)
img_array = np.frombuffer(resp.content, dtype=np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)

results, drawn = ocr.recognize(img)

8. 识别特定区域(ROI 裁剪后识别)

import cv2
from character_ocr import CharacterOCR

ocr = CharacterOCR()
img = cv2.imread("receipt.jpg")
roi = img[100:300, 50:500]          # 裁剪区域 (y:y+h, x:x+w)

results, drawn = ocr.recognize(roi)
for r in results:
    print(f"ROI 区域: {r.text} ({r.score:.2f})")

API 参考

OCRResult 数据类

属性 类型 说明
text str 识别出的文字内容
score float 置信度 (0.0 ~ 1.0)
box list[list[int]] 四点坐标 [[x0,y0],[x1,y1],[x2,y2],[x3,y3]],顺序:左上→右上→右下→左下
center tuple[float, float] 四边形中心点 (cx, cy),由 box 自动计算
bbox tuple[int, int, int, int] 轴对齐包围盒 (x, y, width, height),由 box 自动计算
to_dict() dict 将结果转为字典

CharacterOCR

ocr = CharacterOCR(
    score_threshold=0.3,       # 低于此置信度的结果将被丢弃
    det_limit_side_len=960,    # 检测阶段长边尺寸上限
    rec_batch_size=1,          # 识别批大小
)
方法 签名 说明
load() -> None 显式加载模型(recognize 首次调用时也会自动加载)
recognize (img_bgr: np.ndarray) -> tuple[list[OCRResult], np.ndarray] 检测+识别,返回结果列表和标注图像
recognize_only (img_bgr: np.ndarray) -> list[OCRResult] 检测+识别,只返回结果列表(不绘图)
draw (img_bgr: np.ndarray, results: list[OCRResult]) -> np.ndarray 手动在图片副本上绘制检测框和标签
属性 说明
loaded bool,模型是否已加载

模块级函数

函数 说明
get_ocr(**kwargs) 获取全局单例 CharacterOCR 实例
recognize(img_bgr) 使用全局单例识别一张图,等同于 get_ocr().recognize(img_bgr)

命令行

python character_ocr/ocr_engine.py test.jpg
# 输出识别结果,并将标注图保存为 test_result.jpg

模型说明

库附带 PP-OCRv5_mobile 模型(移动端轻量版),模型总大小约 15MB:

模型 目录 说明
PP-OCRv5_mobile_det models/PP-OCRv5_mobile_det/ 文字检测(定位文字区域)
PP-OCRv5_mobile_rec models/PP-OCRv5_mobile_rec/ 文字识别(识别文字内容)

models/ 目录不存在或路径包含非 ASCII 字符,引擎会自动从 HuggingFace 下载模型。

注意事项

  • 输入图片格式必须为 OpenCV BGR 彩色图np.ndarray,shape 为 (H, W, 3),dtype 为 uint8
  • 灰度图请先用 cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) 转为三通道
  • 模型路径中包含中文可能导致自动回退到网络下载
  • score_threshold 默认 0.3,可根据场景调整:对精度要求高则调高(如 0.5),对召回要求高则调低(如 0.1)

Acknowledgments / 致谢

This project is built upon the excellent work of the PaddleOCR team. The bundled models PP-OCRv5_mobile_det and PP-OCRv5_mobile_rec are part of the PaddleOCR project, licensed under Apache 2.0.

本项目基于 PaddleOCR 团队的杰出成果构建。附带的 PP-OCRv5_mobile_detPP-OCRv5_mobile_rec 模型来自 PaddleOCR 项目,基于 Apache 2.0 协议。

License / 许可证

Copyright 2026 pronoobe

Licensed under the Apache License, Version 2.0. See LICENSE-2.0.txt for the full license text.

基于 Apache License 2.0 发布。详见 LICENSE-2.0.txt

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

character_ocr-0.1.0-py3-none-any.whl (18.7 MB view details)

Uploaded Python 3

File details

Details for the file character_ocr-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: character_ocr-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.2

File hashes

Hashes for character_ocr-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c8d26846a0f0ad21487bd891d5411ff89d817562ea31bfff1076d5eef304b71c
MD5 02d87d551fa445476fa739fe5ab9e5c7
BLAKE2b-256 5ede6b2967c142c32b343f47d5129d5c30ccd25ad9da02203a918c93c199e9c5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page