霍夫变换:从黑白图像中检测直线和曲线。html
优势:对数据的不彻底或噪声不是很是敏感。算法
首先对图像进行边缘检测的处理,即霍夫线变换的直接输入只能是边缘二值图像。函数
多尺度霍夫变换(MSHT)是经典霍夫变换(标准霍夫变换SHT)在多尺度下的一个变种。spa
累计几率霍夫变换(PPHT)是SHT的改进。他在必定的范围内进行霍夫变换,计算单独线段的方向机范围,从而减小计算量,缩短计算时间。3d
标准霍夫变换SHT原理: code
霍夫变换运用两个坐标空间之间的变换,将在一个(图像)空间中具备相同形状(数学模型+参数)的曲线或直线,映射到另外一个(参数)坐标空间的一个点上造成峰值,从而把检测任意形状的问题转化为统计峰值问题。orm
咱们知道,一条直线在直角(图像)坐标系下能够用y=kx+b表示, 霍夫变换的主要思想是将该方程的参数和变量交换,即用x,y做为(参数、系数),k,b做为(变量),因此直角坐标系下的一个点(x1,y1)在直角坐标系下表示为一条直线:y1=x1·k+b, 其中(k,b)是该直线上的任意点;直角坐标系下的一条直线y=kx+b在参数空间表示为一个点:(k,b),为了计算方便,并解决k(直线的斜率)接近无穷大的问题,使用了一种标准的直线标识法,将参数空间的坐标表示为极坐标下的γ和θ。htm
由于同一条直线上的点对应的参数(k,b)/(γ,θ)是相同的,所以能够先将图片进行边缘检测,而后对图像上每个非零像素点,在参数坐标下变换为一条直线,那么在直角坐标下属于同一条直线的点便在参数空间造成多条直线并内交于一点,这一点即为对应直线的参数,全部直线在(γ,θ)参数空间中获得一系列对应曲线。所以可用该原理进行直线检测。blog
Hough变换在计算上的吸引力在于将参数空间进一步分割为所谓的累加器单元,如图9所示。其中(amax,amin)和(bmax,bmin)为参数值的指望范围,通常来讲,值的最大范围是-90°<θ<90°和-D<ρ<D,其中D是图像中角点间的距离。 最初,这些单元被设置为0。而后,对于图像平面上的每个非背景点(xk, yk),令θ等于θ轴上容许的细分值,并经过公式ρ=xkcosθ+yksinθ求出相应的ρ值。而后,将获得的ρ值四 舍五入为最接近的、ρ轴上容许的单元值,相应的累加器单元相加。在这个过程的最后,A(i,j)意味着x-y平面上的Q个点位于线xcosθj+ysinθj=ρi上。ρ-θ平面上的细分数决定了这些点共线的精度。
排序
(1)读取原始图像,并转成灰度图像。
(2)采用小波边缘检测算法对其进行边缘检测,获得二值化的边缘图像。
(3)对此边缘图像作Hough变换。
(4)使用函数houghpeaks 作峰值检测。函数houghpeaks的算法以下:
①找到包含有最大值的Hough变换单元,并记下它的位置;
②把上步找到的最大值点的领域中的Hough 变换单元设为0;
③重复该步骤,直到找到须要的峰值数为止,或者达到一个指定的阈值时为止。
(5)一旦在Hough 变换中识别出了一组候选的峰波,则还要留待肯定是否存在与这些峰值相关的线段及它们的起始和终止为止。对每个峰值来讲,第一步是找到图像中影响到峰值的每个非0 值点的位置。为此,编写函数houghpixls 来实现这一功能。
(6)使用函数houghlines 实现直线边缘链接,函数houghlines的算法以下:
①将像素位置旋转90° - θ ,以便它们大概位于一条垂直线上;
②按旋转的x值来对这些像素位置排序;
③使用函数diff 找到裂口。忽略掉小裂口,这将合并被小空白分离的相邻线段;
④返回比最小阈值长的线段的信息。
众所周知, 一条直线在图像二维空间可由两个变量表示. 例如:
对于霍夫变换, 咱们将用 极坐标系 来表示直线. 所以, 直线的表达式可为:
化简得:
通常来讲对于点 , 咱们能够将经过这个点的一族直线统必定义为:
这就意味着每一对 表明一条经过点 的直线.
若是对于一个给定点 咱们在极坐标对极径极角平面绘出全部经过它的直线, 将获得一条正弦曲线. 例如, 对于给定点 and 咱们能够绘出下图 (在平面 - ):
只绘出知足下列条件的点 and .
咱们能够对图像中全部的点进行上述操做. 若是两个不一样点进行上述操做后获得的曲线在平面 - 相交, 这就意味着它们经过同一条直线. 例如, 接上面的例子咱们继续对点: , 和点 , 绘图, 获得下图:
这三条曲线在 - 平面相交于点 , 坐标表示的是参数对 () 或者是说点 , 点 和点 组成的平面内的的直线.
说明:给定定点(x,y)在极坐标对极径极角平面会出全部经过它的直线,获得一条正弦曲线。(该曲线上任一点均表示经过定点的直线)。几条曲线(由定点肯定的)相交于一点意味着这些定点是共线的。设置直线上点的阈值(个数)来定义多少条曲线交于一点,便可检测到一条直线。
函数:
void HoughLines( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double srn = 0, double stn = 0,
double min_theta = 0, double max_theta = CV_PI );
第一个参数:输入灰度图像
第二个参数:输出图像
第三个参数:极径
第四个参数:极角
第五个参数:累加平面阈值
第六个参数:对于多尺寸霍夫变换,只是第三个参数进步尺寸的除数距离。rho/srn.
第七个参数:对于多尺寸霍夫变换,只是第四个参数进步尺寸的除数距离。
示例:
#include<opencv2/opencv.hpp> #include<opencv2/imgproc/imgproc.hpp> using namespace cv; using namespace std; int Dot_amount = 150; Mat img, img1, dst; void on_traker(int, void *) { img = imread("d://temp/18.png"); imshow("原始图", img); Canny(img, img1, 150, 200, 3); imshow("边缘检测", img1); cvtColor(img1, dst, CV_GRAY2BGR); vector<Vec2f>lines; HoughLines(img1, lines, 1, CV_PI / 180, Dot_amount, 0, 0); for (size_t i = 0; i < lines.size(); i++) { float rho = lines[i][0], theta = lines[i][1]; Point pt1, pt2; double a = cos(theta), b = sin(theta); double x0 = a*rho, y0 = b*rho; pt1.x = cvRound(x0 + 1000 * (-b)); pt1.y = cvRound(y0 + 1000 * (a)); pt2.x = cvRound(x0 - 1000 * (-b)); pt2.y = cvRound(x0 - 1000 * (a)); line(dst, pt1, pt2, Scalar(0, 0, 255), 1, LINE_AA); } imshow("H效果图", dst); } int main() { namedWindow("H效果图1", WINDOW_AUTOSIZE); createTrackbar("点数", "H效果图1", &Dot_amount, 250, on_traker); on_traker(Dot_amount, 0); while (1) { int key = waitKey(1); if ((char)key == 27)break; } return 0; }
累计几率霍夫变换:效果很好
void HoughLinesP( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double minLineLength = 0, double maxLineGap = 0 );
第一个参数:输入灰度图像
第二个参数:输出检测的线条
第三个参数:极径
第四个参数:极角
第五个参数:累加平面阈值
第六个参数:最低线段长度
第七个参数:点点之间的最大距离
示例:
#include<opencv2/opencv.hpp> #include<opencv2/imgproc/imgproc.hpp> using namespace cv; using namespace std; int Dot_amount = 150; Mat img, img1, dst; void on_traker(int, void *) { img = imread("d://temp/16.jpg"); imshow("原始图", img); Canny(img, img1, 150, 200, 3); imshow("边缘检测", img1); cvtColor(img1, dst, COLOR_GRAY2BGR); vector<Vec4i>lines; HoughLinesP(img1, lines, 1, CV_PI / 180, Dot_amount,50, 10); for (size_t i = 0; i < lines.size(); i++) { Vec4i l = lines[i]; line(dst,Point(l[0],l[1]),Point(l[2],l[3]), Scalar(0, 0, 255), 1, LINE_AA); } imshow("H效果图", dst); } int main() { namedWindow("H效果图1", WINDOW_AUTOSIZE); createTrackbar("点数", "H效果图1", &Dot_amount, 250, on_traker); on_traker(Dot_amount, 0); while (1) { int key = waitKey(1); if ((char)key == 27)break; } return 0; }
霍夫圆变换-----------霍夫梯度法原理
霍夫圆变换的基本原理和上面讲的霍夫线变化大致上是很相似的,只是点对应的二维极径极角空间被三维的圆心点x, y还有半径r空间取代。
void HoughCircles( InputArray image, OutputArray circles,
int method, double dp, double minDist,
double param1 = 100, double param2 = 100,
int minRadius = 0, int maxRadius = 0 );
过点(x1,y1)的全部圆能够表示为(a1(i),b1(i),r1(i)),过点(x2,y2)的全部圆能够表示为(a2(i),b2(i),r2(i)),过点(x3,y3)的全部圆能够表示为(a3(i),b3(i),r3(i)),若是这三个点在同一个圆上,那么存在一个值(a0,b0,r0),使得 a0 = a1(k)=a2(k)=a3(k) 且b0 = b1(k)=b2(k)=b3(k) 且r0 = r1(k)=r2(k)=r3(k),即这三个点同时在圆(a0,b0,r0)上。
从下图能够形象的看出: