最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#中使用YOLO的常用方式的詳細(xì)指南

 更新時間:2025年05月15日 09:18:12   作者:LeonDL168  
在C#中使用YOLO(You Only Look Once)目標(biāo)檢測算法,通常有幾種不同的實現(xiàn)方式,例如OpenCV,ONNX Runtime等,下面我們來看看具體的操作方法吧

在C#中使用YOLO(You Only Look Once)目標(biāo)檢測算法,通常有幾種不同的實現(xiàn)方式,包括使用OpenCV、ONNX Runtime或ML.NET等框架。下面為你介紹兩種常見的實現(xiàn)方法:

方法一:使用ONNX Runtime部署YOLOv5模型

這種方法的優(yōu)勢在于實現(xiàn)簡單,且性能優(yōu)化較好。

具體步驟

1.準(zhǔn)備YOLOv5模型

首先,從YOLOv5官方倉庫(https://github.com/ultralytics/yolov5 )下載預(yù)訓(xùn)練模型。

然后,將PyTorch模型轉(zhuǎn)換為ONNX格式:

python export.py --weights yolov5s.pt --include onnx

2.創(chuàng)建C#項目并安裝NuGet包

新建一個.NET Core控制臺應(yīng)用程序。

通過NuGet包管理器安裝以下組件:

  • Microsoft.ML.OnnxRuntime
  • System.Drawing.Common(用于圖像處理)

實現(xiàn)代碼

下面是一個完整的示例代碼

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;

namespace YoloV5OnnxRuntime
{
    class Program
    {
        // 檢測類別名稱
        private static readonly string[] classNames = new[] {
            "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
            "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
            "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
            "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
            "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
            "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
            "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
            "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
            "hair drier", "toothbrush"
        };

        static void Main(string[] args)
        {
            // 模型路徑和輸入圖像路徑
            string modelPath = "yolov5s.onnx";
            string imagePath = "test.jpg";
            
            // 加載模型
            using var session = new InferenceSession(modelPath);
            
            // 加載并預(yù)處理圖像
            var (inputTensor, originalWidth, originalHeight) = LoadImage(imagePath);
            
            // 準(zhǔn)備輸入?yún)?shù)
            var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("images", inputTensor) };
            
            // 運行模型推理
            using var results = session.Run(inputs);
            
            // 處理輸出結(jié)果
            var outputTensor = results.First().AsTensor<float>();
            var predictions = ProcessOutput(outputTensor, originalWidth, originalHeight);
            
            // 繪制檢測結(jié)果
            DrawPredictions(imagePath, predictions, "output.jpg");
            
            Console.WriteLine("檢測完成,結(jié)果已保存至 output.jpg");
        }

        // 加載并預(yù)處理圖像
        private static (DenseTensor<float> tensor, int width, int height) LoadImage(string imagePath)
        {
            using var image = Image.FromFile(imagePath);
            int originalWidth = image.Width;
            int originalHeight = image.Height;
            
            // 調(diào)整圖像大小為模型輸入尺寸(通常為640x640)
            var resizedImage = ResizeImage(image, 640, 640);
            
            // 圖像轉(zhuǎn)張量
            var tensor = new DenseTensor<float>(new[] { 1, 3, 640, 640 });
            var mean = new[] { 0.0f, 0.0f, 0.0f }; // 均值
            var std = new[] { 1.0f, 1.0f, 1.0f };  // 標(biāo)準(zhǔn)差
            
            using (var bitmap = new Bitmap(resizedImage))
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        var pixel = bitmap.GetPixel(x, y);
                        
                        // 注意:圖像通道順序為BGR(OpenCV默認(rèn)),而模型可能需要RGB
                        tensor[0, 0, y, x] = (pixel.R / 255.0f - mean[0]) / std[0];
                        tensor[0, 1, y, x] = (pixel.G / 255.0f - mean[1]) / std[1];
                        tensor[0, 2, y, x] = (pixel.B / 255.0f - mean[2]) / std[2];
                    }
                }
            }
            
            return (tensor, originalWidth, originalHeight);
        }

        // 調(diào)整圖像大小
        private static Image ResizeImage(Image image, int width, int height)
        {
            var destRect = new Rectangle(0, 0, width, height);
            var destImage = new Bitmap(width, height);
            
            destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
            
            using (var graphics = Graphics.FromImage(destImage))
            {
                graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
                graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                
                using (var wrapMode = new System.Drawing.Imaging.ImageAttributes())
                {
                    wrapMode.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY);
                    graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
                }
            }
            
            return destImage;
        }

        // 處理模型輸出
        private static List<Prediction> ProcessOutput(Tensor<float> output, int originalWidth, int originalHeight)
        {
            const float confidenceThreshold = 0.5f;
            const float nmsThreshold = 0.4f;
            
            var predictions = new List<Prediction>();
            
            // 解析模型輸出
            for (int i = 0; i < output.Length / 85; i++)
            {
                float confidence = output[0, i, 4];
                
                if (confidence >= confidenceThreshold)
                {
                    // 找到概率最高的類別
                    int classId = 0;
                    float maxClassProbs = 0;
                    
                    for (int c = 0; c < 80; c++)
                    {
                        float classProbs = output[0, i, 5 + c];
                        if (classProbs > maxClassProbs)
                        {
                            maxClassProbs = classProbs;
                            classId = c;
                        }
                    }
                    
                    float score = confidence * maxClassProbs;
                    
                    if (score >= confidenceThreshold)
                    {
                        // 獲取邊界框坐標(biāo)
                        float cx = output[0, i, 0];
                        float cy = output[0, i, 1];
                        float w = output[0, i, 2];
                        float h = output[0, i, 3];
                        
                        // 轉(zhuǎn)換為左上角和右下角坐標(biāo)
                        float x1 = (cx - w / 2) / 640.0f * originalWidth;
                        float y1 = (cy - h / 2) / 640.0f * originalHeight;
                        float x2 = (cx + w / 2) / 640.0f * originalWidth;
                        float y2 = (cy + h / 2) / 640.0f * originalHeight;
                        
                        predictions.Add(new Prediction
                        {
                            ClassId = classId,
                            Score = score,
                            BBox = new RectangleF(x1, y1, x2 - x1, y2 - y1)
                        });
                    }
                }
            }
            
            // 非極大值抑制
            return NonMaxSuppression(predictions, nmsThreshold);
        }

        // 非極大值抑制
        private static List<Prediction> NonMaxSuppression(List<Prediction> predictions, float threshold)
        {
            var result = new List<Prediction>();
            
            // 按置信度降序排序
            predictions = predictions.OrderByDescending(p => p.Score).ToList();
            
            while (predictions.Count > 0)
            {
                var best = predictions[0];
                result.Add(best);
                predictions.RemoveAt(0);
                
                // 移除重疊度高的邊界框
                predictions = predictions.Where(p => IoU(best.BBox, p.BBox) < threshold).ToList();
            }
            
            return result;
        }

        // 計算交并比
        private static float IoU(RectangleF a, RectangleF b)
        {
            float areaA = a.Width * a.Height;
            if (areaA <= 0) return 0;
            
            float areaB = b.Width * b.Height;
            if (areaB <= 0) return 0;
            
            float minX = Math.Max(a.Left, b.Left);
            float minY = Math.Max(a.Top, b.Top);
            float maxX = Math.Min(a.Right, b.Right);
            float maxY = Math.Min(a.Bottom, b.Bottom);
            
            float intersectionWidth = maxX - minX;
            float intersectionHeight = maxY - minY;
            
            if (intersectionWidth <= 0 || intersectionHeight <= 0)
                return 0;
                
            float intersectionArea = intersectionWidth * intersectionHeight;
            return intersectionArea / (areaA + areaB - intersectionArea);
        }

        // 繪制預(yù)測結(jié)果
        private static void DrawPredictions(string inputImagePath, List<Prediction> predictions, string outputImagePath)
        {
            using var image = Image.FromFile(inputImagePath);
            using var graphics = Graphics.FromImage(image);
            
            // 設(shè)置繪圖質(zhì)量
            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
            
            // 繪制邊界框和標(biāo)簽
            foreach (var prediction in predictions)
            {
                var bbox = prediction.BBox;
                var label = $"{classNames[prediction.ClassId]}: {prediction.Score:F2}";
                
                // 繪制邊界框
                using var pen = new Pen(Color.FromArgb(255, 255, 0, 0), 2);
                graphics.DrawRectangle(pen, bbox.X, bbox.Y, bbox.Width, bbox.Height);
                
                // 繪制標(biāo)簽背景
                using var font = new Font("Arial", 10, FontStyle.Bold);
                using var brush = new SolidBrush(Color.FromArgb(255, 255, 0, 0));
                using var textBrush = new SolidBrush(Color.White);
                
                var textSize = graphics.MeasureString(label, font);
                var textBackground = new RectangleF(bbox.X, bbox.Y - textSize.Height, textSize.Width, textSize.Height);
                
                graphics.FillRectangle(brush, textBackground);
                graphics.DrawString(label, font, textBrush, bbox.X, bbox.Y - textSize.Height);
            }
            
            // 保存結(jié)果圖像
            image.Save(outputImagePath, ImageFormat.Jpeg);
        }
    }

    // 預(yù)測結(jié)果類
    public class Prediction
    {
        public int ClassId { get; set; }
        public float Score { get; set; }
        public RectangleF BBox { get; set; }
    }
}

方法二:使用ML.NET部署YOLOv5模型

ML.NET是微軟的跨平臺機(jī)器學(xué)習(xí)框架,也可用于部署YOLO模型。

具體步驟

1.準(zhǔn)備工作與方法一相同

下載并轉(zhuǎn)換YOLOv5模型。

創(chuàng)建C#項目并安裝必要的NuGet包:

  • Microsoft.ML
  • Microsoft.ML.OnnxTransformer

實現(xiàn)代碼

下面是使用ML.NET的示例代碼:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.OnnxTransformer;
using Microsoft.ML.Trainers;

namespace YoloV5MLNet
{
    class Program
    {
        // 檢測類別名稱(同上)
        private static readonly string[] classNames = new[] { ... }; // 同上,省略
        
        static void Main(string[] args)
        {
            string modelPath = "yolov5s.onnx";
            string imagePath = "test.jpg";
            
            // 創(chuàng)建MLContext
            var mlContext = new MLContext();
            
            // 定義模型輸入輸出架構(gòu)
            var data = new List<ImageInputData> { new ImageInputData { ImagePath = imagePath } };
            var dataView = mlContext.Data.LoadFromEnumerable(data);
            
            // 定義數(shù)據(jù)轉(zhuǎn)換管道
            var pipeline = mlContext.Transforms.LoadImages(outputColumnName: "image", imageFolder: "", inputColumnName: nameof(ImageInputData.ImagePath))
                .Append(mlContext.Transforms.ResizeImages(outputColumnName: "image", imageWidth: 640, imageHeight: 640, inputColumnName: "image"))
                .Append(mlContext.Transforms.ExtractPixels(outputColumnName: "images", inputColumnName: "image", interleavePixelColors: true, offsetImage: 0))
                .Append(mlContext.Transforms.ApplyOnnxModel(
                    shapeDictionary: new Dictionary<string, int[]>()
                    {
                        { "images", new[] { 1, 3, 640, 640 } },
                        { "output", new[] { 1, 25200, 85 } }
                    },
                    inputColumnNames: new[] { "images" },
                    outputColumnNames: new[] { "output" },
                    modelFile: modelPath));
            
            // 訓(xùn)練管道(這里只是為了創(chuàng)建預(yù)測引擎)
            var model = pipeline.Fit(dataView);
            
            // 創(chuàng)建預(yù)測引擎
            var predictor = mlContext.Model.CreatePredictionEngine<ImageInputData, ImagePrediction>(model);
            
            // 進(jìn)行預(yù)測
            var prediction = predictor.Predict(new ImageInputData { ImagePath = imagePath });
            
            // 處理輸出結(jié)果
            var originalImage = Image.FromFile(imagePath);
            var predictions = ProcessOutput(prediction.Output, originalImage.Width, originalImage.Height);
            
            // 繪制檢測結(jié)果
            DrawPredictions(imagePath, predictions, "output.jpg");
            
            Console.WriteLine("檢測完成,結(jié)果已保存至 output.jpg");
        }

        // 圖像處理和結(jié)果解析方法(與ONNX Runtime版本相同)
        private static List<Prediction> ProcessOutput(float[] output, int originalWidth, int originalHeight)
        {
            // 與ONNX Runtime版本中的ProcessOutput方法相同
            // ...
        }

        // 非極大值抑制和IoU計算方法(同上)
        private static List<Prediction> NonMaxSuppression(List<Prediction> predictions, float threshold)
        {
            // ...
        }
        
        private static float IoU(RectangleF a, RectangleF b)
        {
            // ...
        }

        // 繪制預(yù)測結(jié)果(同上)
        private static void DrawPredictions(string inputImagePath, List<Prediction> predictions, string outputImagePath)
        {
            // ...
        }
    }

    // 數(shù)據(jù)模型類
    public class ImageInputData
    {
        [LoadColumn(0)]
        public string ImagePath { get; set; }
    }

    public class ImagePrediction
    {
        [ColumnName("output")]
        public float[] Output { get; set; }
    }

    // 預(yù)測結(jié)果類(同上)
    public class Prediction
    {
        public int ClassId { get; set; }
        public float Score { get; set; }
        public RectangleF BBox { get; set; }
    }
}

性能優(yōu)化建議

使用GPU加速:若要提升檢測速度,可安裝CUDA版本的ONNX Runtime,這樣就能利用GPU進(jìn)行推理。

模型量化:可以將FP32模型轉(zhuǎn)換為INT8量化模型,以此減小模型體積并提高推理速度。

批量處理:如果需要處理大量圖像,可以考慮使用批量輸入來提高吞吐量。

異步推理:對于實時應(yīng)用場景,建議使用異步API來避免阻塞主線程。

通過上述方法,你可以在C#環(huán)境中實現(xiàn)YOLO目標(biāo)檢測功能。ONNX Runtime方法更為直接,而ML.NET方法則能更好地與微軟生態(tài)系統(tǒng)集成。你可以根據(jù)自己的具體需求選擇合適的實現(xiàn)方式。

到此這篇關(guān)于C#中使用YOLO的常用方式的詳細(xì)指南的文章就介紹到這了,更多相關(guān)C#使用YOLO內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#中CompareTo的用法小結(jié)

    C#中CompareTo的用法小結(jié)

    CompareTo方法通常用于比較當(dāng)前對象與另一個對象的順序,本文主要介紹了C#中CompareTo的用法小結(jié),具有一定的參考價值,感興趣的可以了解一下
    2025-04-04
  • C#利用System.Uri轉(zhuǎn)URL為絕對地址的方法

    C#利用System.Uri轉(zhuǎn)URL為絕對地址的方法

    這篇文章主要介紹了C#利用System.Uri轉(zhuǎn)URL為絕對地址的方法,涉及C#操作URL的技巧,非常具有實用價值,需要的朋友可以參考下
    2015-02-02
  • C#實現(xiàn)啟動,關(guān)閉與查找進(jìn)程的方法

    C#實現(xiàn)啟動,關(guān)閉與查找進(jìn)程的方法

    這篇文章主要介紹了C#實現(xiàn)啟動,關(guān)閉與查找進(jìn)程的方法,通過簡單實例形式分析了C#針對進(jìn)程的啟動,關(guān)閉與查找的相關(guān)實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • C#?基礎(chǔ)數(shù)據(jù)類型之字符串類型詳解

    C#?基礎(chǔ)數(shù)據(jù)類型之字符串類型詳解

    C#字符串作為引用類型卻常被當(dāng)作值類型使用,探討其不可變性、字符串駐留及常用操作,本文給大家介紹C#?基礎(chǔ)數(shù)據(jù)類型之字符串類型,感興趣的朋友一起看看吧
    2026-05-05
  • C#實現(xiàn)綁定Combobox的方法

    C#實現(xiàn)綁定Combobox的方法

    這篇文章主要介紹了C#實現(xiàn)綁定Combobox的方法,涉及Combobox參數(shù)設(shè)置的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-08-08
  • C#優(yōu)化if...else代碼的方案總結(jié)

    C#優(yōu)化if...else代碼的方案總結(jié)

    在編寫代碼實現(xiàn)業(yè)務(wù)需求過程中,會使用到大量的if...else 判斷語句,隨業(yè)務(wù)復(fù)雜程度不同,導(dǎo)致判斷語句出現(xiàn)多層嵌套、多分支等情況,導(dǎo)致代碼可讀性變差、增加維護(hù)難度,本文介紹了C# 如何優(yōu)化 if...else 讓代碼優(yōu)雅起來,需要的朋友可以參考下
    2024-06-06
  • C# 讀取指定路徑配置文件的方法

    C# 讀取指定路徑配置文件的方法

    為了實現(xiàn)多個C#程序共用一個config文件,需要程序讀取指定路徑的config文件。代碼如下:
    2013-03-03
  • 基于Silverlight打印的使用詳解,是否為微軟的Bug問題

    基于Silverlight打印的使用詳解,是否為微軟的Bug問題

    本篇文章對Silverlight打印的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C#使用正則表達(dá)式實現(xiàn)常見的格式驗證

    C#使用正則表達(dá)式實現(xiàn)常見的格式驗證

    這篇文章主要為大家詳細(xì)介紹了C#如何使用正則表達(dá)式實現(xiàn)常見的格式驗證,例如:電話號碼、密碼、郵編等,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • C#中使用DevExpress中的ChartControl實現(xiàn)極坐標(biāo)圖的案例詳解

    C#中使用DevExpress中的ChartControl實現(xiàn)極坐標(biāo)圖的案例詳解

    這篇文章主要介紹了在C#中使用DevExpress中的ChartControl實現(xiàn)極坐標(biāo)圖,本案例是使用的是DevExpress 18.1.3版本,之前在14版本上也試過,但是有一個弊端就是實現(xiàn)極坐標(biāo)圖的時候,第一個點和最后一個點總是自動多一條閉合線,會形成一個閉合的多邊形,因此升級了一下版
    2022-02-02

最新評論

随州市| 华池县| 霍州市| 罗江县| 彭州市| 南乐县| 清水河县| 凯里市| 昭觉县| 应城市| 凯里市| 克拉玛依市| 科技| 民权县| 门头沟区| 淮安市| 红安县| 荥阳市| 班玛县| 开原市| 普陀区| 天等县| 百色市| 舟曲县| 久治县| 阳山县| 疏附县| 册亨县| 兴城市| 辰溪县| 祁阳县| 蚌埠市| 惠安县| 达尔| 株洲市| 高邮市| 博客| 武定县| 南陵县| 阜新市| 岳西县|