OpenCv学习20——霍夫变换(圆检测)

时间:2024-04-04 08:22:26
  1. 上一节中学习了霍夫变换的直线检测,本节则是学习霍夫变换的圆检测。
    霍夫变换的圆检测的大致原理可以如图所示
    OpenCv学习20——霍夫变换(圆检测)OpenCv学习20——霍夫变换(圆检测)
    即对于一副图像来说,我们认为其图像中的圆的半径大小已经确定,则我们对于图像中的每一个坐标点,我们以该点为圆心,以待求圆的半径为长度画圆,则最终几个圆之间可能会产生很多交点,我们选取相交点的数目最多的那个,即为待求圆的圆心。

  2. OpenCv中霍夫变换圆检测的实现:
    ①因为霍夫圆检测对于噪声比较敏感,所以首先要对图像进行中值滤波
    ②基于效率考虑,OpenCv中实现的霍夫变换圆检测是基于图像梯度的实现,因此我们将其分为两部:
    1.检测边缘,发现可能的圆心
    2.基于第一步的基础上从候选圆心开始计算最佳半径的大小

    用到的相关API:

    CV_EXPORTS_W void HoughCircles( InputArray image,
    							    OutputArray circles,
                                    int method, 
                                    double dp, 
                                    double minDist,
                                    double param1 = 100,
                                    double param2 = 100,
                                   int minRadius = 0, int maxRadius = 0 );
    

    第一个参数为输入的图像
    第二个参数为输出的参数,即检测到图像中圆的信息
    第三个参数为检测的方法,我们采用HOUGH_GRADIENT的方法即霍夫梯度
    第四个参数为尺度,dip=1,在原图上寻找即让其为1,在原图的一半寻找让其为2
    第五个参数为最短距离,是用来区分两个圆的
    第六个参数为利用Canny来求梯度的低阈值
    第七个参数为中心点累加的阈值(即以每个像素点为中心画圆所相交的点的强度)
    第八个参数为最小半径
    第九个参数为最大半径

  3. 代码

    #include "stdafx.h"
    #include "iostream"
    #include "opencv2\opencv.hpp"
    
    using namespace std;
    using namespace cv;
    
    
    int main()
    {
    	Mat src, dst;
    	src = imread("G:/He/opencv_images/hough_circle_transform.jpg");
    	if (src.empty())
    	{
    		cout << "could not load the images.." << endl;
    		return -1;
    	}
    	namedWindow("original_images", CV_WINDOW_AUTOSIZE);
    	namedWindow("test_images", CV_WINDOW_AUTOSIZE);
    	Mat middle_filter;
    	medianBlur(src,middle_filter, 3);
    	imshow("original_images", src);
    	cvtColor(middle_filter, middle_filter, CV_BGR2GRAY);
    	vector<Vec3f>pcircles;
    	HoughCircles(middle_filter, pcircles, CV_HOUGH_GRADIENT, 1, 10, 100, 30, 0, 50);
    	src.copyTo(dst);
    	for (size_t i = 0; i < pcircles.size(); i++)
    	{
    		Vec3f cc = pcircles[i];
    		circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(255, 0, 0), 2, LINE_AA);
    		circle(dst, Point(cc[0], cc[1]), 2, Scalar(198, 23, 155), 2, LINE_AA);
    	}
    	imshow("test_images", dst);
    	waitKey(0);
    	destroyAllWindows();
        return 0;
    }