当前位置: 首页 > news >正文

C#使用OpenVinoSharp+魔塔社区的读光中英文OCR ONNX模型进行文字检测(仅检测不做识别)

效果如下:

模型链接:读光中英文OCR ONNX · 模型库

模型信息:

全部代码如下:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using OpenCvSharp;
using OpenVinoSharp;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;

namespace DBNetTextDetection
{
    public class DBNetTextDetector : IDisposable
    {
        private Core _core;
        private Model _model;
        private CompiledModel _compiledModel;
        private InferRequest _inferRequest;

        // 模型输入输出信息
        private string _inputName;
        private string _outputName;
        private int[] _inputShape;
        private int[] _outputShape;

        // 图像处理参数
        private const int ModelWidth = 800;
        private const int ModelHeight = 800;

        public DBNetTextDetector(string modelPath)
        {
            // 初始化OpenVINO Runtime
            _core = new Core();

            // 加载模型
            _model = _core.read_model(modelPath);

            // 编译模型
            _compiledModel = _core.compile_model(_model, "GPU.0");

            // 创建推理请求
            _inferRequest = _compiledModel.create_infer_request();

            // 获取输入输出信息
            var inputs = _compiledModel.get_input();
            var outputs = _compiledModel.get_output();

            _inputName = inputs.get_name();
            _inputShape = new int[] { (int)inputs.get_shape()[0], (int)inputs.get_shape()[1], (int)inputs.get_shape()[2], (int)inputs.get_shape()[3] };

            _outputName = outputs.get_name();
            if (outputs.get_shape().Count == 4)
                _outputShape = new int[] { (int)outputs.get_shape()[0], (int)outputs.get_shape()[1], (int)outputs.get_shape()[2], (int)outputs.get_shape()[3] };
            else
                _outputShape = new int[] { (int)outputs.get_shape()[0], (int)outputs.get_shape()[1], (int)outputs.get_shape()[2] };
            Console.WriteLine($"模型加载成功: {modelPath}");
            Console.WriteLine($"输入名称: {_inputName}, 形状: [{string.Join(", ", _inputShape)}]");
            Console.WriteLine($"输出名称: {_outputName}, 形状: [{string.Join(", ", _outputShape)}]");
        }

        public List<RotatedRect> DetectText(Mat image, float threshold = 0.3f, float boxThreshold = 0.5f)
        {
            // 预处理图像
            var preprocessedImage = PreprocessImage(image);

            // 准备输入Tensor
            var inputTensor = _inferRequest.get_input_tensor();
            FillTensorWithImage(inputTensor, preprocessedImage);

            // 执行推理
            _inferRequest.infer();

            // 获取输出
            var outputTensor = _inferRequest.get_output_tensor();

            // 后处理获取文本框
            var textBoxes = PostProcess(outputTensor, image.Width, image.Height, threshold, boxThreshold);

            return textBoxes;
        }

        private Mat PreprocessImage(Mat image)
        {
            // 调整图像大小到模型输入尺寸
            Mat resized = new Mat();
            Cv2.Resize(image, resized, new Size(ModelWidth, ModelHeight));

            // 转换为float32并归一化
            Mat floatImage = new Mat();
            resized.ConvertTo(floatImage, MatType.CV_32FC3, 1.0 / 255.0);

            // 注意:OpenCV默认是BGR格式,如果模型需要RGB,需要转换
            //Cv2.CvtColor(floatImage, floatImage, ColorConversionCodes.BGR2RGB);

            resized.Dispose();
            return floatImage;
        }

        private unsafe void FillTensorWithImage(Tensor tensor, Mat image)
        {
            IntPtr tensorData = tensor.data();
            int channels = image.Channels();
            int height = image.Height;
            int width = image.Width;

            // 将HWC格式转换为CHW格式
            Mat[] channelsArray = new Mat[channels];
            Cv2.Split(image, out channelsArray);

            float* tensorPtr = (float*)tensorData.ToPointer();

            for (int c = 0; c < channels; c++)
            {
                using (Mat channelMat = channelsArray[c])
                {
                    // 获取当前通道数据的指针
                    float* channelPtr = (float*)channelMat.Data.ToPointer();

                    for (int h = 0; h < height; h++)
                    {
                        for (int w = 0; w < width; w++)
                        {
                            // 计算目标索引 (CHW格式)
                            int destIndex = c * height * width + h * width + w;

                            // 计算源索引 (HW格式)
                            int srcIndex = h * width + w;

                            tensorPtr[destIndex] = channelPtr[srcIndex];
                        }
                    }
                }
            }
        }

        private List<RotatedRect> PostProcess(Tensor outputTensor, int originalWidth, int originalHeight,
                                            float threshold, float boxThreshold)
        {
            List<RotatedRect> textBoxes = new List<RotatedRect>();

            // 获取输出数据
            float[] outputData = GetTensorData(outputTensor);

            // 将一维数据转换为二维概率图
            Mat probMap = new Mat(ModelHeight, ModelWidth, MatType.CV_32FC1, outputData);

            // 二值化处理
            Mat binaryMap = new Mat();
            Cv2.Threshold(probMap, binaryMap, threshold, 1.0, ThresholdTypes.Binary);
            binaryMap.ConvertTo(binaryMap, MatType.CV_8UC1,255.0);
            Cv2.ImShow("binaryMap", binaryMap);

            // 查找轮廓
            Point[][] contours;
            HierarchyIndex[] hierarchy;
            Cv2.FindContours(binaryMap, out contours, out hierarchy,
                           RetrievalModes.List, ContourApproximationModes.ApproxSimple);

            // 处理每个轮廓
            foreach (var contour in contours)
            {
                if (contour.Length < 5) continue;

                // 获取最小外接矩形
                RotatedRect rotatedRect = Cv2.MinAreaRect(contour);

                // 过滤太小的框
                if (rotatedRect.Size.Width < 2 || rotatedRect.Size.Height < 2) continue;

                // 将坐标缩放回原始图像尺寸
                float scaleX = (float)originalWidth / ModelWidth;
                float scaleY = (float)originalHeight / ModelHeight;

                RotatedRect scaledRect = new RotatedRect(
                    new Point2f(rotatedRect.Center.X * scaleX, rotatedRect.Center.Y * scaleY),
                    new Size2f(rotatedRect.Size.Width * scaleX*2.3, rotatedRect.Size.Height * scaleY*2.0),
                    rotatedRect.Angle);

                textBoxes.Add(scaledRect);
            }

            probMap.Dispose();
            binaryMap.Dispose();

            return textBoxes;
        }

        private float[] GetTensorData(Tensor tensor)
        {
            // 根据Tensor的数据类型获取数据
            // 这里假设是float32类型
            int elementCount = 1;
            for (int i = 0; i < tensor.get_shape().Count; i++)
            {
                elementCount *= (int)tensor.get_shape()[i];
            }

            float[] data = new float[elementCount];
            Marshal.Copy(tensor.data(), data, 0, elementCount);

            return data;
        }

        public Mat DrawDetectionResult(Mat image, List<RotatedRect> textBoxes)
        {
            Mat result = image.Clone();

            foreach (var box in textBoxes)
            {
                Point2f[] points = box.Points();

                // 绘制旋转矩形
                for (int i = 0; i < 4; i++)
                {
                    Cv2.Line(result, (Point)points[i], (Point)points[(i + 1) % 4],
                            new Scalar(0, 255, 0), 2);
                }

                // 绘制中心点
                Cv2.Circle(result, (Point)box.Center, 3, new Scalar(0, 0, 255), -1);
            }

            return result;
        }

        public void Dispose()
        {
            _inferRequest?.Dispose();
            _compiledModel?.Dispose();
            _model?.Dispose();
            _core?.Dispose();
        }
    }


}

http://www.dtcms.com/a/520269.html

相关文章:

  • 积分商城小程序深圳seo网络优化公司
  • [Linux文件系统——Lesson17.软硬链接]
  • apr库在x86架构下交叉编译成arm64架构
  • 软件设计师-结构化分析方法-耦合
  • 响应式企业网站 下载网站制作是不是要先用ps做
  • 购买网站建设需要注意app软件开发制作公司电话
  • 【AI Agent】入门、学习、求职
  • C++中const与引用深度解析:从使用到底层原理
  • Product Hunt 每日热榜 | 2025-10-23
  • 【大话码游之 Observation 传说】上集:月光宝盒里的计数玄机
  • raid恢复之后数据库故障处理(ora-01200,ORA-26101,ORA-600)---惜分飞
  • 2025年中专机电一体化专业做什么工作?
  • JavaWeb 全栈学习路径:从工具到项目的实战蜕变指南
  • 中国工信备案查询网站做网站的软件电子
  • tailwindcss暗色主题切换
  • Classwork 5 - Check the HTML Tags
  • 15、【Ubuntu】【VSCode】VSCode 断联问题分析:UID 补充
  • 本地网站404错误德州网站怎样建设
  • 从被动防御到主动防护:雷池WAF+cpolar的安全实践
  • 网络营销咨询网站源码多平台网页制作
  • 广州在建火车站在哪里国内最好的危机公关公司
  • mysql锁整理
  • linux下java程序使用jprofiler进行压测
  • R语言随机森林分析显示R方和P值
  • 《Python爬虫 + 飞书自动化上传》全流程详细讲解
  • ELK——logstash
  • 图像进行拼接-后进行ocr检测识别
  • 登封网站设计wordpress终极简码
  • 网站服务器关闭建设网站需要的安全设备
  • STM32 RS422异步UART通信测试全方案C++软件开发,嵌入式软件开发,Linux