1、写在前面在《离线桌面OCR的用户有福了!试试OnnxOCR的C#版》里,我把 OnnxOCR 的 Python 实现移植成了 C# 版 OnnxOCRSharp,当时用的是 PP-OCRv5 mobile 模型,产品的MVP算是落地了。而在《PP-OCRv6 ONNX部署的官方和手搓方案》中,我又手搓了PP-OCRv6的ONNX部署方案。而今天,OnnxOCRSharp 正式支持 PP-OCRv6了。这次跟着 PP-OCRv6 的架构变化,把检测后处理、识别预处理、字典加载、图像裁剪整条流水线都重构了一遍。同时发布了0.1.1 版本——NuGet 包可以引用,桌面应用可以直接下载使用,安装包里也不再捆绑 v5 模型了。同时,我终于把github上自动化发布给玩明白了,直接下载的桌面应用是一体免安装的,打开直接使用。感觉是打开了新世界的大门,越来越有意思了!2、本次更新了啥2.1 版本目标交付物说明OnnxOcr.Core核心 OCR 引擎,适配 PP-OCRv6NuGet 包OnnxOcr.Core,方便其他 C# 项目引用OnnxOcr.Desktop 0.1.0带界面的桌面应用,可直接使用模型默认使用 PP-OCRv6_tiny 模型2.2 项目分层(延续 v5 架构)分层结构没有大改,还是在 v5 基础上做增量适配:┌─────────────────────────────────────────┐ │ OnnxOcr.Desktop 0.1.1 (WPF) │ 视图 + ViewModel + 关于页 ├─────────────────────────────────────────┤ │ OnnxOcr.App │ 应用服务、DTO ├─────────────────────────────────────────┤ │ OnnxOcr.Core │ OCR 引擎(v6 适配) ├─────────────────────────────────────────┤ │ OnnxOcr.Infrastructure │ ONNX Session、配置加载 └─────────────────────────────────────────┘2.3 流水线变化v5 时代是「检测 → [可选]方向校正 → 识别」,v6 官方 ONNX 方案简化为两阶段:图片输入 ↓ TextDetector(PP-OCRv6 det)→ DbPostProcessV6 ↓ ImageCropper(透视变换裁剪) ↓ TextRecognizer(PP-OCRv6 rec)→ CtcLabelDecode ↓ OcrResult方向分类模块保留在代码里,但默认关闭——和 Python 手搓方案保持一致。3、核心改动详解整体仍是TextSystem串联TextDetector → ImageCropper → TextRecognizer,v5 / v6共用同一套实现,差异主要体现在预设参数、模型路径和字典来源。3.1 检测模块(TextDetector + DbPostProcess)预处理:检测仍用 ImageNet 归一化检测预处理在DetPreprocessor里,v5 和 v6 走同一段代码:// DetPreprocessor.NormalizeImage — 检测侧varmean=new[]{0.485f,0.456f,0.406f};varstd=new[]{0.229f,0.224f,0.225f};// ConvertTo CV_32FC3 → 按通道 (x/255 - mean) / std另外会对过小图做 padding、按limit_side_len缩放并对齐到 32 的倍数,再转成 CHW 张量喂给 ONNX。0.5 归一化只用在识别侧(见 3.2),这一点和 Python 手搓笔记里的写法不同。后处理:DbPostProcess + findContours后处理类是DbPostProcess,v5 / v6 共用。流程是:概率图按det_db_thresh二值化得到 mask(可选 dilation)Cv2.FindContours找轮廓MinAreaRect得到旋转框,BoxScoreFast/BoxScoreSlow按区域平均概率过滤Unclip扩框后映射回原图坐标// DbPostProcess.BoxesFromBitmapCv2.FindContours(mask,outPoint[][]contours,out_,RetrievalModes.List,ContourApproximationModes.ApproxSimple);for(varindex=0;indexnumContours;index++){var(points,shortSide)=GetMiniBoxes(contour);// MinAreaRectif(shortSide3)continue