【机器视觉】C# .NET 8 部署yolov9 onnx对象检测

文章描述了一个C#程序,使用YOLOv9模型进行对象检测,展示了如何加载图片、调整尺寸、执行预测并使用OpenCvSharp进行可视化。代码中包含了测试图片加载、预测结果验证和图像显示功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这段代码展示了一个使用YOLOv9进行对象检测的简单测试框架。代码主体以及其功能分为以下几个关键部分:

  1. 创建测试图片数组 _testImages,它包含了图片文件名和对应的标签。使用 buildTests 方法来从给定的文件名中加载图片并调整尺寸,准备测试数据集。

  2. 实现了 DisplayImageWithPredictions 方法,该方法接收一个 System.Drawing.Image 对象和一组YOLO预测结果,使用OpenCvSharp的功能将图像和预测结果可视化。它首先将图像转换为字节数组,然后用Mat对象来绘制对象框和相应的标签。

  3. CheckResult 方法是一个辅助测试的方法,该方法验证预测结果的数量和标签是否符合预期。

  4. Main 方法是程序的入口点,它首先构建测试图片,然后实例化一个 Yolov8 对象用于进行预测(这里可能是代码有误,实际上是YOLOv9模型),对每个测试图片进行预测,展示预测结果,并在控制台输出对象检测框的坐标。

  5. 使用了xUnit的 Assert 方法进行断言验证,这部分通常用于自动化测试确认程序的正确性。但这里注释掉了这部分代码,可能是因为在实际的使用过程中不需要对结果进行断言。

代码展示了如何将YOLO对象检测模型集成到C#应用程序中,并使用OpenCvSharp在窗口中显示检测到的对象。整个程序流程包括加载和处理测试图像、执行模型推理、展示和验证检测结果。不过请注意,代码中有一些小的不一致之处,如 Yolov8 的实例化(YOLOv9 onnx模型)和注释掉的一些测试断言。此外,代码中的一些Yolo类和方法可能来源于特定的库或框架,但没有在代码段中直接给出,因此需要在相应上下文中查找相关的实现。

26040cdb4c45ab46319511ef7687ef57.png

using System; // 使用System命名空间,包含基础类和基本输入输出
using System.Diagnostics; // 使用System.Diagnostics命名空间,提供调试输出和性能测试等功能
using System.Drawing; // 使用System.Drawing命名空间,支持图形界面绘制
using System.Drawing.Imaging; // 使用System.Drawing.Imaging,支持高级GDI+图形功能
using Xunit; // 使用Xunit命名空间,是单元测试的框架
using Yolov7net; // 使用Yolov7net命名空间,可能是YOLO的一个.NET实现(源代码中实际为Yolov8,可能存在误导)
using Yolov7net.Extentions; // 使用Yolov7net的扩展名空间,可能包含一些额外的方法
using OpenCvSharp; // 使用OpenCvSharp库,它是OpenCV的C#语言封装


// 定义yolov9_det_opencvsharp命名空间
namespace yolov9_det_opencvsharp
{
    // 定义Program类
    internal class Program
    {
        // 声明测试用的图片数组
        public  static (Image image, string label)[] _testImages;


        // 定义buildTests方法,用以构建测试图片
        public static void  buildTests()
        {
            // 声明测试图片文件名及对应标签的数组
            var testFiles = new (string fileName, string label)[]
            {
                ("demo.jpg", "dog"),
                ("cat_224x224.jpg", "cat"),
                ("1.jpeg",""),
                ("2.png","")
            };


            // 基于提供的测试文件构建测试图片数组,包括图片和标签
            var array = new (Image image, string label)[testFiles.Length];
            // var array = new (Image image, string label)[testFiles.Length * 2];
            int i = 0;
            foreach (var tuple in testFiles)
            {
                // 从Assets文件夹加载图片
                var image = Image.FromFile("Assets/" + tuple.fileName);
                //array[i++] = (image, tuple.label);
                // 调整图片大小为640x640
                image = Utils.ResizeImage(image, 640, 640);


                // 添加到数组中
                array[i++] = (image, tuple.label);
            }


            // 将数组赋值给类的静态成员变量
            _testImages = array;
        }


        // 定义DisplayImageWithPredictions方法,用于展示带预测框的图片
        public static void DisplayImageWithPredictions(Image image, List<YoloPrediction> predictions)
        {
            // 将System.Drawing.Image转换为字节数组
            byte[] imageBytes;
            using (var ms = new MemoryStream())
            {
                image.Save(ms, ImageFormat.Bmp);
                imageBytes = ms.ToArray();
            }


            // 使用OpenCVSharp从字节数组创建Mat对象
            Mat mat = Mat.FromImageData(imageBytes, ImreadModes.Color);


            // 遍历预测结果,在图像上绘制矩形框和标签
            foreach (var prediction in predictions)
            {
                // 绘制预测框
                Cv2.Rectangle(mat,
                    new OpenCvSharp.Point(prediction.Rectangle.Left, prediction.Rectangle.Top),
                    new OpenCvSharp.Point(prediction.Rectangle.Right, prediction.Rectangle.Bottom),
                    Scalar.Red, 2);


                // 绘制标签和得分
                string labelText = $"{prediction.Label.Name} ({prediction.Score:P})";
                int baseLine;
                // 获取标签文本的尺寸
                var labelSize = Cv2.GetTextSize(labelText, HersheyFonts.HersheySimplex, 0.5, 1, out baseLine);
                // 在图形上添加文本
                Cv2.PutText(mat, labelText,
                    new OpenCvSharp.Point(prediction.Rectangle.Left, prediction.Rectangle.Top + labelSize.Height + baseLine),
                    HersheyFonts.HersheySimplex, 0.5, Scalar.Yellow, 1);
            }


            // 使用OpenCVSharp在新窗口显示带预测结果的图片
            using (new Window("Image Display", mat, WindowFlags.AutoSize))
            {
                Cv2.WaitKey(2000); // 显示图像2000毫秒,然后继续执行
                //Cv2.DestroyAllWindows(); // 关闭所有OpenCV窗口
            }
        }


        // 定义CheckResult方法,用于断言预测结果的对错
        public static  void CheckResult(List<YoloPrediction> predictions, string label)
        {
            // 断言预测结果非空
            Assert.NotNull(predictions);
            // 断言只有一个预测结果
            Assert.Equal(1, predictions.Count);
            //Assert.Equal(label, predictions[0].Label.Name);
            // 打印第一个预测结果的矩形坐标
            Console.WriteLine(predictions[0].Rectangle);
        }


        // 定义程序的主入口点Main方法
        static void Main(string[] args)
        {
            // 构建测试图片
            buildTests();
            // using var yolo = new Yolov7("./assets/yolov7-tiny.onnx", true); //yolov7 模型,不需要 nms 操作
            // 使用yolov9-c.onnx创建YOLO模型实例,并启用nms操作
            using var yolo = new Yolov8("./assets/yolov9-c.onnx", true);


            // 设置YOLO模型的默认类别标签
            yolo.SetupYoloDefaultLabels();


            // 遍历测试图片
            foreach (var tuple in _testImages)
            {
                // 对每张图片进行预测
                List<YoloPrediction> ret = yolo.Predict(tuple.image);
                //CheckResult(ret, tuple.label);
                // 输出预测结果的矩形坐标
                Console.WriteLine(ret[0].Rectangle);
                // 显示带预测框的图片
                DisplayImageWithPredictions(tuple.image,ret);
            }


            // 等待用户输入,程序暂停
            Console.ReadLine();
        }
    }
}

这段代码定义了一个使用YOLOv9模型进行对象检测的控制台应用程序。它主要执行以下步骤:

  1. buildTests 函数初始化了一个测试图片数组 _testImages,包含图片文件名和对应的标签。

  2. DisplayImageWithPredictions 函数接收一个 Image 对象和一个 YoloPrediction 列表,用OpenCVSharp将图片显示出来,并在图片上绘制检测到的对象的边界框和预测标签。

  3. CheckResult 函数对预测结果进行断言以确保正确性,这通常在测试环境下使用。

  4. Main 方法是程序的入口点,它构建测试数据,初始化YOLO模型,运行模型进行预测,并使用 DisplayImageWithPredictions 方法来展示结果。

代码中使用了Yolov7net库。程序的主要作用是进行图像处理和对象识别,并输出识别结果到控制台和图形界面展示。

### 如何在C++中部署ONNX目标检测模型 为了在C++环境中成功部署ONNX格式的目标检测模型,通常需要遵循一系列特定的操作流程。这不仅涉及安装必要的库和支持工具,还包括编写能够加载并执行推理过程的应用程序代码。 #### 安装依赖项 首先,确保已安装ONNX Runtime环境以及其对应的开发包。可以通过官方文档获取最新的安装指南[^1]。对于Linux系统而言,可以利用预编译二进制文件或者通过源码构建;而对于Windows,则推荐使用Chocolatey或vcpkg来简化这一过程。 #### 加载ONNX模型 一旦准备好了运行时环境,在应用程序内部就可以创建Session对象来进行后续操作: ```cpp #include "onnxruntime_cxx_api.h" Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(1); session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); std::unique_ptr<Ort::Session> session{new Ort::Session(env, L"path_to_your_model.onnx", session_options)}; ``` 这段代码展示了如何初始化一个`Ort::Env`实例作为全局日志配置入口,并设置会话选项以优化性能表现。接着,通过指定路径加载训练好的`.onnx`文件到内存当中形成具体的计算图结构表示形式——即`Ort::Session`类的对象。 #### 准备输入数据 由于大多数计算机视觉任务都涉及到图像处理环节,因此这里假设传入的数据为一张RGB编码方式存储的图片矩阵。考虑到不同框架间可能存在维度顺序差异(NCHW vs NHWC),所以在实际应用前还需要做适当调整转换工作: ```cpp cv::Mat image = cv::imread("input_image.jpg"); // Read an input image using OpenCV. // Preprocess the image (resize, normalize etc.) float* inputDataPtr = ...; // Pointer pointing to preprocessed data buffer. auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, inputDataPtr, total_input_size, input_node_dims.data(), num_of_dimensions); ``` 上述片段说明了怎样读取原始图像资料并通过OpenCV完成初步变换之后再构造成适合送入网络层的形式。注意这里的`total_input_size`应该等于所有像素值乘以其通道数之积,而`input_node_dims`则记录着批次大小、高度宽度及色彩分量的具体数值。 #### 执行推理运算 当一切就绪以后便可以直接调用API接口触发预测动作: ```cpp std::vector<const char*> input_names{"images"}; std::vector<const char*> output_names{"output"}; auto outputs = session->Run( Ort::RunOptions{nullptr}, /* Run options */ &input_names[0], /* Input names array pointer */ &input_tensor, /* Input tensor(s)*/ 1, /* Number of inputs*/ &output_names[0], /* Output name(s) array pointer */ static_cast<int>(outputs.size()) /* Expected number of outputs */ ); ``` 此部分实现了向量化批量求解的过程,其中指定了参与交互作用的名字列表及其对应的实际参数实体。最终得到的结果会被封装在一个动态数组内供下一步解析展示用途。 #### 解析输出结果 最后一步就是依据具体算法设计提取有用信息出来,比如边界框坐标位置、类别标签索引编号等特征属性: ```cpp for(size_t i = 0 ;i < outputs.size(); ++i){ float *preds = outputs[i].GetTensorMutableData<float>(); // Process predictions... } ``` 以上便是整个基于C++实现ONNX目标检测模型部署的大致步骤概述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值