C# OpenCvSharp DNN 部署yolov5旋转目标检测

目录

效果

模型信息

项目

代码

下载


C# OpenCvSharp DNN 部署yolov5旋转目标检测

效果

模型信息

Inputs
-------------------------
name:images
tensor:Float[1, 3, 1024, 1024]
---------------------------------------------------------------

Outputs
-------------------------
name:output
tensor:Float[1, 107520, 9]
---------------------------------------------------------------

项目

代码

using OpenCvSharp;
using OpenCvSharp.Dnn;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics;
using System.Reflection;
using System.Windows.Forms;

namespace OpenCvSharp_DNN_Demo
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string image_path = "";

        DateTime dt1 = DateTime.Now;
        DateTime dt2 = DateTime.Now;

        float confThreshold;
        float nmsThreshold;
        float objThreshold;

        float[,] anchors = new float[3, 10] {
                                 {27, 26, 20, 40, 44, 19, 34, 34, 25, 47},
                                 {55, 24, 44, 38, 31, 61, 50, 50, 63, 45},
                                 {65, 62, 88, 60, 84, 79, 113, 85, 148, 122}
        };

        float[] stride = new float[3] { 8.0f, 16.0f, 32.0f };

        string modelpath;

        int inpHeight;
        int inpWidth;

        List<string> class_names;
        int num_class;

        Net opencv_net;
        Mat BN_image;

        Mat image;
        Mat result_image;

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;

            pictureBox1.Image = null;
            pictureBox2.Image = null;
            textBox1.Text = "";

            image_path = ofd.FileName;
            pictureBox1.Image = new Bitmap(image_path);
            image = new Mat(image_path);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            confThreshold = 0.5f;
            nmsThreshold = 0.5f;
            objThreshold = 0.5f;

            modelpath = "model/best.onnx";

            inpHeight = 1024;
            inpWidth = 1024;

            opencv_net = CvDnn.ReadNetFromOnnx(modelpath);

            class_names = new List<string>();
            StreamReader sr = new StreamReader("model/coco.names");
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                class_names.Add(line);
            }
            num_class = class_names.Count();

            image_path = "test_img/1.png";
            pictureBox1.Image = new Bitmap(image_path);

        }

        float sigmoid(float x)
        {
            return (float)(1.0 / (1 + Math.Exp(-x)));
        }

        Mat ResizeImage(Mat srcimg, out int newh, out int neww, out int top, out int left)
        {
            int srch = srcimg.Rows, srcw = srcimg.Cols;
            top = 0;
            left = 0;
            newh = inpHeight;
            neww = inpWidth;
            Mat dstimg = new Mat();
            if (srch != srcw)
            {
                float hw_scale = (float)srch / srcw;
                if (hw_scale > 1)
                {
                    newh = inpHeight;
                    neww = (int)(inpWidth / hw_scale);
                    Cv2.Resize(srcimg, dstimg, new OpenCvSharp.Size(neww, newh), 0, 0, InterpolationFlags.Area);
                    left = (int)((inpWidth - neww) * 0.5);
                    Cv2.CopyMakeBorder(dstimg, dstimg, 0, 0, left, inpWidth - neww - left, BorderTypes.Constant);
                }
                else
                {
                    newh = (int)(inpHeight * hw_scale);
                    neww = inpWidth;
                    Cv2.Resize(srcimg, dstimg, new OpenCvSharp.Size(neww, newh), 0, 0, InterpolationFlags.Area);
                    top = (int)((inpHeight - newh) * 0.5);
                    Cv2.CopyMakeBorder(dstimg, dstimg, top, inpHeight - newh - top, 0, 0, BorderTypes.Constant);
                }
            }
            else
            {
                Cv2.Resize(srcimg, dstimg, new OpenCvSharp.Size(neww, newh));
            }
            return dstimg;
        }

        void nms_angle(List<BoxInfo> input_boxes)
        {
            input_boxes.Sort((a, b) => { return a.score > b.score ? -1 : 1; });

            float[] vArea = new float[input_boxes.Count];
            for (int i = 0; i < input_boxes.Count; ++i)
            {
                vArea[i] = input_boxes[i].box.Size.Height* input_boxes[i].box.Size.Width;
            }

            bool[] isSuppressed = new bool[input_boxes.Count];

            for (int i = 0; i < input_boxes.Count(); ++i)
            {
                if (isSuppressed[i]) { continue; }
                for (int j = i + 1; j < input_boxes.Count(); ++j)
                {
                    if (isSuppressed[j]) { continue; }
                    Point2f[] intersectingRegion;

                    Cv2.RotatedRectangleIntersection(input_boxes[i].box, input_boxes[j].box, out intersectingRegion);

                    if (intersectingRegion.Length==0) { continue; }

                    float inter = (float)Cv2.ContourArea(intersectingRegion);
                    float ovr = inter / (vArea[i] + vArea[j] - inter);

                    if (ovr >= nmsThreshold)
                    {
                        isSuppressed[j] = true;
                    }
                }
            }

            for (int i = isSuppressed.Length - 1; i >= 0; i--)
            {
                if (isSuppressed[i])
                {
                    input_boxes.RemoveAt(i);
                }
            }

        }

        private unsafe void button2_Click(object sender, EventArgs e)
        {
            if (image_path == "")
            {
                return;
            }
            textBox1.Text = "检测中,请稍等……";
            pictureBox2.Image = null;
            Application.DoEvents();

            image = new Mat(image_path);

            int newh = 0, neww = 0, padh = 0, padw = 0;
            Mat dstimg = ResizeImage(image, out newh, out neww, out padh, out padw);

            BN_image = CvDnn.BlobFromImage(dstimg, 1 / 255.0, new OpenCvSharp.Size(inpWidth, inpHeight), new Scalar(0, 0, 0), true, false);

            //配置图片输入数据
            opencv_net.SetInput(BN_image);

            //模型推理,读取推理结果
            Mat[] outs = new Mat[3] { new Mat(), new Mat(), new Mat() };
            string[] outBlobNames = opencv_net.GetUnconnectedOutLayersNames().ToArray();

            dt1 = DateTime.Now;

            opencv_net.Forward(outs, outBlobNames);

            dt2 = DateTime.Now;

            int num_proposal = outs[0].Size(1);
            int nout = outs[0].Size(2);

            if (outs[0].Dims > 2)
            {
                outs[0] = outs[0].Reshape(0, num_proposal);
            }

            float ratioh = 1.0f * image.Rows / newh, ratiow = 1.0f * image.Cols / neww;

            float* pdata = (float*)outs[0].Data;

            List<BoxInfo> generate_boxes = new List<BoxInfo>();

            int row_ind = 0;

            for (int n = 0; n < 3; n++)
            {

                int num_grid_x = (int)(inpWidth / stride[n]);
                int num_grid_y = (int)(inpHeight / stride[n]);

                for (int q = 0; q < 5; q++)    ///anchor
                {
                    float anchor_w = anchors[n, q * 2];
                    float anchor_h = anchors[n, q * 2 + 1];
                    for (int i = 0; i < num_grid_y; i++)
                    {
                        for (int j = 0; j < num_grid_x; j++)
                        {
                            float box_score = sigmoid(pdata[6]);
                            if (box_score > objThreshold)
                            {
                                Mat scores = outs[0].Row(row_ind).ColRange(7, 7 + num_class);
                                double minVal, max_class_socre;
                                OpenCvSharp.Point minLoc, classIdPoint;
                                //Get the value and location of the maximum score
                                Cv2.MinMaxLoc(scores, out minVal, out max_class_socre, out minLoc, out classIdPoint);
                                int class_idx = classIdPoint.X;
                                max_class_socre = sigmoid((float)max_class_socre) * box_score;
                                if (max_class_socre > confThreshold)
                                {
                                    float cx = (sigmoid(pdata[0]) * 2.0f - 0.5f + j) * stride[n];  //cx
                                    float cy = (sigmoid(pdata[1]) * 2.0f - 0.5f + i) * stride[n];   //cy
                                    float w = (float)(Math.Pow(sigmoid(pdata[2]) * 2.0f, 2.0f) * anchor_w);   //w
                                    float h = (float)(Math.Pow(sigmoid(pdata[3]) * 2.0f, 2.0f) * anchor_h);  //h
                                    
                                    cx = (cx - padw) * ratiow;
                                    cy = (cy - padh) * ratioh;
                                   
                                    w *= ratiow;
                                    h *= ratioh;

                                    float angle = (float)(Math.Acos(sigmoid(pdata[4])) * 180 / Math.PI);
                                    RotatedRect box = new RotatedRect(new Point2f(cx, cy), new Size2f(w, h), angle);
                                    generate_boxes.Add(new BoxInfo(box, (float)max_class_socre, class_idx));
                                }
                            }
                            row_ind++;
                            pdata += nout;
                        }
                    }
                }

            }

            nms_angle(generate_boxes);

            result_image = image.Clone();

            for (int i = 0; i < generate_boxes.Count(); ++i)
            {
                RotatedRect rectInput = generate_boxes[i].box;
                
                Point2f[] vertices =rectInput.Points();

                for (int j = 0; j < 4; j++)
                {
                    Cv2.Line(result_image, (OpenCvSharp.Point)vertices[j], (OpenCvSharp.Point)vertices[(j + 1) % 4], new Scalar(0, 0, 255), 2);
                }

                int xmin = (int)vertices[0].X;
                int ymin = (int)vertices[0].Y - 10;
                int idx = generate_boxes[i].label;
                string label = class_names[idx] + ":" + generate_boxes[i].score.ToString("0.00");
 
                Cv2.PutText(result_image, label, new OpenCvSharp.Point(xmin, ymin - 5), HersheyFonts.HersheySimplex, 0.75, new Scalar(0, 0, 255), 1);

            }

            pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());
            textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";
        }

        private void pictureBox2_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox2.Image);
        }

        private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox1.Image);
        }
    }
}

using OpenCvSharp;
using OpenCvSharp.Dnn;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics;
using System.Reflection;
using System.Windows.Forms;

namespace OpenCvSharp_DNN_Demo
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string image_path = "";

        DateTime dt1 = DateTime.Now;
        DateTime dt2 = DateTime.Now;

        float confThreshold;
        float nmsThreshold;
        float objThreshold;

        float[,] anchors = new float[3, 10] {
                                 {27, 26, 20, 40, 44, 19, 34, 34, 25, 47},
                                 {55, 24, 44, 38, 31, 61, 50, 50, 63, 45},
                                 {65, 62, 88, 60, 84, 79, 113, 85, 148, 122}
        };

        float[] stride = new float[3] { 8.0f, 16.0f, 32.0f };

        string modelpath;

        int inpHeight;
        int inpWidth;

        List<string> class_names;
        int num_class;

        Net opencv_net;
        Mat BN_image;

        Mat image;
        Mat result_image;

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;

            pictureBox1.Image = null;
            pictureBox2.Image = null;
            textBox1.Text = "";

            image_path = ofd.FileName;
            pictureBox1.Image = new Bitmap(image_path);
            image = new Mat(image_path);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            confThreshold = 0.5f;
            nmsThreshold = 0.5f;
            objThreshold = 0.5f;

            modelpath = "model/best.onnx";

            inpHeight = 1024;
            inpWidth = 1024;

            opencv_net = CvDnn.ReadNetFromOnnx(modelpath);

            class_names = new List<string>();
            StreamReader sr = new StreamReader("model/coco.names");
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                class_names.Add(line);
            }
            num_class = class_names.Count();

            image_path = "test_img/1.png";
            pictureBox1.Image = new Bitmap(image_path);

        }

        float sigmoid(float x)
        {
            return (float)(1.0 / (1 + Math.Exp(-x)));
        }

        Mat ResizeImage(Mat srcimg, out int newh, out int neww, out int top, out int left)
        {
            int srch = srcimg.Rows, srcw = srcimg.Cols;
            top = 0;
            left = 0;
            newh = inpHeight;
            neww = inpWidth;
            Mat dstimg = new Mat();
            if (srch != srcw)
            {
                float hw_scale = (float)srch / srcw;
                if (hw_scale > 1)
                {
                    newh = inpHeight;
                    neww = (int)(inpWidth / hw_scale);
                    Cv2.Resize(srcimg, dstimg, new OpenCvSharp.Size(neww, newh), 0, 0, InterpolationFlags.Area);
                    left = (int)((inpWidth - neww) * 0.5);
                    Cv2.CopyMakeBorder(dstimg, dstimg, 0, 0, left, inpWidth - neww - left, BorderTypes.Constant);
                }
                else
                {
                    newh = (int)(inpHeight * hw_scale);
                    neww = inpWidth;
                    Cv2.Resize(srcimg, dstimg, new OpenCvSharp.Size(neww, newh), 0, 0, InterpolationFlags.Area);
                    top = (int)((inpHeight - newh) * 0.5);
                    Cv2.CopyMakeBorder(dstimg, dstimg, top, inpHeight - newh - top, 0, 0, BorderTypes.Constant);
                }
            }
            else
            {
                Cv2.Resize(srcimg, dstimg, new OpenCvSharp.Size(neww, newh));
            }
            return dstimg;
        }

        void nms_angle(List<BoxInfo> input_boxes)
        {
            input_boxes.Sort((a, b) => { return a.score > b.score ? -1 : 1; });

            float[] vArea = new float[input_boxes.Count];
            for (int i = 0; i < input_boxes.Count; ++i)
            {
                vArea[i] = input_boxes[i].box.Size.Height* input_boxes[i].box.Size.Width;
            }

            bool[] isSuppressed = new bool[input_boxes.Count];

            for (int i = 0; i < input_boxes.Count(); ++i)
            {
                if (isSuppressed[i]) { continue; }
                for (int j = i + 1; j < input_boxes.Count(); ++j)
                {
                    if (isSuppressed[j]) { continue; }
                    Point2f[] intersectingRegion;

                    Cv2.RotatedRectangleIntersection(input_boxes[i].box, input_boxes[j].box, out intersectingRegion);

                    if (intersectingRegion.Length==0) { continue; }

                    float inter = (float)Cv2.ContourArea(intersectingRegion);
                    float ovr = inter / (vArea[i] + vArea[j] - inter);

                    if (ovr >= nmsThreshold)
                    {
                        isSuppressed[j] = true;
                    }
                }
            }

            for (int i = isSuppressed.Length - 1; i >= 0; i--)
            {
                if (isSuppressed[i])
                {
                    input_boxes.RemoveAt(i);
                }
            }

        }

        private unsafe void button2_Click(object sender, EventArgs e)
        {
            if (image_path == "")
            {
                return;
            }
            textBox1.Text = "检测中,请稍等……";
            pictureBox2.Image = null;
            Application.DoEvents();

            image = new Mat(image_path);

            int newh = 0, neww = 0, padh = 0, padw = 0;
            Mat dstimg = ResizeImage(image, out newh, out neww, out padh, out padw);

            BN_image = CvDnn.BlobFromImage(dstimg, 1 / 255.0, new OpenCvSharp.Size(inpWidth, inpHeight), new Scalar(0, 0, 0), true, false);

            //配置图片输入数据
            opencv_net.SetInput(BN_image);

            //模型推理,读取推理结果
            Mat[] outs = new Mat[3] { new Mat(), new Mat(), new Mat() };
            string[] outBlobNames = opencv_net.GetUnconnectedOutLayersNames().ToArray();

            dt1 = DateTime.Now;

            opencv_net.Forward(outs, outBlobNames);

            dt2 = DateTime.Now;

            int num_proposal = outs[0].Size(1);
            int nout = outs[0].Size(2);

            if (outs[0].Dims > 2)
            {
                outs[0] = outs[0].Reshape(0, num_proposal);
            }

            float ratioh = 1.0f * image.Rows / newh, ratiow = 1.0f * image.Cols / neww;

            float* pdata = (float*)outs[0].Data;

            List<BoxInfo> generate_boxes = new List<BoxInfo>();

            int row_ind = 0;

            for (int n = 0; n < 3; n++)
            {

                int num_grid_x = (int)(inpWidth / stride[n]);
                int num_grid_y = (int)(inpHeight / stride[n]);

                for (int q = 0; q < 5; q++)    ///anchor
                {
                    float anchor_w = anchors[n, q * 2];
                    float anchor_h = anchors[n, q * 2 + 1];
                    for (int i = 0; i < num_grid_y; i++)
                    {
                        for (int j = 0; j < num_grid_x; j++)
                        {
                            float box_score = sigmoid(pdata[6]);
                            if (box_score > objThreshold)
                            {
                                Mat scores = outs[0].Row(row_ind).ColRange(7, 7 + num_class);
                                double minVal, max_class_socre;
                                OpenCvSharp.Point minLoc, classIdPoint;
                                //Get the value and location of the maximum score
                                Cv2.MinMaxLoc(scores, out minVal, out max_class_socre, out minLoc, out classIdPoint);
                                int class_idx = classIdPoint.X;
                                max_class_socre = sigmoid((float)max_class_socre) * box_score;
                                if (max_class_socre > confThreshold)
                                {
                                    float cx = (sigmoid(pdata[0]) * 2.0f - 0.5f + j) * stride[n];  //cx
                                    float cy = (sigmoid(pdata[1]) * 2.0f - 0.5f + i) * stride[n];   //cy
                                    float w = (float)(Math.Pow(sigmoid(pdata[2]) * 2.0f, 2.0f) * anchor_w);   //w
                                    float h = (float)(Math.Pow(sigmoid(pdata[3]) * 2.0f, 2.0f) * anchor_h);  //h
                                    
                                    cx = (cx - padw) * ratiow;
                                    cy = (cy - padh) * ratioh;
                                   
                                    w *= ratiow;
                                    h *= ratioh;

                                    float angle = (float)(Math.Acos(sigmoid(pdata[4])) * 180 / Math.PI);
                                    RotatedRect box = new RotatedRect(new Point2f(cx, cy), new Size2f(w, h), angle);
                                    generate_boxes.Add(new BoxInfo(box, (float)max_class_socre, class_idx));
                                }
                            }
                            row_ind++;
                            pdata += nout;
                        }
                    }
                }

            }

            nms_angle(generate_boxes);

            result_image = image.Clone();

            for (int i = 0; i < generate_boxes.Count(); ++i)
            {
                RotatedRect rectInput = generate_boxes[i].box;
                
                Point2f[] vertices =rectInput.Points();

                for (int j = 0; j < 4; j++)
                {
                    Cv2.Line(result_image, (OpenCvSharp.Point)vertices[j], (OpenCvSharp.Point)vertices[(j + 1) % 4], new Scalar(0, 0, 255), 2);
                }

                int xmin = (int)vertices[0].X;
                int ymin = (int)vertices[0].Y - 10;
                int idx = generate_boxes[i].label;
                string label = class_names[idx] + ":" + generate_boxes[i].score.ToString("0.00");
 
                Cv2.PutText(result_image, label, new OpenCvSharp.Point(xmin, ymin - 5), HersheyFonts.HersheySimplex, 0.75, new Scalar(0, 0, 255), 1);

            }

            pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());
            textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";
        }

        private void pictureBox2_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox2.Image);
        }

        private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox1.Image);
        }
    }
}

下载

源码下载

猜你喜欢

转载自blog.csdn.net/lw112190/article/details/134972458