基于DirectML的Windows OCR推理方案
目录1. 引言2. 优势3. 效果4. OCR 模型选择与准备5. WinForm 界面实现6. 下载1. 引言本方案旨在利用 DirectML 的硬件加速能力在 Windows 系统上部署和运行一个轻量级、高精度的 OCR 模型。2. 优势其核心优势在于跨硬件兼容DirectML 支持集成显卡、独立显卡NVIDIA/AMD/Intel以及 CPU确保在不同 Windows 设备上都能获得加速。低延迟推理通过 DirectX 12 底层接口直接与硬件通信减少中间层开销实现端到端的高效推理。易于集成提供 C 和 WinRT API可方便地集成到桌面应用、UWP 应用或服务中。模型格式支持支持 ONNX 模型格式便于使用主流深度学习框架如 PyTorch, TensorFlow训练并导出的模型。3. 效果4. OCR 模型选择与准备PaddleOCR 轻量级模型百度开源的 OCR 工具包提供了优秀的轻量级中英文识别模型。5. WinForm 界面实现为了将 OCR 推理功能集成到 Windows 桌面应用中我们可以使用 WinForm 创建一个简单的图形界面。以下是一个基本的 WinForm 窗体实现包含图像选择、OCR 识别和结果显示功能。namespace OnnxRuntimeForm { public partial class Form1 : Form { private IntPtr engine IntPtr.Zero; private Bitmap currentImage null; private string imgPath null; private ListOcrResult ltOCRResult new ListOcrResult(); private StringBuilder OCRResultInfo new StringBuilder(); private StringBuilder OCRResultAllInfo new StringBuilder(); private Pen pen new Pen(Brushes.Red, 2f); private const string BaseModelDir inference; public class OcrResult { public ListListdouble box { get; set; } public double score { get; set; } public string text { get; set; } } [DllImport(OnnxRuntimeDll.dll, CallingConvention CallingConvention.Cdecl, CharSet CharSet.Unicode)] static extern int init(out IntPtr engine, [MarshalAs(UnmanagedType.U1)] bool use_gpu, int gpu_id, string det_model_dir, int limit_side_len, double det_db_thresh, double det_db_box_thresh, double det_db_unclip_ratio, [MarshalAs(UnmanagedType.U1)] bool use_dilation, [MarshalAs(UnmanagedType.U1)] bool cls, [MarshalAs(UnmanagedType.U1)] bool use_angle_cls, string cls_model_dir, double cls_thresh, double cls_batch_num, string rec_model_dir, string rec_char_dict_path, int rec_batch_num, int rec_img_h, int rec_img_w, int predictor_num, StringBuilder msg); [DllImport(OnnxRuntimeDll.dll, CallingConvention CallingConvention.Cdecl, CharSet CharSet.Unicode)] static extern int ocr(IntPtr engine, int rows, int cols, int channels, IntPtr data, StringBuilder msg, out IntPtr ocr_result, out int ocr_result_len); [DllImport(OnnxRuntimeDll.dll, CallingConvention CallingConvention.Cdecl, CharSet CharSet.Unicode)] static extern int destroy(IntPtr engine, StringBuilder msg); public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { rdoV6Tiny.Checked true; chkGPU.Checked false; chkCls.Checked false; UpdateModelPaths(); txtUnclipRatio.Text 1.8; LoadModel(); } private void rdoModel_CheckedChanged(object sender, EventArgs e) { if (((RadioButton)sender).Checked) { UpdateModelPaths(); } } private void UpdateModelPaths() { string det ; string rec ; string dict ; bool v6 false; if (rdoV5Mobile.Checked) { det Path.Combine(BaseModelDir, PP-OCRv5_mobile_det_onnx.onnx); rec Path.Combine(BaseModelDir, PP-OCRv5_mobile_rec_onnx.onnx); dict Path.Combine(BaseModelDir, ppocrv5_dict.txt); } else if (rdoV5Server.Checked) { det Path.Combine(BaseModelDir, PP-OCRv5_server_det_infer.onnx); rec Path.Combine(BaseModelDir, PP-OCRv5_server_rec_infer.onnx); dict Path.Combine(BaseModelDir, ppocrv5_dict.txt); } else if (rdoV6Tiny.Checked) { det Path.Combine(BaseModelDir, PP-OCRv6_tiny_det.onnx); rec Path.Combine(BaseModelDir, PP-OCRv6_tiny_rec.onnx); dict Path.Combine(BaseModelDir, PP-OCRv6_tiny_rec_dict.txt); v6 true; } else if (rdoV6Small.Checked) { det Path.Combine(BaseModelDir, PP-OCRv6_small_det.onnx); rec Path.Combine(BaseModelDir, PP-OCRv6_small_rec.onnx); dict Path.Combine(BaseModelDir, PP-OCRv6_small_rec_dict.txt); v6 true; } else if (rdoV6Medium.Checked) { det Path.Combine(BaseModelDir, PP-OCRv6_medium_det.onnx); rec Path.Combine(BaseModelDir, PP-OCRv6_medium_rec.onnx); dict Path.Combine(BaseModelDir, PP-OCRv6_medium_rec_dict.txt); v6 true; } txtDetModel.Text det; txtRecModel.Text rec; txtDict.Text dict; if (v6) { chkCls.Checked false; chkCls.Enabled false; } else { chkCls.Enabled true; } } private void btnInit_Click(object sender, EventArgs e) { richTextBox1.Clear(); if (engine ! IntPtr.Zero) { UnloadModel(); } LoadModel(); } private void btnSelect_Click(object sender, EventArgs e) { using (OpenFileDialog ofd new OpenFileDialog()) { ofd.Filter 图片|*.bmp;*.jpg;*.jpeg;*.tiff;*.tif;*.png;*.gif|所有文件|*.*; if (ofd.ShowDialog() DialogResult.OK) { imgPath ofd.FileName; currentImage?.Dispose(); currentImage new Bitmap(imgPath); pictureBox1.Image currentImage; richTextBoxResult.Clear(); } } } private void btnOCR_Click(object sender, EventArgs e) { if (engine IntPtr.Zero) { MessageBox.Show(请先初始化模型); return; } if (imgPath null || currentImage null) { MessageBox.Show(请先选择图片); return; } btnSelect.Enabled false; btnOCR.Enabled false; richTextBoxResult.Clear(); OCRResultInfo.Clear(); OCRResultAllInfo.Clear(); var msgTemp new StringBuilder(1024); var stopwatch System.Diagnostics.Stopwatch.StartNew(); IntPtr strPtr IntPtr.Zero; int ocr_result_len 0; string ocr_result string.Empty; int res; byte[] bgrData; using (Bitmap bgrBitmap LoadBgrBitmap(imgPath, out bgrData)) { GCHandle handle GCHandle.Alloc(bgrData, GCHandleType.Pinned); try { res ocr2(engine, bgrBitmap.Height, bgrBitmap.Width, 3, handle.AddrOfPinnedObject(), msgTemp, out strPtr, out ocr_result_len); } finally { handle.Free(); } } if (strPtr ! IntPtr.Zero ocr_result_len 0) { byte[] buffer new byte[ocr_result_len]; Marshal.Copy(strPtr, buffer, 0, ocr_result_len); ocr_result Encoding.UTF8.GetString(buffer); Marshal.FreeCoTaskMem(strPtr); strPtr IntPtr.Zero; } stopwatch.Stop(); double totalTime stopwatch.Elapsed.TotalMilliseconds; OCRResultAllInfo.AppendLine($耗时: {totalTime:F2}ms); OCRResultAllInfo.AppendLine(---------------------------); OCRResultInfo.AppendLine($耗时: {totalTime:F2}ms); OCRResultInfo.AppendLine(---------------------------); if (res 0) { ltOCRResult ParseOCRResults(ocr_result); ltOCRResult.Sort((a, b) { double ax1 a.box[0][0], ay1 a.box[0][1], ax2 a.box[0][0], ay2 a.box[0][1]; double bx1 b.box[0][0], by1 b.box[0][1], bx2 b.box[0][0], by2 b.box[0][1]; foreach (var p in a.box) { ax1 Math.Min(ax1, p[0]); ay1 Math.Min(ay1, p[1]); ax2 Math.Max(ax2, p[0]); ay2 Math.Max(ay2, p[1]); } foreach (var p in b.box) { bx1 Math.Min(bx1, p[0]); by1 Math.Min(by1, p[1]); bx2 Math.Max(bx2, p[0]); by2 Math.Max(by2, p[1]); } double y_overlap Math.Max(0, Math.Min(ay2, by2) - Math.Max(ay1, by1)); double h Math.Min(ay2 - ay1, by2 - by1); if (h 0 y_overlap / h 0.5) return ax1.CompareTo(bx1); return ay1.CompareTo(by1); }); OCRResultAllInfo.Append(FormatJson(ocr_result)); if (ltOCRResult.Count 0) { OCRResultInfo.AppendLine([未识别到文字]); OCRResultAllInfo.AppendLine([未识别到文字]); } using (Graphics graphics Graphics.FromImage(currentImage)) { foreach (OcrResult item in ltOCRResult) { OCRResultInfo.AppendLine(item.text); if (item.box ! null item.box.Count 4) { Point[] points item.box.Select(p new Point((int)p[0], (int)p[1])).ToArray(); graphics.DrawPolygon(pen, points); } } } pictureBox1.Image null; pictureBox1.Image currentImage; UpdateRichText(); } else { if (strPtr ! IntPtr.Zero) Marshal.FreeCoTaskMem(strPtr); MessageBox.Show(识别失败 msgTemp.ToString()); } btnSelect.Enabled true; btnOCR.Enabled true; } private void chkAllInfo_CheckedChanged(object sender, EventArgs e) { UpdateRichText(); } private void UpdateRichText() { richTextBoxResult.Text chkAllInfo.Checked ? OCRResultAllInfo.ToString() : OCRResultInfo.ToString(); } private double ParseDouble(TextBox tb, double defaultValue) { if (double.TryParse(tb.Text.Trim(), out double v)) return v; return defaultValue; } private int ParseInt(TextBox tb, int defaultValue) { if (int.TryParse(tb.Text.Trim(), out int v)) return v; return defaultValue; } private void LoadModel() { var msgTemp new StringBuilder(1024); bool use_gpu chkGPU.Checked; int gpu_id 0; string det_model_dir txtDetModel.Text.Trim(); int limit_side_len ParseInt(txtLimitSideLen, 960); double det_db_thresh ParseDouble(txtDbThresh, 0.3); double det_db_box_thresh ParseDouble(txtBoxThresh, 0.6); double det_db_unclip_ratio ParseDouble(txtUnclipRatio, 1.6); bool use_dilation true; bool use_angle_cls chkCls.Checked chkCls.Enabled; bool cls use_angle_cls; string cls_model_dir use_angle_cls ? Path.Combine(BaseModelDir, PP-OCRv5_mobile_cls_onnx.onnx) : ; double cls_thresh 0.9; double cls_batch_num 1; string rec_model_dir txtRecModel.Text.Trim(); string rec_char_dict_path txtDict.Text.Trim(); int rec_batch_num ParseInt(txtRecBatchNum, 8); int rec_img_h 48; int rec_img_w 960; int predictor_num 4; AppendStatus(正在初始化模型...); AppendStatus(det: det_model_dir); AppendStatus(rec: rec_model_dir); AppendStatus(dict: rec_char_dict_path); AppendStatus(device: (use_gpu ? GPU : CPU)); AppendStatus($db_thresh{det_db_thresh}, box_thresh{det_db_box_thresh}, unclip{det_db_unclip_ratio}); int res init(out engine, use_gpu, gpu_id, det_model_dir, limit_side_len, det_db_thresh, det_db_box_thresh, det_db_unclip_ratio, use_dilation, cls, use_angle_cls, cls_model_dir, cls_thresh, cls_batch_num, rec_model_dir, rec_char_dict_path, rec_batch_num, rec_img_h, rec_img_w, predictor_num, msgTemp); if (res 0) { AppendStatus(模型加载成功: msgTemp.ToString()); } else { AppendStatus(模型加载失败: msgTemp.ToString()); MessageBox.Show(模型加载失败 msgTemp.ToString()); engine IntPtr.Zero; } } private void UnloadModel() { if (engine ! IntPtr.Zero) { var msgTemp new StringBuilder(1024); destroy(engine, msgTemp); AppendStatus(释放成功: msgTemp.ToString()); engine IntPtr.Zero; } } private void AppendStatus(string text) { richTextBox1.AppendText($[{DateTime.Now:HH:mm:ss}] {text}{Environment.NewLine}); } private Bitmap LoadBgrBitmap(string path, out byte[] bgrData) { using (Bitmap source new Bitmap(path)) { Bitmap bitmap new Bitmap(source.Width, source.Height, PixelFormat.Format24bppRgb); using (Graphics g Graphics.FromImage(bitmap)) { g.DrawImage(source, 0, 0, source.Width, source.Height); } Rectangle rect new Rectangle(0, 0, bitmap.Width, bitmap.Height); BitmapData data bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); try { int rowBytes bitmap.Width * 3; bgrData new byte[rowBytes * bitmap.Height]; for (int y 0; y bitmap.Height; y) { IntPtr src IntPtr.Add(data.Scan0, y * data.Stride); Marshal.Copy(src, bgrData, y * rowBytes, rowBytes); } } finally { bitmap.UnlockBits(data); } return bitmap; } } private ListOcrResult ParseOCRResults(string json) { try { var serializer new JavaScriptSerializer(); return serializer.DeserializeListOcrResult(json) ?? new ListOcrResult(); } catch (Exception ex) { MessageBox.Show(JSON 解析失败 ex.Message); return new ListOcrResult(); } } private string FormatJson(string json) { try { var serializer new JavaScriptSerializer(); var obj serializer.Deserializeobject(json); return serializer.Serialize(obj); } catch { return json; } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { UnloadModel(); currentImage?.Dispose(); pen?.Dispose(); } } }6. 下载通过网盘分享的文件OnnxRuntime链接: https://pan.baidu.com/s/1OnmaLUQs-TIQBWzk83j4Jg 提取码: fx8n

相关新闻

计算机软考资料包考试大纲、专项题集、真题库类专项、科目资料等免费下载

计算机软考资料包考试大纲、专项题集、真题库类专项、科目资料等免费下载

计算机软考资料包考试大纲、专项题集、真题库类专项、科目资料等免费下载【领取资料】:https://docs.qq.com/aio/DV1NpZGpqaGpPdnpZ26年架构师软考高级26全国计算机等级考试资料合集2026年中级-系统集成项目管理师2026软考高级信息系统项目管理师计算机考试资料包【…

2026/7/23 13:15:48阅读更多 →
iPad Pro M2运行Win11 Pro的UTM虚拟机完整指南

iPad Pro M2运行Win11 Pro的UTM虚拟机完整指南

1. 项目背景与核心挑战 在iPad Pro 2022(M2芯片)上运行完整版Windows 11 Pro 23H2,这个看似不可能的任务通过UTM虚拟机成为了现实。作为首批在iPadOS 16.3.1系统上实现全速虚拟化的实践者,我想分享这个突破性方案的完整实现路径。…

2026/7/23 13:15:48阅读更多 →
2026 秋新版|小初高全套教辅资料免费领(持续更新)

2026 秋新版|小初高全套教辅资料免费领(持续更新)

2026 秋新版|小初高全套教辅资料免费领(持续更新)【领取资料】:https://docs.qq.com/aio/DV1NpZGpqaGpPdnpZ一、资料包含内容覆盖小学、初中、高中全学段,2026 春 / 秋新版同步更新,资源类型齐全无缺漏&…

2026/7/23 13:15:48阅读更多 →
DETR与GLIP:Transformer在目标检测中的创新应用

DETR与GLIP:Transformer在目标检测中的创新应用

1. DETR与GLIP技术概览目标检测作为计算机视觉的基础任务,经历了从传统手工特征到深度学习方法的演进。2020年Facebook提出的DETR(Detection Transformer)首次将Transformer架构引入目标检测领域,打破了传统方法依赖手工设计组件(如锚框和非极…

2026/7/23 14:42:05阅读更多 →
数据标注企业上市可行性路径分析

数据标注企业上市可行性路径分析

标注猿的第92篇原创 一个用数据视角看AI世界的标注猿 大家好,我是AI数据标注猿刘吉,一个用数据视角看AI世界的标注猿。最近我在读彼得蒂尔的《从0到1:开启商业与未来的秘密》,作者的观点一直很“毒”:创造价值不够&a…

2026/7/23 14:42:05阅读更多 →
Middleware管道在AI Agent治理中的架构设计与实践

Middleware管道在AI Agent治理中的架构设计与实践

1. 项目概述:Middleware管道在Agent治理中的核心价值 在AI Agent开发领域,我们常常面临一个关键矛盾:随着业务复杂度提升,Agent需要处理的治理逻辑(如权限管控、记忆管理、异常处理等)会呈指数级增长&#…

2026/7/23 14:42:05阅读更多 →
从零上手TI DRV2625触觉反馈评估板:硬件解析、软件调试与实战应用

从零上手TI DRV2625触觉反馈评估板:硬件解析、软件调试与实战应用

1. 从零上手:DRV2625触觉反馈评估板开箱与核心认知如果你正在寻找一个能快速上手、评估触觉反馈(Haptics)效果的硬件平台,那么德州仪器(TI)的DRV2625 Haptics BoosterPack绝对是一个不容错过的选择。作为一…

2026/7/23 14:42:05阅读更多 →
藏在小人物身上的民族精神镜像!这份《阿Q正传》深度解读别错过

藏在小人物身上的民族精神镜像!这份《阿Q正传》深度解读别错过

想沉浸式读懂鲁迅笔下这部戳中无数国人灵魂的传世经典,一定要走进这个内容详实的专属解读页面:《阿Q正传》完整深度内容 为什么这个小人物的故事,能火过百年? 很多人初读《阿Q正传》只觉得阿Q滑稽可笑,等真正读懂才发…

2026/7/23 14:42:05阅读更多 →
AI模型优化:动态计算分配提升对话系统性能

AI模型优化:动态计算分配提升对话系统性能

1. 项目概述:当AI学会"偷懒"反而更聪明最近在优化对话系统时发现一个反直觉现象:当强制AI模型减少60%的思维链计算量时,其回答准确率反而提升了12%。这就像让一个习惯反复验算的学生停止过度检查,结果考试分数不降反升。…

2026/7/23 14:40:05阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/23 0:56:31阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/23 0:56:31阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 0:56:31阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:00:28阅读更多 →
从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:28阅读更多 →
油泥处理设备哪里能买到

油泥处理设备哪里能买到

油泥处理设备哪里有?这是许多从事油田、炼化、清罐业务的从业者最关心的问题。根据河南三丰环保设备有限公司的行业经验,选购油泥处理设备的核心在于设备能否适配当地环保法规与原料特性,而非单纯看价格。该公司总经理王钦田先生指出&#xf…

2026/7/23 0:00:28阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/22 22:56:18阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/22 18:55:50阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/22 18:55:50阅读更多 →