news 2026/3/1 9:26:34

免费GPU版OCR推理库来了!不挑卡的OnnxRuntime DML方案来了

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
免费GPU版OCR推理库来了!不挑卡的OnnxRuntime DML方案来了

无论你是N卡、A卡还是集成显卡,现在都能跑出高效的OCR识别效果!

效果

测试项目

跨显卡的OCR痛点

在OCR模型部署的实际应用中,开发者常常面临这样的困境:

训练时用的N卡,部署环境却是A卡

客户机器只有集成显卡,GPU加速无法使用

不同型号显卡需要不同的推理后端配置

CUDA依赖导致部署环境复杂

特别是对于中小型开发团队或个人开发者,为每一类显卡维护不同的推理方案成本实在太高。

DML:微软的跨显卡解决方案

DirectML(Direct Machine Learning)是微软推出的高性能硬件加速DirectX 12库,它最大的优势就是 跨厂商显卡支持:

✅ 支持NVIDIA、AMD、Intel全系列显卡

✅ 无需额外安装CUDA或ROCm环境

✅ 直接使用Windows原生图形接口

✅ 性能接近专用AI推理框架

我们的OCR推理库正是基于OnnxRuntime的DML执行提供程序构建,这意味着只要你的Windows机器有DirectX 12兼容的显卡,就能享受GPU加速的OCR识别!

API接口

//ocr 初始化 extern "C" _declspec(dllexport) int __cdecl init(void** engine , bool use_gpu , int gpu_id , char* det_model_dir , int limit_side_len , double det_db_thresh , double det_db_box_thresh , double det_db_unclip_ratio , bool use_dilation , bool cls , bool use_angle_cls , char* cls_model_dir , double cls_thresh , double cls_batch_num , char* rec_model_dir , char* rec_char_dict_path , int rec_batch_num , int rec_img_h , int rec_img_w , int rec_predictor_num , char* msg); //识别 extern "C" _declspec(dllexport) int __cdecl ocr(void* engine, Mat* image, char* msg, char** ocr_result, int* ocr_result_len); //释放 extern "C" _declspec(dllexport) int __cdecl destroy(void* engine, char* msg);

C#调用案例

using Newtonsoft.Json; using OpenCvSharp; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; namespace OCRV5Test { public partial class Form1 : Form { public Form1() { InitializeComponent(); } const string DllName = "lw.OnnxRuntime.PPOCRSharp_dml.dll"; //初始化 [DllImport(DllName, EntryPoint = "init", CallingConvention = CallingConvention.Cdecl)] public extern static int init(ref IntPtr engine , 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 , bool use_dilation , bool cls , 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(DllName, EntryPoint = "ocr", CallingConvention = CallingConvention.Cdecl)] public extern static int ocr(IntPtr engine, IntPtr image, StringBuilder msg, out IntPtr ocr_result, out int ocr_result_len); //释放 [DllImport(DllName, EntryPoint = "destroy", CallingConvention = CallingConvention.Cdecl)] public extern static int destroy(IntPtr engine, StringBuilder msg); static IntPtr OCREngine; private Bitmap bmp; private String imgPath = null; private List<OCRResult> ltOCRResult; private string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tif;*.png"; private StringBuilder OCRResultInfo = new StringBuilder(); private StringBuilder OCRResultAllInfo = new StringBuilder(); Pen pen = new Pen(Brushes.Red, 2f); /// <summary> /// 选择图片 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = fileFilter; if (ofd.ShowDialog() == DialogResult.OK) { imgPath = ofd.FileName; bmp = new Bitmap(imgPath); pictureBox1.Image = bmp; richTextBox1.Clear(); button2_Click(null, null); } } /// <summary> /// 识别 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { if (OCREngine == IntPtr.Zero) { MessageBox.Show("请先初始化!!!"); return; } if (imgPath == null) { MessageBox.Show("请先选择图片!!!"); return; } button1.Enabled = false; button2.Enabled = false; richTextBox1.Clear(); OCRResultInfo.Clear(); OCRResultAllInfo.Clear(); Application.DoEvents(); Mat img = new Mat(imgPath); StringBuilder msgTemp = new StringBuilder(128); StringBuilder ocrResultStr = new StringBuilder(1024 * 100); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); IntPtr strPtr; int ocr_result_len = 0; int res = ocr(OCREngine, img.CvPtr, msgTemp, out strPtr, out ocr_result_len); img.Dispose(); byte[] buffer = new byte[ocr_result_len]; Marshal.Copy(strPtr, buffer, 0, ocr_result_len); string ocr_result = Encoding.UTF8.GetString(buffer); Marshal.FreeCoTaskMem(strPtr); 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 = Newtonsoft.Json.JsonConvert.DeserializeObject<List<OCRResult>>(ocr_result); OCRResultAllInfo.Append(JsonConvert.SerializeObject(ltOCRResult, Newtonsoft.Json.Formatting.Indented)); Graphics graphics = Graphics.FromImage(bmp); foreach (OCRResult item in ltOCRResult) { OCRResultInfo.AppendLine(item.text); System.Drawing.Point[] pt = new System.Drawing.Point[] { new System.Drawing.Point(item.x1, item.y1) , new System.Drawing.Point(item.x2, item.y2) , new System.Drawing.Point(item.x3, item.y3) , new System.Drawing.Point(item.x4, item.y4) }; graphics.DrawPolygon(pen, pt); } graphics.Dispose(); if (checkBox1.Checked) { richTextBox1.Text = OCRResultAllInfo.ToString(); } else { richTextBox1.Text = OCRResultInfo.ToString(); } pictureBox1.Image = null; pictureBox1.Image = bmp; } else { MessageBox.Show("识别失败," + msgTemp.ToString()); } img.Release(); button1.Enabled = true; button2.Enabled = true; } /// <summary> /// 初始化 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_Load(object sender, EventArgs e) { rdomobile.Checked = true; chkcls.Checked = false; chkuse_gpu.Checked = true; txtgpu_id.Text = "1"; } private void checkBox1_CheckedChanged(object sender, EventArgs e) { richTextBox1.Clear(); if (checkBox1.Checked) { richTextBox1.Text = OCRResultAllInfo.ToString(); } else { richTextBox1.Text = OCRResultInfo.ToString(); } } private void radioButton1_CheckedChanged(object sender, EventArgs e) { RadioButton rb = sender as RadioButton; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { UnloadModel(); } private void btnDestroy_Click(object sender, EventArgs e) { UnloadModel(); } void UnloadModel() { if (OCREngine != IntPtr.Zero) { StringBuilder msgTemp = new StringBuilder(128); destroy(OCREngine, msgTemp); Console.WriteLine("释放成功:" + msgTemp.ToString()); OCREngine = IntPtr.Zero; } } private void btnInit_Click(object sender, EventArgs e) { if (OCREngine != IntPtr.Zero) { StringBuilder msgTemp = new StringBuilder(128); destroy(OCREngine, msgTemp); Console.WriteLine("释放成功:" + msgTemp.ToString()); OCREngine = IntPtr.Zero; LoadModel(); } else { LoadModel(); } } void LoadModel() { StringBuilder msgTemp = new StringBuilder(128); string root_dir = Application.StartupPath + @"\inference"; bool use_gpu = true; int gpu_id = 0; string det_model_dir = ""; int limit_side_len = 960; double det_db_thresh = 0.3; double det_db_box_thresh = 0.6; double det_db_unclip_ratio = 1.2; bool use_dilation = false; bool cls = true; bool use_angle_cls = true; string cls_model_dir = ""; double cls_thresh = 0.9; int cls_batch_num = 1; string rec_model_dir = ""; string rec_char_dict_path = "inference/ppocrv5_dict.txt"; int rec_batch_num = 8; int rec_img_h = 48; int rec_img_w = 320; int predictor_num = 4; //赋值 if (chkuse_gpu.Checked == true) { use_gpu = true; } else { use_gpu = false; } gpu_id = Convert.ToInt32(txtgpu_id.Text.ToString()); det_db_thresh = Convert.ToDouble(txtdet_db_thresh.Text.ToString()); det_db_box_thresh = Convert.ToDouble(txtdet_db_box_thresh.Text.ToString()); det_db_unclip_ratio = Convert.ToDouble(txtdet_db_unclip_ratio.Text.ToString()); if (chkcls.Checked == true) { cls = true; } else { cls = false; } cls_batch_num = Convert.ToInt32(txtcls_batch_num.Text.ToString()); rec_batch_num = Convert.ToInt32(txtrec_batch_num.Text.ToString()); predictor_num = Convert.ToInt32(txtpredictor_num.Text.ToString()); if (rdomobile.Checked) { det_model_dir = "inference/PP-OCRv5_mobile_det_onnx.onnx"; rec_model_dir = "inference/PP-OCRv5_mobile_rec_onnx.onnx"; cls_model_dir = "inference/PP-OCRv5_mobile_cls_onnx.onnx"; } else { det_model_dir = "inference/PP-OCRv5_server_det_infer.onnx"; rec_model_dir = "inference/PP-OCRv5_server_rec_infer.onnx"; cls_model_dir = "inference/PP-OCRv5_server_cls_infer.onnx"; } int res = init(ref OCREngine , 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) { Console.WriteLine("模型加载成功!"); } else { string msg = msgTemp.ToString(); Console.WriteLine("模型加载失败," + msg); } } } }

下载

通过网盘分享的文件:lw.OnnxRuntime.PPOCRSharp_dml_test.rar 链接: https://pan.baidu.com/s/188r8psLROddGQrCxglyBIQ?pwd=cs37 提取码: cs37

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/27 15:34:44

个性化Minecraft启动器PCL2-CE:解决玩家痛点的终极方案

个性化Minecraft启动器PCL2-CE&#xff1a;解决玩家痛点的终极方案 【免费下载链接】PCL2-CE PCL2 社区版&#xff0c;可体验上游暂未合并的功能 项目地址: https://gitcode.com/gh_mirrors/pc/PCL2-CE Minecraft启动器频繁崩溃、Java版本不兼容、界面千篇一律——这些问…

作者头像 李华
网站建设 2026/2/22 1:11:25

数据库密码加密与安全管理

在现代软件开发中,密码管理是一个关键的安全问题。今天我们将探讨如何使用Python和PostgreSQL来创建一个安全的用户管理系统,确保密码在存储和传输时的安全性。 背景介绍 当我们开发用户系统时,通常需要存储用户的密码。然而,直接存储明文密码是极其不安全的做法。为了提…

作者头像 李华
网站建设 2026/2/19 20:28:44

Qwen3-ASR-0.6B学术应用:LaTeX论文语音笔记自动整理系统

Qwen3-ASR-0.6B学术应用&#xff1a;LaTeX论文语音笔记自动整理系统 1. 科研场景里的“听写烦恼”&#xff1a;为什么我们需要这个系统 上周参加完一场关于拓扑量子计算的学术讲座&#xff0c;我打开录音笔回放时&#xff0c;心里直打鼓——整整97分钟的密集推导&#xff0c;…

作者头像 李华
网站建设 2026/2/28 15:27:22

告别限制:NCM解密与音乐格式转换完全指南

告别限制&#xff1a;NCM解密与音乐格式转换完全指南 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 诊断加密困境&#xff1a;NCM格式的技术枷锁 当你在网易云音乐下载喜欢的歌曲时&#xff0c;是否注意到文件后缀是.ncm&#xff…

作者头像 李华
网站建设 2026/2/26 21:03:49

ContextMenuManager:让Windows右键菜单重获新生的终极工具

ContextMenuManager&#xff1a;让Windows右键菜单重获新生的终极工具 【免费下载链接】ContextMenuManager &#x1f5b1;️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager ContextMenuManager作为一款专业的右键菜单…

作者头像 李华
网站建设 2026/2/22 14:34:42

YOLOv8实战案例:零售店客流量统计系统从零搭建完整指南

YOLOv8实战案例&#xff1a;零售店客流量统计系统从零搭建完整指南 1. 为什么选YOLOv8做客流统计——不是所有目标检测都适合落地 你有没有遇到过这样的问题&#xff1a;想在小超市、社区便利店或连锁奶茶店装一套客流统计系统&#xff0c;但市面上的方案要么贵得离谱&#x…

作者头像 李华