news 2026/4/15 18:56:33

免费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/4/5 21:30:15

Qwen1.5-0.5B-Chat部署疑问?常见错误代码解决方案

Qwen1.5-0.5B-Chat部署疑问&#xff1f;常见错误代码解决方案 1. 为什么选它&#xff1a;轻量级对话模型的真实价值 你是不是也遇到过这样的情况&#xff1a;想快速搭一个本地聊天服务&#xff0c;但发现动辄7B、14B的大模型&#xff0c;光是加载就要8GB显存&#xff0c;连中…

作者头像 李华
网站建设 2026/3/22 3:12:33

Pi0控制中心GPU算力适配:CUDA版本兼容性与显存利用率提升技巧

Pi0控制中心GPU算力适配&#xff1a;CUDA版本兼容性与显存利用率提升技巧 1. 为什么Pi0控制中心需要精细的GPU算力管理 Pi0机器人控制中心不是普通Web应用&#xff0c;它是一个实时运行视觉-语言-动作&#xff08;VLA&#xff09;模型的工业级交互终端。当你在界面上输入“把…

作者头像 李华
网站建设 2026/4/15 18:56:13

YOLO12实战:电商商品自动标注全流程解析

YOLO12实战&#xff1a;电商商品自动标注全流程解析 在电商运营中&#xff0c;每天要处理成千上万张商品图——主图、细节图、场景图、多角度图……人工标注每张图里的商品类别、位置、数量&#xff0c;不仅耗时费力&#xff0c;还容易出错。当SKU增长到10万&#xff0c;传统标…

作者头像 李华
网站建设 2026/4/16 12:23:49

Qwen3-ASR-0.6B保姆级教程:WebUI快捷导出Markdown笔记模板

Qwen3-ASR-0.6B保姆级教程&#xff1a;WebUI快捷导出Markdown笔记模板 1. 模型简介 Qwen3-ASR-0.6B是阿里云通义千问团队开发的开源语音识别模型&#xff0c;专为高效语音转文字设计。这个模型特别适合需要将会议录音、讲座内容或日常语音快速转换为文字笔记的场景。 模型核…

作者头像 李华
网站建设 2026/4/5 9:05:18

HY-Motion 1.0高效率实践:单次生成耗时<8秒(A100 80GB)实测报告

HY-Motion 1.0高效率实践&#xff1a;单次生成耗时<8秒&#xff08;A100 80GB&#xff09;实测报告 1. 这不是“又一个”文生动作模型&#xff0c;而是动作生成的效率拐点 你有没有试过等一个动作生成结果&#xff0c;盯着进度条数到第17秒&#xff0c;心里默念“再快一点…

作者头像 李华
网站建设 2026/4/13 9:30:00

解决Angular应用与WebSocket服务器连接问题

引言 在现代Web开发中,WebSocket技术被广泛应用于实时通信,以实现即时更新和互动性。然而,连接WebSocket服务器时,开发者可能会遇到各种问题,比如无限加载、页面无法渲染等。本文将探讨在Angular应用中如何正确连接WebSocket服务器,并通过一个具体实例展示解决方案。 问…

作者头像 李华