离线桌面OCR的用户有福了!试试OnnxOCR的C#版
1、写在前面
之前有两篇文章是关于PP-OCRv5的ONNX部署的,使用的还都是python。而我真实的目的,是要将PP-OCRv5直接用在C#应用和Android应用上。毕竟很多场景就是这样纯粹。
后来对比了手搓ONNX方案和OnnxOCR,毅然选择了后者,确实有很多出彩的地方。
所以,今天我想先把OnnxOCR的python实现,转为C#实现。这样,离线桌面OCR用户就有福了。
2、从最小可行性(MVP)开始
参考OnnxOCR的核心流水线,使用WPF实现一个带界面的OCR应用,功能如下:
- 用户可选择一张图片(jpg / png / bmp / webp)
- 点击「开始识别」,在后台完成 OCR 推理
- 左侧显示原图及检测框叠加,右侧显示识别文本与置信度
- 推理结果与 OnnxOCR Python 版保持一致
3、核心技术栈
在核心技术选型中,我做出了一些突破,UI界面采用WPF+MVVM模式,之前咱可不管这那的直接上WinForm。而推理采用Microsoft.ML.OnnxRuntime,图像处理采用OpenCvSharp4 + runtime.win。
| 层次 | 技术 | 版本建议 |
|---|---|---|
| UI | WPF | 内置 |
| MVVM | CommunityToolkit.Mvvm | 8.x |
| 推理 | Microsoft.ML.OnnxRuntime | 1.20.x |
| 图像处理 | OpenCvSharp4 + runtime.win | 4.x |
简要说明下:
CommunityToolkit.Mvvm是微软官方出品的轻量级 MVVM 工具包,比 Prism 轻量,比手写 MVVM 优雅。
Microsoft.ML.OnnxRuntime是微软官方出品的 ONNX 推理引擎,支持 CPU 和 GPU,C# 世界唯一正统选择。
OpenCvSharp4 + runtime.win是OpenCV的C#绑定库,C# 社区事实标准,OpenCV 官方 C++ 库的 C# 封装。我的项目名称准备借鉴OpenCvSharp4的命名规范,就叫做OnnxOCRSharp吧。
4、OnnxOCR实现参考
在我的上一篇文章《PP-OCRv5 ONNX部署但使用OnnxOCR》中,并没有提到OnnxOCR的相关技术架构,这次不同,我们需要将技术栈切换为C#,需要了解OnnxOCR的核心流水线。
4.1 核心流水线
对应 Python 源文件映射:
| Python 模块 | 职责 |
|---|---|
predict_det.py |
检测预处理、ONNX 推理、DB 后处理 |
db_postprocess.py |
Differentiable Binarization 后处理 |
predict_rec.py |
识别预处理、批推理、归一化 |
rec_postprocess.py |
CTC 标签解码 |
orientation.py |
RapidOrientation 方向校正 |
predict_system.py |
流水线编排 |
utils.py |
图像裁剪、检测框绘制、默认参数 |
predict_base.py |
ONNX Session 管理 |
inference_engine/ |
推理引擎抽象(CPU / GPU) |
4.2 默认推理参数
| 参数 | 默认值 | 说明 |
|---|---|---|
det_limit_side_len |
960 | 检测输入最长边 |
det_limit_type |
max | 缩放策略 |
det_db_thresh |
0.3 | DB 二值化阈值 |
det_db_box_thresh |
0.6 | 检测框置信度阈值 |
det_db_unclip_ratio |
1.5 | 检测框扩展比例 |
det_box_type |
quad | 四边形检测框 |
rec_image_shape |
3, 48, 320 | 识别输入形状 |
rec_batch_num |
6 | 识别批大小 |
drop_score |
0.5 | 识别结果过滤阈值 |
use_angle_cls |
false | 默认关闭方向校正 |
5、项目系统架构
5.1 项目分层
┌─────────────────────────────────────────┐
│ OnnxOcr.Desktop (WPF) │ 视图 + ViewModel
├─────────────────────────────────────────┤
│ OnnxOcr.App │ 应用服务、DTO
├─────────────────────────────────────────┤
│ OnnxOcr.Core │ OCR 引擎(无 UI 依赖)
├─────────────────────────────────────────┤
│ OnnxOcr.Infrastructure │ ONNX Session、配置加载
└─────────────────────────────────────────┘
5.2 项目架构
架构图如下:
文字描述整个流程:
用户操作(拖拽图片)
↓
MainWindow(接收图片路径)
↓
MainViewModel(调用 OcrService)
↓
OcrService(传递给 TextSystem)
↓
TextSystem(编排):
├→ OrientationClassifier(判断方向)
├→ TextDetector(检测文字区域)→ DbPostProcess(转坐标)
└→ TextRecognizer(识别文字)→ CtcLabelDecode(转字符串)
↓
ResultVisualizer(绘制标注框)
↓
OcrService(返回结果)
↓
MainViewModel(更新绑定属性)
↓
ImageCanvas(自动重绘,显示标注结果)
6、核心模块设计
6.1 数据模型
/// <summary>单个文本行识别结果</summary>
public sealed record TextLine(
IReadOnlyList<Point2f> Box, // 4 点四边形坐标
string Text,
float Score
);
/// <summary>整张图片的 OCR 结果</summary>
public sealed record OcrResult(
IReadOnlyList<TextLine> Lines,
TimeSpan Elapsed,
int ImageWidth,
int ImageHeight
);
6.2 TextSystem 流水线
public class TextSystem
{
public OcrResult Run(Mat image, bool useCls = false)
{
// 1. 检测
var boxes = _detector.Detect(image);
if (boxes.Count == 0) return OcrResult.Empty;
// 2. 排序
boxes = BoxSorter.Sort(boxes);
// 3. 裁剪
var crops = boxes.Select(b => ImageCropper.Crop(image, b)).ToList();
// 4. [可选] 方向校正
if (useCls) crops = _classifier.Classify(crops);
// 5. 识别
var recResults = _recognizer.Recognize(crops);
// 6. 过滤 + 组装
return BuildResult(boxes, recResults);
}
}
6.3 检测模块(TextDetector)
移植自 predict_det.py + db_postprocess.py:
| 步骤 | 实现类 | Python 参考 |
|---|---|---|
| 缩放 | DetPreprocessor.ResizeForTest |
DetResizeForTest |
| 归一化 | DetPreprocessor.Normalize |
NormalizeImage |
| CHW 转换 | DetPreprocessor.ToChw |
ToCHWImage |
| ONNX 推理 | TextDetector.Infer |
det_onnx_session.run |
| DB 后处理 | DbPostProcess |
DBPostProcess |
| 边界裁剪 | TextDetector.ClipBoxes |
clip_det_res |
启动时执行 warm-up(OnnxOCR 在 predict_det.py:57 有同样逻辑),避免首次推理慢 2–10 倍。
6.4 识别模块(TextRecognizer)
移植自 predict_rec.py + rec_postprocess.py:
| 步骤 | 说明 |
|---|---|
| 动态宽度 | 按 (imgH * ratio) 计算,上限 imgW=320 |
| 归一化 | (pixel / 255.0 - 0.5) / 0.5 |
| 批推理 | 每批最多 rec_batch_num=6 张 |
| CTC 解码 | CtcLabelDecode 读取 ppocrv5_dict.txt |
6.5 方向分类(OrientationClassifier)
移植自 orientation.py,MVP 阶段实现但默认关闭(use_angle_cls=false),在设置页提供开关。
6.6 ONNX Session 管理
public interface IOnnxSessionFactory
{
InferenceSession Create(string modelPath);
}
- CPU 推理是默认配置
OcrOptions从appsettings.json加载模型路径与阈值- 应用启动时预加载 det + rec 模型并进行预热
7、来看看效果
模型采用ppocrv5的mobile版本,由于模型不是很大,直接放到项目源码中了。来看看效果吧。
我的笔记本配置如下:
- CPU:Intel Core i7-1355U
- 内存:32GB
还是那张老图,识别速度为390ms,识别结果大体OK,但是有一处文字没有识别出来,需要后续优化。
8、开源地址
代码已经开源,细节部分源码见!欢迎一起来完善这个项目。
https://github.com/lincyang/OnnxOCRSharp
欢迎关注公众号获取更多技术文章和项目更新!
参考:
1、https://github.com/jingsongliujOCR
更多推荐


所有评论(0)