霍夫变换-----特征提取

霍夫变换:从黑白图像中检测直线和曲线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 找到裂口。忽略掉小裂口,这将合并被小空白分离的相邻线段;
       ④返回比最小阈值长的线段的信息。

  1. 众所周知, 一条直线在图像二维空间可由两个变量表示. 例如:

    1. 在 笛卡尔坐标系: 可由参数: (m,b) 斜率和截距表示.
    2. 在 极坐标系: 可由参数: (r,\theta) 极径和极角表示
    Line variables

    对于霍夫变换, 咱们将用 极坐标系 来表示直线. 所以, 直线的表达式可为:

    y = \left ( -\dfrac{\cos \theta}{\sin \theta} \right ) x + \left ( \dfrac{r}{\sin \theta} \right )

    化简得: r = x \cos \theta + y \sin \theta

  2. 通常来讲对于点 (x_{0}, y_{0}), 咱们能够将经过这个点的一族直线统必定义为:

    r_{\theta} = x_{0} \cdot \cos \theta  + y_{0} \cdot \sin \theta

    这就意味着每一对 (r_{\theta},\theta) 表明一条经过点 (x_{0}, y_{0}) 的直线.

  3. 若是对于一个给定点 (x_{0}, y_{0}) 咱们在极坐标对极径极角平面绘出全部经过它的直线, 将获得一条正弦曲线. 例如, 对于给定点 x_{0} = 8 and y_{0} = 6咱们能够绘出下图 (在平面 \theta - r):

    Polar plot of a the family of lines of a point

    只绘出知足下列条件的点 r > 0 and 0< \theta < 2 \pi.

  4. 咱们能够对图像中全部的点进行上述操做. 若是两个不一样点进行上述操做后获得的曲线在平面 \theta - r 相交, 这就意味着它们经过同一条直线. 例如, 接上面的例子咱们继续对点: x_{1} = 9y_{1} = 4 和点 x_{2} = 12y_{2} = 3 绘图, 获得下图:

    Polar plot of the family of lines for three points

    这三条曲线在 \theta - r 平面相交于点 (0.925, 9.6), 坐标表示的是参数对 (\theta, r) 或者是说点 (x_{0}, y_{0}), 点 (x_{1}, y_{1}) 和点 (x_{2}, y_{2}) 组成的平面内的的直线.


    说明:给定定点(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 );

  • 第一个参数,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,表示圆半径的最大值。

过点(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)上。
从下图能够形象的看出:

hough变换是如何检测出直线和圆的? - 钰央 - 计算机视觉·图像处理
首先,分析过点(x1,y1)的全部圆(a1(i),b1(i),r1(i)),当肯定r1(i)时 ,(a1(i),b1(i))的轨迹是一个以(x1,y1,r1(i))为中心半径为r1(i)的圆。那么,全部圆(a1(i),b1(i),r1(i))的组成了一个以(x1,y1,0)为顶点,锥角为90度的圆锥面。 三个圆锥面的交点A 既是同时过这三个点的圆。