C# 使用opencv识别圆

这个例子我在winform中写的,做了一些二值化、高斯滤波处理,然后用霍夫圆检测或者网格提取法,代码如下:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private Mat imgscr = null;
        private void Form1_Load(object sender, EventArgs e)
        {
            LoadPicture();

            // 相机标定
            //var objectPoints = ExternalParameter.GetObjectPoints();
            //var imagePoints = ExternalParameter.GetImagePoints(out int pw, out int ph);
            using Mat cameraMatrix = new Mat(3, 3, DepthType.Cv32F, 0);
            using Mat distortionCoeffs = new Mat(1, 5, DepthType.Cv32F, 0);
            //MCvTermCriteria termCriteria = new MCvTermCriteria(10);
            //using Matrix<double> matrix = ExternalParameter.GetCameraInternalParameterMatrix();
            //using Matrix<double> matrix2 = ExternalParameter.GetDistortionMatrix(ks: new double[] { 1, 1, 1, 1 });
            //var result = CvInvoke.CalibrateCamera(objectPoints, imagePoints, new Size(pw, ph), matrix, matrix2, CalibType.UserIntrinsicGuess, termCriteria, out Mat[] rotationVectors, out Mat[] translationVectors);
            //var fisrt = rotationVectors.First().GetInputArray();

            //richTextBox1.Text = string.Join(',', fisrt);

            //rotationVectors = null;
            //translationVectors = null;

            //Mat mat = new Mat();
             二值化
            //CvInvoke.Threshold(imgscr, mat, 163, 255, ThresholdType.Binary);
            // 高斯滤波去噪
            //参数:输入图像,输出图像,内核,高斯核在x方向的标准差,高斯核在y方向的标准差
            //sigmaY=0时,其值自动由sigmaX确定(sigmaY=sigmaX);
            //sigmaY=sigmaX=0时,它们的值将由ksize.width和ksize.height自动确定))
            //CvInvoke.GaussianBlur(mat, mat, new Size(5, 5), 0);
            //this.pictureBox2.Image = mat.Bitmap;


            //bmp.Dispose();
            //CvInvoke.Imshow("img", mat);//显示图像
            //CvInvoke.WaitKey(0);//按键等待 findChessboardCorners

            //Mat mat = new Mat();
            //var status= CvInvoke.FindChessboardCorners(imgscr,new Size(4,6), mat);

            //OutputArray data = mat.GetOutputArray();
            //data.Dispose();




           
        }
        private void LoadPicture()
        {
            if (imgPath != string.Empty)
            {
                imgscr = CvInvoke.Imread(imgPath, LoadImageType.Grayscale);
                //CvInvoke.CornerSubPix(imgscr, imgscr,new Size(imgscr.Width>>1, imgscr.Bitmap.Height>>1),new Size(-1,-1)):
                //CvInvoke.CalibrateCamera
                this.pictureBox1.Image = imgscr.Bitmap;
            }
        }
        /// <summary>
        /// 二值化阈值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            if (checkBox1.Checked && imgscr != null)
            {
                label3.Text = trackBar1.Value.ToString();
                // 二值化
                CvInvoke.Threshold(imgscr, imgscr, trackBar1.Value, trackBar2.Value, ThresholdType.Binary);
                this.pictureBox1.Image = imgscr.Bitmap;
            }
        }
        /// <summary>
        /// 二值化maxValue
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar2_Scroll(object sender, EventArgs e)
        {
            if (checkBox1.Checked && imgscr != null)
            {
                label4.Text = trackBar2.Value.ToString();
                // 二值化
                CvInvoke.Threshold(imgscr, imgscr, trackBar1.Value, trackBar2.Value, ThresholdType.Binary);
                this.pictureBox1.Image = imgscr.Bitmap;
            }

            /* double threshold(InputArray src,//src输入数组(多通道,8位或32位浮点)。
                   OutputArray dst,//dst输出数组的大小和类型与src相同,通道数相同。
                   double thresh, //二值化阈值,阈值两端的分别置为0、255
                   double maxval, //与#THRESH_BINARY=0和#THRESH_BINARY_INV=1一起使用的maxval最大值类型。(8位图像为255)
                   int type //二值化类型
                   );

            CV_THRESH_BINARY = 0,  /**值大于阈值置为最大值,否则为0
            CV_THRESH_BINARY_INV = 1,  /**值大于阈值置为0,否则为最大值
    CV_THRESH_TRUNC = 2,  /**值大于阈值置为阈值,否则不变
    CV_THRESH_TOZERO = 3,  /**值大于阈值不变,否则置为0
    CV_THRESH_TOZERO_INV = 4,  /**值大于阈值置为0,否则不变
    
    CV_THRESH_OTSU = 8, /**<利用大津法自动选择最优阈值;将标志与上述CV_THRESH_x值之一组合
    CV_THRESH_TRIANGLE = 16  /**采用三角形算法选择最优阈值;将标志与上述CV_THRESH_x值之一组合,但不能用CV_THRESH_OTSU
             */
        }
        private void Disposable()
        {
            imgscr?.Dispose();
        }
        ~Form1()
        {
            Disposable();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Disposable();
            this.Dispose();

            Application.ExitThread();
            Process.GetCurrentProcess().Kill();
        }
        /// <summary>
        /// 高斯核大小width
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar4_Scroll(object sender, EventArgs e)
        {
            if (checkBox2.Checked && imgscr != null && (trackBar4.Value & 1) == 1)
            {
                label8.Text = trackBar4.Value.ToString();
                CvInvoke.GaussianBlur(imgscr, imgscr, new Size(trackBar4.Value, trackBar3.Value), (double)numericUpDown1.Value, (double)numericUpDown2.Value);
                this.pictureBox1.Image = imgscr.Bitmap;
            }
        }
        /// <summary>
        /// 高斯核大小height
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar3_Scroll(object sender, EventArgs e)
        {
            if (checkBox2.Checked && imgscr != null && (trackBar3.Value & 1) == 1)
            {
                label7.Text = trackBar3.Value.ToString();
                CvInvoke.GaussianBlur(imgscr, imgscr, new Size(trackBar4.Value, trackBar3.Value), (double)numericUpDown1.Value, (double)numericUpDown2.Value);
                this.pictureBox1.Image = imgscr.Bitmap;
            }
            /*
             Size    ksize,    (高斯核大小,ksize.width和ksize.height可以不同,但是都必须为正的奇数(或者为0,此时它们的值会自动由sigma进行计算))
            double    sigmaX,    (高斯核在x方向的标准差)
            double    sigmaY=0,    (高斯核在y方向的标准差(sigmaY=0时,其值自动由sigmaX确定(sigmaY=sigmaX);sigmaY=sigmaX=0时,它们的值将由ksize.width和ksize.height自动确定))
            int    borderType=BORDER_DEFAULT    (像素外插策略,可参考BorderTypes)
             */
        }
        /// <summary>
        /// 启动霍夫圆检测
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            StartHoughCircles();
        }
        private void StartHoughCircles()
        {
            if (imgscr != null)
            {
                // 霍夫圆检测
                CircleF[] circles = CvInvoke.HoughCircles(imgscr, HoughType.Gradient, (double)numericUpDown3.Value, (double)numericUpDown4.Value, (double)numericUpDown5.Value, (double)numericUpDown6.Value, trackBar6.Value, trackBar5.Value);
                if (circles == null)
                    return;
                Bitmap bmp = new Bitmap(imgscr.Bitmap);
                using Graphics graphics = Graphics.FromImage(bmp);
                using Brush brush = new SolidBrush(Color.Red);
                using Pen pen = new Pen(Color.Red);
                for (int i = 0; i < circles.Length; i++)
                {
                    var circle = circles[i];
                    //var d = circle.Radius * 2;
                    graphics.FillEllipse(brush, new RectangleF(circle.Center.X - 9, circle.Center.Y - 9, 18, 18));
                    //graphics.DrawEllipse(pen, new Rectangle(6, 6, 30, 30));
                    //graphics.DrawRectangle(pen, new Rectangle(30, 36, 50, 50));

                }
                this.pictureBox1.Image = bmp;
            }
            /*public static CircleF[] HoughCircles(
           IInputArray image,//输入图像,8位单通道灰度图像
           HoughType method,//检测方法使用。目前,唯一实现的方法是CV_HOUGH_GRADIENT
           double dp,//累加器分辨率与图像分辨率的反比。例如,如果dp = 1,则累加器具有与输入图像相同的分辨率。如果dp = 2,则累加器的宽度和高度都是一半
           double minDist,//检测到的圆的中心之间的最小距离。太小会多检,太大会漏检
           double param1 = 100,//传递给Canny()检测器的两个阈值中的较高的阈值(较高的是较低的两倍左右)
           double param2 = 100,//检测阶段圆心的累加器阈值。越小,可得到越多的圆
           int minRadius = 0,//最小圆半径
           int maxRadius = 0//最大圆半径
           )*/
        }
        /// <summary>
        /// 开启二值化处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked && imgscr != null)
            {
                // 二值化
                CvInvoke.Threshold(imgscr, imgscr, trackBar1.Value, trackBar2.Value, ThresholdType.Binary);
                this.pictureBox1.Image = imgscr.Bitmap;
            }

        }
        /// <summary>
        /// 开启高斯滤波
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox2.Checked && imgscr != null && (trackBar4.Value & 1) == 1)
            {
                CvInvoke.GaussianBlur(imgscr, imgscr, new Size(trackBar4.Value, trackBar3.Value), (double)numericUpDown1.Value, (double)numericUpDown2.Value);
                this.pictureBox1.Image = imgscr.Bitmap;
            }
        }
        /// <summary>
        /// 重置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            LoadPicture();
            checkBox1.Checked = false;
            checkBox2.Checked = false;

        }
        /// <summary>
        /// 霍夫圆检测-minRadius
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar6_Scroll(object sender, EventArgs e)
        {
            StartHoughCircles();
            label14.Text = trackBar6.Value.ToString();
        }
        /// <summary>
        /// 霍夫圆检测-maxRadius
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar5_Scroll(object sender, EventArgs e)
        {
            StartHoughCircles();
            label13.Text = trackBar5.Value.ToString();
        }
        /// <summary>
        /// 启动圆形网格
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            LoadCirclesGrid();
        }
        private void LoadCirclesGrid()
        {
            if (imgscr != null)
            {
                //InputArray _image:输入图片;    Size patternSize:网格大小;    _centers:提取的网格点中心;  
                //flags:是否为对称网格;           blobDetector:斑点检测器;      parameters:参数
                var feature2D = new SimpleBlobDetector();
                var img = imgscr.ToImage<Gray, Byte>();
                var circles = CvInvoke.FindCirclesGrid(img, new Size(trackBar8.Value, trackBar7.Value), CalibCgType.SymmetricGrid, feature2D);
                if (circles == null)
                    return;
                Bitmap bmp = new Bitmap(imgscr.Bitmap);
                Graphics graphics = Graphics.FromImage(bmp);
                Brush brush = new SolidBrush(Color.Red);
                Pen pen = new Pen(Color.Red);
                for (int i = 0; i < circles.Length; i++)
                {
                    var circle = circles[i];
                    //var d = circle.Radius * 2;
                    graphics.FillEllipse(brush, new RectangleF(circle.X - 9, circle.Y - 9, 18, 18));
                    //graphics.DrawEllipse(pen, new Rectangle(6, 6, 30, 30));
                    //graphics.DrawRectangle(pen, new Rectangle(30, 36, 50, 50));

                }
                this.pictureBox1.Image = bmp;
                pen.Dispose();
                brush.Dispose();
                graphics.Dispose();
                feature2D.Dispose();
                img.Dispose();
            }
        }
        /// <summary>
        /// 图片路径
        /// </summary>
        private string imgPath = string.Empty;
        /// <summary>
        /// 选择图像
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Multiselect = true;
            ofd.Title = "打开一幅图像";
            ofd.Filter = "图片(*.jpg,*.gif,*.bmp)|*.jpg;*.gif;*.bmp";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                imgPath = ofd.FileName;
                label21.Text = imgPath;
                LoadPicture();
            }
        }

        private void trackBar8_Scroll(object sender, EventArgs e)
        {
            label25.Text = trackBar8.Value.ToString();
            LoadCirclesGrid();
        }

        private void trackBar7_Scroll(object sender, EventArgs e)
        {
            label24.Text = trackBar7.Value.ToString();
            LoadCirclesGrid();
        }
    }

结果如下:

网格提取

 霍夫圆:

 需要代码私。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值