opencv学习之路(18)、霍夫变换

一、简介

在图像处理和计算机视觉领域中,如何从当前的图像中提取所需要的特征信息是图像识别的关键所在。在许多应用场合中需要快速准确地检测出直线或者圆。其中一种非常有效的解决问题的方法是霍夫(Hough)变换。

二、霍夫线变换

霍夫线变换的原理

 

 以上原理部分,转自http://blog.csdn.net/poem_qianmo/article/details/26977557

 

 1 #include "opencv2/opencv.hpp"
 2 using namespace cv;
 3 
 4 void main()
 5 {
 6     Mat src=imread("E://1.png");
 7     Mat dst;
 8     imshow("src", src);
 9     
10     Canny(src, src, 50, 200);
11     imshow("Canny", src);
12     //cvtColor(src, dst, CV_BGR2GRAY);//彩色图转灰度图:该语句不能放在canny边缘检测后(canny检测后,图像变为了灰度图)
13     cvtColor(src, dst, CV_GRAY2BGR);//灰度图转彩色图
14     
15     //进行霍夫线变换
16     vector<Vec2f> lines;  //定义矢量结构lines用于存放得到的线段矢量集合
17     HoughLines(src, lines, 1, CV_PI/180, 150);//超过150的线段才被检测到
18 
19     //依次在图中绘制出每条线段
20     for (size_t i = 0; i < lines.size(); i++)
21     {
22         float rho=lines[i][0],theta=lines[i][1];
23         Point pt1,pt2;
24         double a=cos(theta),b=sin(theta);
25         double x0=a*rho,y0=b*rho;
26         pt1.x=cvRound(x0+1000*(-b));//cvRound(double value) 函数:对一个double型数字四舍五入,返回一个整数
27         pt1.y=cvRound(y0+1000*(a));
28         pt2.x = cvRound(x0 - 1000*(-b));  
29         pt2.y = cvRound(y0 - 1000*(a));  
30         line(dst,pt1,pt2,Scalar(55,100,195),2,8);
31     }
32     
33     imshow("dst", dst);
34     waitKey(0);
35     destroyAllWindows();
36 }

三、累计概率霍夫变换

 1 #include "opencv2/opencv.hpp"
 2 using namespace cv;
 3 
 4 void main()
 5 {
 6     //HoughLinesP()用法
 7     Mat src = imread("E://1.png");
 8     Mat dstImg = src.clone();
 9     imshow("src", src);
10 
11     cvtColor(src, src, CV_BGR2GRAY);
12     Canny(src,src, 50, 200);
13     vector<Vec4i> lines;  //定义矢量结构lines用于存放得到的线段矢量集合
14     HoughLinesP(src, lines, 1, CV_PI/180, 150, 50, 10);
15     //依次在图中绘制出每条线段
16     for(size_t i = 0; i<lines.size(); i++)
17     {
18         Vec4i p = lines[i];
19         line(dstImg, Point(p[0], p[1]), Point(p[2], p[3]), Scalar(0, 255, 0), 2, 8);20     }
21     imshow("dst", dstImg);
22     waitKey(0);
23     destroyAllWindows();
24 }

四、霍夫圆变换

霍夫圆变换的基本原理和上面讲的霍夫线变化大体上是很类似的,只是点对应的二维极径极角空间被三维的圆心点x, y还有半径r空间取代。说“大体上类似”的原因是,如果完全用相同的方法的话,累加平面会被三维的累加容器所代替:在这三维中,一维是x,一维是y,另外一维是圆的半径r。这就意味着需要大量的内存而且执行效率会很低,速度会很慢。

对直线来说, 一条直线能由参数极径极角表示. 而对圆来说, 我们需要三个参数来表示一个圆, 也就是:

这里的(Xcenter,Ycenter)表示圆心的位置 (下图中的绿点) ,而 r 表示半径, 这样我们就能唯一的定义一个圆了, 见下图:

在OpenCV中,我们一般通过一个叫做“霍夫梯度法”的方法来解决圆变换的问题。

  • 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的灰度单通道图像。
  • 第二个参数,InputArray类型的circles,经过调用HoughCircles函数后此参数存储了检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x, y, radius)表示。
  • 第三个参数,int类型的method,即使用的检测方法,目前OpenCV中就霍夫梯度法一种可以使用,它的标识符为CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。
  • 第四个参数,double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例如,如果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
  • 第五个参数,double类型的minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。
  • 第六个参数,double类型的param1,有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
  • 第七个参数,double类型的param2,也有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了。
  • 第八个参数,int类型的minRadius,有默认值0,表示圆半径的最小值。
  • 第九个参数,int类型的maxRadius,也有默认值0,表示圆半径的最大值。

需要注意的是,使用此函数可以很容易地检测出圆的圆心,但是它可能找不到合适的圆半径。我们可以通过第八个参数minRadius和第九个参数maxRadius指定最小和最大的圆半径,来辅助圆检测的效果。或者,我们可以直接忽略返回半径,因为它们都有着默认值0,单单用HoughCircles函数检测出来的圆心,然后用额外的一些步骤来进一步确定半径。

 

 1 #include "opencv2/opencv.hpp"
 2 using namespace cv;
 3 
 4 void main()
 5 {
 6     Mat src = imread("E://C.jpg");
 7     Mat dst = src.clone();
 8     imshow("src", src);
 9 
10     cvtColor(src, src, CV_BGR2GRAY);
11     GaussianBlur(src,src,Size(9,9),2);
12 
13     vector<Vec3f> circles;
14     HoughCircles(src, circles, CV_HOUGH_GRADIENT,1.5, 10, 200, 100);
15     for(size_t i = 0; i<circles.size(); i++)
16     {
17         Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
18         int radius = cvRound(circles[i][2]);
19         circle(dst, center, 3, Scalar(0, 0, 255), -1, 8,0);//设置为-1时,画实心圆
20         circle(dst, center, radius, Scalar(0, 255, 0), 3, 8,0);//画空心圆
21     }
22     imshow("dst", dst);
23     waitKey(0);
24 }

五、其他

 

 

posted @ 2017-08-03 21:46  进击的小猴子  阅读(1918)  评论(0编辑  收藏  举报