C#自学32—OpenCvSharp模板匹配,检测圆并获得圆心坐标

在这里插入图片描述

using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;

namespace DrawROI
{
    public partial class Form1 : Form
    {
        private System.Drawing.Point RectStartPoint, tempEndPoint;
        bool blnDraw;
        Mat ImageROI;
        Mat OrgMat;
        private string FilePath;
        public Form1()
        {
            InitializeComponent();
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            RectStartPoint = e.Location; //获得鼠标按下的pictureBox上坐标
            Invalidate();
            blnDraw = true;//判断标志
        }
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (blnDraw)
            {
                if (e.Button != MouseButtons.Left)//判断是否按下左键
                {
                    return;
                }

                tempEndPoint = e.Location; //记录框的位置和大小
                //pictureBox上开始点坐标
                //Rect.Location = new System.Drawing.Point(
                //Math.Min(RectStartPoint.X, tempEndPoint.X),
                //Math.Min(RectStartPoint.Y, tempEndPoint.Y));
                pictureBox上矩形大小
                //Rect.Size = new System.Drawing.Size(
                //Math.Abs(RectStartPoint.X - tempEndPoint.X),
                //Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
                pictureBox1.Invalidate();


                // 最后点位置
                int X0, Y0;
                Utilities.ConvertCoordinates(pictureBox1, out X0, out Y0, e.X, e.Y);

                //在控件中
                //textBox1.Text = Convert.ToString("pictureBox最后点坐标" + e.X + "  ," + e.Y); //pictureBox 上终点坐标
                //textBox2.Text = Convert.ToString("pictureBox开始点坐标" + Rect.X + "  ," + Rect.Y); //开始点坐标
                //textBox3.Text = Convert.ToString("pictureBox的Width" + Rect.Width + "  ," + Rect.Height);//大小

                //Create ROI 感兴趣区域
                Utilities.ConvertCoordinates(pictureBox1, out X0, out Y0, RectStartPoint.X, RectStartPoint.Y);
                int X1, Y1;
                Utilities.ConvertCoordinates(pictureBox1, out X1, out Y1, tempEndPoint.X, tempEndPoint.Y);

                //感兴趣区域 左上点坐标-宽-高
                //RealImageRect.Location = new System.Drawing.Point(
                //    Math.Min(X0, X1),
                //    Math.Min(Y0, Y1));
                //RealImageRect.Size = new System.Drawing.Size(
                //    Math.Abs(X0 - X1),
                //    Math.Abs(Y0 - Y1));
                //textBox4.Text = "原图像上最后点坐标: X:" + X0 + "  Y:" + Y0;
                //textBox5.Text = "原图像上RealImageRect: X:" + RealImageRect.X + "  Y:" + RealImageRect.Y; // 原图像-左上点坐标
                //textBox6.Text = "原图像上RealImageRectSize: X:" + RealImageRect.Width + "  Y:" + RealImageRect.Height; // 原图像-大小


                Rect tmp_Rect = new Rect(Math.Min(X0, X1), Math.Min(Y0, Y1), Math.Abs(X0 - X1), Math.Abs(Y0 - Y1));
                ImageROI = new Mat(OrgMat, tmp_Rect);//新建一个mat,把roi内的图像加载到里面去。
                                                     //Cv2.ImWrite("4.jpg",ImageROI);  //保存       

            }
        }
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            // mouseUp 结束以后 将图像显示在pictureBox2控件中
            pictureBox2.Image = ImageROI.ToBitmap();
            //***************************************//
            blnDraw = false; //结束绘制      
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.ShowDialog();
            //openFileDialog.Multiselect=true;
            FilePath = openFileDialog.FileName;
            OrgMat = new Mat(FilePath, ImreadModes.Grayscale);
            OrgMat.MedianBlur(3);
            pictureBox1.Image = BitmapConverter.ToBitmap(OrgMat);
        }

        private void button3_Click(object sender, EventArgs e)
        {

            if (ImageROI == null)
            {
                MessageBox.Show("请先绘制模板");
                return ;
            }

            Mat RoiClone = ImageROI.Clone();


            Mat mat3 = new Mat();
            //创建result的模板,就是MatchTemplate里的第三个参数
            //mat3.Create(mat1.Cols - mat2.Cols + 1, mat1.Rows - mat2.Rows + 1, MatType.CV_32FC1);

            //进行匹配(1母图,2模版子图,3返回的result,4匹配模式)
            Cv2.MatchTemplate(OrgMat, RoiClone, mat3, TemplateMatchModes.SqDiff);

            //对结果进行归一化(这里我测试的时候没有发现有什么用,但在opencv的书里有这个操作,应该有什么神秘加成,这里也加上)
            Cv2.Normalize(mat3, mat3, 1, 0, NormTypes.MinMax, -1);

            //double minValue, maxValue;
            Point minLocation, maxLocation;
            /// 通过函数 minMaxLoc 定位最匹配的位置
            /// (这个方法在opencv里有5个参数,这里我写的时候发现在有3个重载,看了下可以直接写成拿到起始坐标就不取最大值和最小值了)
            /// minLocation和maxLocation根据匹配调用的模式取不同的点
            Cv2.MinMaxLoc(mat3, out minLocation, out maxLocation);
            Mat OrgMatClone = OrgMat.Clone();
            //画出匹配的矩,
            //Cv2.Rectangle(mask, maxLocation, new Point(maxLocation.X + mat2.Cols, maxLocation.Y + mat2.Rows), Scalar.Red, 2);
            //Cv2.Rectangle(OrgMatClone, minLocation, new Point(minLocation.X + RoiClone.Cols, minLocation.Y + RoiClone.Rows), Scalar.Red, 2);
            //Cv2.ImShow("mat1", mat1);
            //Cv2.ImShow("mat2", mat2);


            //霍夫圆检测:使用霍夫变换查找灰度图像中的圆。
            /*
             * 参数:
             *      1:输入参数: 8位、单通道、灰度输入图像
             *      2:实现方法:目前,唯一的实现方法是HoughCirclesMethod.Gradient
             *      3: dp      :累加器分辨率与图像分辨率的反比。默认=1
             *      4:minDist: 检测到的圆的中心之间的最小距离。(最短距离-可以分辨是两个圆的,否则认为是同心圆-                            src_gray.rows/8)
             *      5:param1:   第一个方法特定的参数。[默认值是100] canny边缘检测阈值低
             *      6:param2:   第二个方法特定于参数。[默认值是100] 中心点累加器阈值 – 候选圆心
             *      7:minRadius: 最小半径
             *      8:maxRadius: 最大半径
             * 
             */
            CircleSegment[] cs = Cv2.HoughCircles(RoiClone, HoughMethods.Gradient, 1, 80, 70, 100, 100, 200);
            
            for (int i = 0; i < cs.Count(); i++)
            {
                //画圆
                Cv2.Circle(OrgMatClone, (int)(cs[i].Center.X + minLocation.X), (int)(cs[i].Center.Y + minLocation.Y), (int)cs[i].Radius, new Scalar(0, 0, 255), 2, LineTypes.AntiAlias);
                //加强圆心显示
                Cv2.Circle(OrgMatClone, (int)cs[i].Center.X, (int)cs[i].Center.Y, 3, new Scalar(0, 0, 255), 2, LineTypes.AntiAlias);
                textBox1.Text = cs[i].Center.X.ToString();
                textBox2.Text = cs[i].Center.Y.ToString();
            }

            //pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            pictureBox1.Image = BitmapConverter.ToBitmap(OrgMatClone);



        }

        //private void pictureBox1_Paint(object sender, PaintEventArgs e)
        //{
        //    if (blnDraw)
        //    {
        //        if (pictureBox1.Image != null)
        //        {
        //            if (Rect != null && Rect.Width > 0 && Rect.Height > 0)
        //            {
        //                e.Graphics.DrawRectangle(new Pen(Color.Red, 1), Rect);//重新绘制颜色为红色
        //            }
        //        }
        //    }
        //}
        public class Utilities
        {
            //坐标转换
            //**************************************
            //* 图片左边转换,
            //* Input输入: pictureBox 坐标X,Y
            //* Output输出: Image 图像上对应的坐标
            //**************************************//
            public static void ConvertCoordinates(PictureBox pic,
                out int X0, out int Y0, int x, int y)
            {
                int pic_hgt = pic.ClientSize.Height;
                int pic_wid = pic.ClientSize.Width;
                int img_hgt = pic.Image.Height;
                int img_wid = pic.Image.Width;

                X0 = x;
                Y0 = y;
                switch (pic.SizeMode)
                {
                    case PictureBoxSizeMode.AutoSize:
                    case PictureBoxSizeMode.StretchImage:
                        X0 = (int)(img_wid * x / (float)pic_wid);
                        Y0 = (int)(img_hgt * y / (float)pic_hgt);
                        break;
                }
            }

        }


        //******************************************************************//
        /// 

        /// 多角度模板匹配方法
        /// 
        /// 待匹配图像
        /// 模板图像
        /// 起始角度
        /// 角度范围
        /// 角度步长
        /// 金字塔层级
        /// 得分阈值
        /// 
        //Mat ImageRotate;
        
        //private ResultPoint CircleMatchNcc(Mat srcImage, Mat modelImage, double angleStart, double angleRange, double angleStep, int numLevels, double thresScore, int nccMethod)
        //{
        //    double step = angleRange / ((angleRange / angleStep) / 100);
        //    double start = angleStart;
        //    double range = angleRange;

        //    //定义图片匹配所需要的参数
        //    int resultCols = srcImage.Cols - modelImage.Cols + 1;
        //    int resultRows = srcImage.Rows - modelImage.Cols + 1;
        //    Mat result = new Mat(resultCols, resultRows, MatType.CV_8U);
        //    Mat src = new Mat();
        //    Mat model = new Mat();
        //    srcImage.CopyTo(src);
        //    modelImage.CopyTo(model);

        //    //对模板图像和待检测图像分别进行图像金字塔下采样
        //    for (int i = 0; i < numLevels; i++)
        //    {
        //        Cv2.PyrDown(src, src, new Size(src.Cols / 2, src.Rows / 2));
        //        Cv2.PyrDown(model, model, new Size(model.Cols / 2, model.Rows / 2));
        //    }

        //    TemplateMatchModes matchMode = TemplateMatchModes.CCoeffNormed;
        //    switch (nccMethod)
        //    {
        //        case 0:
        //            matchMode = TemplateMatchModes.SqDiff;
        //            break;
        //        case 1:
        //            matchMode = TemplateMatchModes.SqDiffNormed;
        //            break;
        //        case 2:
        //            matchMode = TemplateMatchModes.CCorr;
        //            break;
        //        case 3:
        //            matchMode = TemplateMatchModes.CCorrNormed;
        //            break;
        //        case 4:
        //            matchMode = TemplateMatchModes.CCoeff;
        //            break;
        //        case 5:
        //            matchMode = TemplateMatchModes.CCoeffNormed;
        //            break;
        //    }

            //    //在没有旋转的情况下进行第一次匹配
            //    Cv2.MatchTemplate(src, model, result, matchMode);
            //    Cv2.MinMaxLoc(result, out double minVal, out double maxVal, out Point minLoc, out Point maxLoc, new Mat());

            //    Point location = maxLoc;
            //    double temp = maxVal;
            //    double angle = 0;

            //    Mat newImg;

            //    //以最佳匹配点左右十倍角度步长进行循环匹配,直到角度步长小于参数角度步长
            //    if (nccMethod == 0 || nccMethod == 1)
            //    {
            //        do
            //        {
            //            for (int i = 0; i <= (int)range / step; i++)
            //            {
            //                newImg = ImageRotate(model, start + step * i);
            //                Cv2.MatchTemplate(src, newImg, result, matchMode);
            //                Cv2.MinMaxLoc(result, out double minval, out double maxval, out Point minloc, out Point maxloc, new Mat());
            //                if (maxval < temp)
            //                {
            //                    location = maxloc;
            //                    temp = maxval;
            //                    angle = start + step * i;
            //                }
            //            }
            //            range = step * 2;
            //            start = angle - step;
            //            step = step / 10;
            //        } while (step > angleStep);
            //        return new ResultPoint(location.X * Math.Pow(2, numLevels) + modelImage.Width / 2, location.Y * Math.Pow(2, numLevels) + modelImage.Height / 2, -angle, temp);
            //    }
            //    else
            //    {
            //        do
            //        {
            //            for (int i = 0; i <= (int)range / step; i++)
            //            {
            //                newImg = ImageRotate(model, start + step * i);
            //                Cv2.MatchTemplate(src, newImg, result, matchMode);
            //                Cv2.MinMaxLoc(result, out double minval, out double maxval, out Point minloc, out Point maxloc, new Mat());
            //                if (maxval > temp)
            //                {
            //                    location = maxloc;
            //                    temp = maxval;
            //                    angle = start + step * i;
            //                }
            //            }
            //            range = step * 2;
            //            start = angle - step;
            //            step = step / 10;
            //        } while (step > angleStep);
            //        if (temp > thresScore)
            //        {
            //            return new ResultPoint(location.X * Math.Pow(2, numLevels), location.Y * Math.Pow(2, numLevels), -angle, temp);
            //        }
            //    }
            //    return new ResultPoint();
            //}

            旋转模板
            //private Mat ImageRotate(Mat src, double angle)
            //{
            //    Mat dst = new Mat();
            //    Point2f center = new Point2f(src.Cols / 2, src.Rows / 2);
            //    Mat rot = Cv2.GetRotationMatrix2D(center, angle, 1);
            //    Size2f s2f = new Size2f(src.Size().Width, src.Size().Height);
            //    Rect box = new RotatedRect(new Point2f(0, 0), s2f, (float)angle).BoundingRect();
            //    double xx = rot.At<double>(0, 2) + box.Width / 2 - src.Cols / 2;
            //    double zz = rot.At<double>(1, 2) + box.Height / 2 - src.Rows / 2;
            //    rot.Set(0, 2, xx);
            //    rot.Set(1, 2, zz);
            //    Cv2.WarpAffine(src, dst, rot, box.Size);
            //    return dst;
            
        }
    }


  • 3
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: OpenCvSharp是一个基于OpenCV库的开源计算机视觉库,提供了许多图像处理和计算机视觉函数。模板匹配是其的一个功能,可以用于在一幅图像寻找与给定模板相似的部分。 模板匹配的基本思想是,在目标图像滑动模板窗口,与模板进行相似度比较,找到相似度最高的位置作为匹配结果。相似度的度量可以使用不同的方法,如平方差匹配、相关匹配和标准化互相关匹配等。 在OpenCvSharp,我们可以使用`Cv2.MatchTemplate`函数进行模板匹配。这个函数的输入参数包括目标图像、模板图像以及匹配方法。匹配方法是一个枚举类型,可以选择不同的相似度比较方法。 例如,假设目标图像为`sourceImage`,模板图像为`templateImage`,我们可以使用以下代码进行模板匹配: ``` // 将图像转换为灰度图像 var graySource = new Mat(); Cv2.CvtColor(sourceImage, graySource, ColorConversionCodes.BGR2GRAY); // 进行模板匹配 var result = new Mat(); Cv2.MatchTemplate(graySource, templateImage, result, TemplateMatchModes.CCoeffNormed); // 查找匹配结果的最大值和最小值 double minVal, maxVal; Point minLoc, maxLoc; Cv2.MinMaxLoc(result, out minVal, out maxVal, out minLoc, out maxLoc); // 可以选择在目标图像绘制矩形框标识匹配部分 Cv2.Rectangle(sourceImage, new Rect(maxLoc, templateImage.Size()), Scalar.Red, 2); // 显示结果 Cv2.ImShow("Template Matching", sourceImage); Cv2.WaitKey(0); ``` 通过上述代码,我们可以找到目标图像与模板最相似的部分,并将其用红色矩形框标识出来。在实际应用模板匹配可以用于目标检测、物体跟踪等领域。 ### 回答2: OpenCVSharp是一个基于OpenCV的C#开发库,可以用于图像处理和计算机视觉任务。模板匹配是一种在图像寻找特定模式的技术。 模板匹配的过程包括以下步骤: 1. 准备一幅待匹配的源图像和一幅待寻找的模板图像。 2. 通过OpenCVSharp的函数读取图像文件,并将其转换为OpenCV的图像数据类型。 3. 使用OpenCVSharp模板匹配函数,将源图像与模板图像进行匹配。这些函数包括cv::matchTemplate,cv::minMaxLoc等。 4. 匹配函数会返回一个结果图像,其包含了源图像与模板最接近的区域。可以使用cv::minMaxLoc函数来获取匹配结果的位置坐标。 5. 可以根据需要进一步处理匹配结果,例如在结果图像上绘制矩形框标记出匹配的区域,或者计算匹配的相似度得分。 模板匹配在很多应用都有广泛的应用,例如目标识别、图像分类、图像拼接等。使用OpenCVSharp进行模板匹配可以方便地利用OpenCV的功能和算法来实现这些任务。同时,OpenCVSharp的API也相对简单易用,适合快速开发和原型验证。 总的来说,OpenCVSharp提供了强大的模板匹配功能,可以帮助我们在图像寻找特定模式,并且可以根据匹配结果进行后续的图像处理和分析。 ### 回答3: OpenCvSharp是一个基于OpenCV的开源计算机视觉库,它提供了用于图像处理和分析的函数和类。其一个功能是模板匹配,它可以用于在一副图像查找特定模板的位置。 模板匹配的基本原理是将一个模板图像与目标图像进行比较,通过计算相似度来确定模板在目标图像的位置。 在OpenCvSharp模板匹配的主要步骤如下: 1. 准备目标图像和模板图像。目标图像是待搜索的图像,而模板图像是要匹配的部分。 2. 选择一个匹配方法。OpenCvSharp提供了几种不同的匹配方法,如平方差匹配、相关性匹配和归一化互相关匹配等。 3. 使用匹配方法进行模板匹配。首先,使用cv2.MatchTemplate函数将模板图像与目标图像进行匹配。然后,通过计算相似度得分来找到最好的匹配位置。 4. 根据相似度得分确定模板在目标图像的位置。可以使用cv2.MinMaxLoc函数找到得分最高的位置,即最佳匹配位置。 5. 可以选择是否进行阈值处理。通过设置适当的阈值,可以将相似度得分低于阈值的匹配位置排除。 6. 可以通过绘制矩形来标记模板在目标图像的位置。可以使用cv2.Rectangle函数在目标图像上绘制矩形框。 总之,OpenCvSharp模板匹配功能提供了一种方便快捷的方法来查找图像特定模板的位置。通过选择适当的匹配方法和设置适当的阈值,我们可以得到准确的匹配结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值