SimdPaddleOCR README

The project's README from github.com/sdcb/SimdPaddleOCR. As one markdown file: README.md.

Sdcb.SimdPaddleOCR test NuGet License: Apache-2.0 QQ

中文 | English

纯 C# PP-OCRv6 推理库:多平台 SIMD 优化、较低内存占用、高正确率。 自带托管 ONNX 解释器,不依赖 Paddle Inference、ONNX Runtime 或 OpenCV 原生库。

核心 API 只接收 BGR8 内存,不负责图片解码,因此不会强制引入 ImageSharp、SkiaSharp 或 OpenCvSharp。

快速开始

安装核心包和 tiny 模型(tiny 会传递引用 CLS 与 ModelProvider):

dotnet add package Sdcb.SimdPaddleOCR
dotnet add package Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny
dotnet add package SixLabors.ImageSharp --version 3.1.11

模型从程序集嵌入资源直接加载,不会解压或写入临时文件。输入为 8-bit BGR,stride = 0 表示紧密排列(width * 3)。

ImageSharp 3(推荐)

using Sdcb.SimdPaddleOCR;
using Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

using PaddleOcrAll ocr = await PaddleOcrAll.LoadAsync(ChineseV6TinyModels.Default);
using Image<Bgr24> image = await Image.LoadAsync<Bgr24>("sample.jpg");
byte[] bgr = new byte[image.Width * image.Height * 3];
image.CopyPixelDataTo(bgr);
PaddleOcrResult result = ocr.Run(bgr, image.Width, image.Height);
Console.WriteLine(result.Text);

后续三个示例只演示如何解码到 BGR,加载与 Run 与上面相同。

SkiaSharp

using SkiaSharp;

SKBitmap bitmap = SKBitmap.Decode("sample.jpg")
    ?? throw new InvalidDataException("无法读取图片");
int stride = bitmap.Width * 3;
byte[] bgr = new byte[stride * bitmap.Height];
for (int y = 0; y < bitmap.Height; y++)
{
    for (int x = 0; x < bitmap.Width; x++)
    {
        SKColor color = bitmap.GetPixel(x, y);
        int offset = y * stride + x * 3;
        bgr[offset] = color.Blue;
        bgr[offset + 1] = color.Green;
        bgr[offset + 2] = color.Red;
    }
}

OpenCvSharp5

using System.Runtime.InteropServices;
using OpenCvSharp;

using Mat image = Cv2.ImRead("sample.jpg", ImreadModes.Color);
if (image.Empty()) throw new InvalidDataException("无法读取图片");
int rowBytes = image.Width * image.Channels();
byte[] bgr = new byte[rowBytes * image.Height];
for (int y = 0; y < image.Height; y++)
    Marshal.Copy(IntPtr.Add(image.Data, (int)(y * image.Step())), bgr, y * rowBytes, rowBytes);

Bitmap

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

using Bitmap bitmap = new("sample.jpg");
int stride = bitmap.Width * 3;
byte[] bgr = new byte[stride * bitmap.Height];
Rectangle rectangle = new(0, 0, bitmap.Width, bitmap.Height);
BitmapData data = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
try
{
    for (int y = 0; y < bitmap.Height; y++)
        Marshal.Copy(new IntPtr(data.Scan0.ToInt64() + y * (long)data.Stride), bgr, y * stride, stride);
}
finally
{
    bitmap.UnlockBits(data);
}

NuGet 包

NuGet 包 版本 说明
Sdcb.SimdPaddleOCR NuGet 纯托管推理核心(net10.0;netstandard2.0)
Sdcb.SimdPaddleOCR.ModelProvider NuGet 模型契约(IPaddleOcrModelProvider / PaddleOcrModelBundle),通常被传递引用
Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny NuGet PP-OCRv6 tiny DET+REC+字典;ChineseV6TinyModels.Default 含 CLS
Sdcb.SimdPaddleOCR.Models.ChineseV6Small NuGet PP-OCRv6 small;ChineseV6SmallModels.Default
Sdcb.SimdPaddleOCR.Models.ChineseV6Medium NuGet PP-OCRv6 medium;ChineseV6MediumModels.Default
Sdcb.SimdPaddleOCR.Models.TextLineOrientation NuGet PP-LCNet 文本行方向 CLS,被三个中文模型包传递引用

每个 IPaddleOcrModelProvider 提供 Name、Kind、Format、语言和版本元数据以及 OpenRead() / OpenReadAsync()。完整 OCR 组合由 PaddleOcrModelBundle 表达(DET、REC、字典和可选 CLS)。当前语言代码为 zh。单个模型也可被其他推理实现消费,例如 ChineseV6TinyModel.Detection.OpenReadAsync()。Model、PaddleOcrDetector、PaddleOcrClassifier、PaddleOcrRecognizer 和 PaddleOcrAll 均提供 Stream 加载入口;解析完成后不会继续保留完整的 ONNX 原始字节。

使用本地模型

核心不下载模型。使用本地 DET、CLS、REC 和字典文件时:

using Sdcb.SimdPaddleOCR;

using PaddleOcrAll ocr = await PaddleOcrAll.LoadAsync(
    detectionPath: "models/det.onnx",
    classificationPath: "models/cls.onnx",
    recognitionPath: "models/rec.onnx",
    dictionaryPath: "models/ppocr_keys.txt");

PaddleOcrOptions 里两套并行不要混用:DetIntraOpThreads 是检测图内的卷积线程 (一份 session,默认最多 8);LineWorkerCount 是一行一组的 CLS/REC worker 路数 (每路一个 session,上限,实际 min(请求, ProcessorCount);0 为 min(ProcessorCount, 4))。检测阈值、边界长度、方向分类、 动态识别宽度和 Session 缓存上限等也在同一组 options 里。

示例

四个示例共用 examples/sample.jpg,图片由示例负责解码并转换为 BGR:

dotnet run --project examples/ImageSharp.AspNetCore
dotnet run --project examples/OpenCvSharp5.Wpf -- path/to/image.jpg
dotnet run --project examples/SkiaSharp.Avalonia -- path/to/image.jpg
dotnet run --project examples/SystemDrawing.WinForms --framework net10.0-windows

Web 示例打开站点即可上传;API 为 POST /api/ocr(multipart/form-data 字段 file、model),文档在 /scalar。

常见问题

为什么调试时 OCR 识别特别慢?

调试器可能会在模块加载时取消 JIT 优化,使 OCR 的计算密集型代码无法获得应有的运行时优化,从而导致识别明显变慢。

请关闭该选项,然后重新启动调试会话:

支持范围

说明
目标框架 核心 net10.0;netstandard2.0;ModelProvider 与全部模型包为 netstandard2.0
推荐运行时 .NET 10:完整 x86 SIMD 与 NativeAOT(IsAotCompatible)
兼容运行时 netstandard2.0 可在 .NET Framework 4.8 等环境使用;编译时去掉 AVX / AVX-512 / VNNI 源,走 System.Numerics.Vector / 标量
CI 架构 Windows x64 / x86 / ARM64,Linux x64 / ARM64,macOS x64 / ARM64
SIMD .NET 10 运行时探测 AVX → AVX2 → AVX-512 / VNNI;无对应指令集或 ARM 时用 Vector/标量
输入 8-bit BGR 内存;无图片路径、文件或图片库 API
设备 CPU only,无 GPU
NativeAOT 裁剪发布时请保留核心程序集和所用模型程序集

许可证与第三方组件

本仓库中由本项目编写的源代码和文档采用 Apache License 2.0 发布。 Apache-2.0 提供明确的专利授权条款,更适合公开发布的库和 NuGet 包。

模型资源和第三方代码不因本项目许可证而被重新授权:

完整的第三方归属和分发说明见 THIRD-PARTY-NOTICES.md。PaddleOCR、PP-OCR 及相关名称归其 各自权利人所有,本项目不代表官方,也不构成官方背书。

性能

GitHub-hosted runner、PP-OCRv6 tiny、去掉首张 warmup 后的中位墙钟(2026-09,4 次 CI 合计):

平台 CPU ISA 中位 ms/图 工作集峰值 简评
win-x64 AMD EPYC 7763(4 vCPU) AVX2 238 ~790 MB 默认路径;正确率跨 ISA 不变
win-x64 netstandard2.0 同上 AVX2(Vector) 373 ~785 MB 约为 net10 AVX2 的 1.56×
linux-arm64 Neoverse N2 AdvSimd 273 ~847 MB replica 间几乎一条直线

同机引擎对比(win-x64 / EPYC 7763,tiny 4 worker;与上表不是同一批 VM,只看相对关系):

引擎 中位 ms/图 工作集峰值 行精确 CER
本库 224 ~790 MB 757/1022 3.53%
lw.PPOCR.C 281 ~586 MB 759/1022 4.18%
OpenVINO.NET 214 ~2600 MB 698/1022 3.63%

lw.PPOCR.C 用的是 2026 年 8 月底的一份构建,不代表该项目最新版本。

简评:墙钟接近 OpenVINO.NET、比这份 lw.PPOCR.C 快约 26%;工作集约 OpenVINO.NET 的 1/3,比 C 高一截。正确率跨 Windows / Linux / macOS 与 scalar 都是 757/1022、CER 3.53%;CER 好于该份 C,行精确高于 OpenVINO.NET。

完整环境、ISA 阶梯和读数规则见 docs/perf.md。

性能复现

GitHub Actions test 工作流 会跑单元测试,并在 Windows / Linux / macOS 多架构上对 tiny / small / medium 做 bench (含关闭 AVX-512 / AVX2 / AVX / 全部硬件加速,以及 netstandard2.0 库)。汇总报告写入 job summary 与 perf-report artifact。

微信群

如果微信群二维码过期了,请加入 QQ 群 C#/.NET计算机视觉技术交流 579060605。

SimdPaddleOCR (sdcb/SimdPaddleOCR)

Searching Database…

What is this?A pure C# OCR library for PP-OCRv6 models: it detects and recognizes text in images using hand-written SIMD-optimized kernels, and ships its own managed ONNX interpreter — no Paddle Inference, ONNX Runtime, or OpenCV native dependencies.
Is this a library I plug into my .NET code, or a ready-to-run app?A library — you reference the Sdcb.SimdPaddleOCR NuGet packages from your own .NET app. The repo also ships runnable examples: an ASP.NET Core web demo with a POST /api/ocr API, plus Avalonia, WPF, and WinForms sample apps.
How do I add it to a .NET project?Install the core package plus a model package such as Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny (it transitively brings the CLS classifier and ModelProvider). Weights load from embedded assembly resources — no downloads or temp files — and the API takes 8-bit BGR pixel buffers.
Do I need to deploy any native libraries alongside it?None. The ONNX interpreter is fully managed C#, so there are no Paddle Inference, ONNX Runtime, or OpenCV native binaries. The only thing you bring is an image decoder (ImageSharp 3, SkiaSharp, OpenCvSharp, or System.Drawing) to produce BGR8 buffers.
What are the biggest limitations right now?It's CPU-only (no GPU) and currently Chinese-only (zh models). The API accepts raw 8-bit BGR memory — no file paths or image-library helpers — and the tiny model peaks around 790 MB of RAM at ~238 ms per image on a 4-vCPU server CPU.
Which platforms and .NET runtimes does it cover?Windows x64/x86/ARM64, Linux x64/ARM64, and macOS x64/ARM64 are CI-tested. Target net10.0 for full AVX/AVX-512/VNNI SIMD and NativeAOT support, or netstandard2.0 for older runtimes like .NET Framework 4.8, which falls back to Vector/scalar.
Can I tune how many threads it uses?Yes, via PaddleOcrOptions: DetIntraOpThreads caps convolution threads inside the detection graph (one session, default max 8), while LineWorkerCount sets parallel per-line CLS/REC workers (one session each, capped at min(request, ProcessorCount); 0 means min(ProcessorCount, 4)).
Why is OCR so slow when I run it under the debugger?Debuggers can suppress JIT optimizations on module load, which cripples the compute-heavy SIMD code. Turn that off and restart the debug session — in Visual Studio uncheck it under Tools > Options > Debugging > General; in Rider under debugger JIT settings; in VS Code set csharp.debug.suppressJITOptimizations to false.
Can I load my own local model files instead of the NuGet model packages?Yes. The core itself never downloads models — you can supply local DET, CLS, REC, and dictionary files through a model provider, with detection thresholds, line-length limits, and session cache caps configured in the same PaddleOcrOptions.
Is everything in the repo under Apache-2.0?The project's own code and docs are Apache-2.0, chosen for its explicit patent grant. Model assets keep their upstream terms (they come from the PaddleOCR ecosystem), ImageSharp 3.x uses the Six Labors Split License, and the project is unofficial — not endorsed by PaddleOCR.
Creator
sdcb
Size
128.9 MB
Stars
488
Age
1mo
Commits · 90 Days