OpenCVSharp 使用 Yolo V3 模型进行视频目标检测和分类

该博客介绍了如何在C#环境下利用OpenCVSharp库结合YOLOv3模型进行目标检测。首先,下载预训练的YOLOv3模型文件,包括cfg、weights和类别名称文件。然后,通过读取模型配置,设定阈值,对视频帧进行处理,将图像转换为blob输入网络,并获取输出层。接着,提取最佳结果,进行非极大值抑制(NMS)以消除重叠框。最后,绘制识别出的目标框及标签,并实时显示结果。整个过程展示了C#与OpenCVSharp在计算机视觉领域的应用。

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

首先下载 Yolo 训练好的模型:https://pjreddie.com/media/files/yolov3.weights

 共3个文件:yolov3.cfg,yolov3.weights,coco.names

using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenCvSharp;
using OpenCvSharp.Dnn;

namespace OpenCvSharpYolo3
{
    class Program
    {

        static string[] Labels;
        static void Main()
        {
            const string Cfg = @"h:\csharp\yolov3\yolov3.cfg";
            const string Weight = @"h:\csharp\yolov3\yolov3.weights";
            const string Names = @"h:\csharp\yolov3\coco.names";

            const float threshold = 0.5f;       //置信度阈值
            const float nmsThreshold = 0.3f;    //nms 阈值

            //读入标签
            Labels = File.ReadAllLines(Names).ToArray();

            string videofile = @"h:\csharp\videos\vtest.avi";

            var net = CvDnn.ReadNetFromDarknet(Cfg, Weight);
            //读入模型和设置
            net.SetPreferableBackend(3); // 3:DNN_BACKEND_OPENCV 
            net.SetPreferableTarget(0); //dnn target cpu

            Cv2.NamedWindow("Result", WindowMode.Normal);
            VideoCapture capture = new VideoCapture(videofile);
            while (true)
            {
                Mat org = new Mat();
                capture.Read(org);
                if (org.Empty())
                    break;
                //生成blob, 块尺寸可以是320/416/608
                var blob = CvDnn.BlobFromImage(org, 1.0 / 255, new Size(320, 320), new Scalar(), true, false);

                // 输入数据
                net.SetInput(blob);

                //获得输出层名
                var outNames = net.GetUnconnectedOutLayersNames();

                //转换成 Mat[]
                var outs = outNames.Select(_ => new Mat()).ToArray();

                net.Forward(outs, outNames);

                //从输出中获得最佳的结果
                //GetBestResult(outs, org, threshold, nmsThreshold);
                //for nms
                var classIds = new List<int>();
                var confidences = new List<float>();
                var probabilities = new List<float>();
                var boxes = new List<Rect2d>();

                var w = org.Width;
                var h = org.Height;
                const int prefix = 5;   //分类概率

                foreach (var prob in outs)
                {
                    for (var i = 0; i < prob.Rows; i++)
                    {
                        var confidence = prob.At<float>(i, 4);
                        if (confidence > threshold) //置信度大于阈值
                        {
                            //获得识别概率
                            Cv2.MinMaxLoc(prob.Row[i].ColRange(prefix, prob.Cols), out _, out Point max);
                            var classes = max.X;
                            var probability = prob.At<float>(i, classes + prefix);

                            if (probability > threshold) //概率大于阈值
                            {
                                var centerX = prob.At<float>(i, 0) * w;
                                var centerY = prob.At<float>(i, 1) * h;
                                var width = prob.At<float>(i, 2) * w;
                                var height = prob.At<float>(i, 3) * h;

                                //准备nms(非极大值抑制)数据
                                classIds.Add(classes);
                                confidences.Add(confidence);
                                probabilities.Add(probability);
                                boxes.Add(new Rect2d(centerX, centerY, width, height));
                            }
                        }
                    }
                }

                //nms(非极大值抑制)提取分数最高的
                //去除重叠和低置信度的目标框
                CvDnn.NMSBoxes(boxes, confidences, threshold, nmsThreshold, out int[] indices);

                foreach (var i in indices)
                {
                    //画出目标方框并标注置信度和分类标签
                    var box = boxes[i];
                    //Draw(image, classIds[i], confidences[i], probabilities[i], box.X, box.Y, box.Width, box.Height);
                    //标签字符串
                    int classes = classIds[i];

                    var label = string.Format("{0} {1:0.0}%", Labels[classIds[i]], probabilities[i] * 100);
                    var x1 = (box.X - box.Width / 2) < 0 ? 0 : box.X - box.Width / 2;
                    //画方框
                    org.Rectangle(new Point(x1, box.Y - box.Height / 2), new Point(box.X + box.Width / 2, box.Y + box.Height / 2), Scalar.Red, 1);

                    //标签字符大小
                    var textSize = Cv2.GetTextSize(label, HersheyFonts.HersheyTriplex, 0.5, 1, out var baseline);
                    //画标签背景框
                    Cv2.Rectangle(org, new Rect(new Point(x1, box.Y - box.Height / 2 - textSize.Height - baseline),
                        new Size(textSize.Width, textSize.Height + baseline)), Scalar.Red, Cv2.FILLED);
                    Cv2.PutText(org, label, new Point(x1, box.Y - box.Height / 2 - baseline), HersheyFonts.HersheyTriplex, 0.5, Scalar.White);
                }
                //显示结果
                Cv2.ImShow("Result", org);
                int key = Cv2.WaitKey(10);
                if (key == 27)
                    break;
            }
        }

    }
}

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值