• 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 }

    五、其他

     

  • 相关阅读:
    搭建微信小程序开发环境
    DOM 的classList 属性
    mui监听多个下拉刷新当前处于哪个选项卡
    mui常用功能链接地址
    css 弹性盒模型Flex 布局
    定义变量let,const
    微信小程序从零开始开发步骤(六)4种页面跳转的方法
    微信小程序从零开始开发步骤(五)轮播图
    展开符和解构赋值
    POJ 3660 Floyd传递闭包
  • 原文地址:https://www.cnblogs.com/little-monkey/p/7281459.html
Copyright © 2020-2023  润新知