您的位置:首页 > 其它

hough变换检测直线

2014-07-08 19:08 155 查看
摘录自http://lansesky23.blog.163.com/blog/static/35724627201351811014458/

/article/1820973.html

1,基本思想

Hough变换时一种利用图像的全局特征将特定形状边缘链接起来。它通过点线的对偶性,将源图像上的点影射到用于累加的参数空间,把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题。由于利用全局特征,所以受噪声和边界间断的影响较小,比较鲁棒。

Hough变换思想为:在原始图像坐标系下的一个点对应了参数坐标系中的一条直线,同样参数坐标系的一条直线对应了原始坐标系下的一个点,然后,原始坐标系下呈现直线的所有点,它们的斜率和截距是相同的,所以它们在参数坐标系下对应于同一个点。这样在将原始坐标系下的各个点投影到参数坐标系下之后,看参数坐标系下有没有聚集点,这样的聚集点就对应了原始坐标系下的直线。

我们知道,一条直线在直角坐标系下可以用y=kx+b表示, 霍夫变换的主要思想是将该方程的参数和变量交换,即用x,y作为已知量k,b作为变量坐标,所以直角坐标系下的直线y=kx+b在参数空间表示为点(k,b),而一个点(x1,y1)在直角坐标系下表示为一条直线y1=x1·k+b,其中(k,b)是该直线上的任意点。为了计算方便,我们将参数空间的坐标表示为极坐标下的γ和θ。因为同一条直线上的点对应的(γ,θ)是相同的,因此可以先将图片进行边缘检测,然后对图像上每一个非零像素点,在参数坐标下变换为一条直线,那么在直角坐标下属于同一条直线的点便在参数空间形成多条直线并内交于一点。因此可用该原理进行直线检测。

X--Y平面上任意一条直线y
= ax + b,对应在参数a-b平面上都有一个点



如果点(x1,y1)与点(x2,y2)共线,则这两个点在参数a-b平面上的直线将有一个交点:

这样,在参数a-b平面上相交直线对多的点,对应的x-y平面上的直线就是我们的解。利用点--正弦曲线对偶来解题

点--正弦曲线对偶利用极坐标系描述直线



因此采用hough变换主要有以下几个步骤:

1)Detect the edge

检测得到图像的边缘

2)Create accumulator

采用二维向量描述图像上每一条直线区域,将图像上的直线区域计数器映射到参数空间中的存储单元,ρ为直线区域到原点的距离(直线到原点的垂直距离),所以对于对角线长度为n的图像,ρ的取值范围为(0,
n),θ值得取值范围为(0, 360),定义为二维数组HoughBuf
[360]为存储单元。
对所有像素点(x,y)在所有θ角的时候,求出ρ.从而累加ρ值出现的次数。高于某个阈值的ρ就是一个直线。

这个过程就类似于如下一个二维的表格,横坐标就是θ角,ρ就是到直线的最短距离。

横坐标θ不断变换,根据直线方程公司,ρ = xcosθ + ysinθ 对于所有的不为0的像素点,计算出ρ,找到ρ在坐标(θ,ρ)的位置累加1.

3) Detect the peaks, maximal in the accumulator

通过统计特性,假如图像平面上有两条直线,那么最终会出现2个峰值,累加得到最高的数组的值为所求直线参数。

具体代码片段:
for( ang = 0, n = 0; n < numangle; ang += theta, n++ )
{
tabSin[ n ] = ( float )( sin( ang )  *  irho);
tabCos[ n ] = ( float )( cos( ang ) * irho);
}

// stage 1. fill accumulator
for( i = 0; i < height; i++ )
for( j = 0; j < width; j++ )
{
if( image[ i * step + j ] != 0 )
for( n = 0; n < numangle; n++ )
{
r = cvRound( j * tabCos
+ i * tabSin
);
r += (numrho - 1) / 2;
accum[(n+1) * (numrho+2) + r+1]++;
}
}

// stage 2. find local maximums
for( r = 0; r < numrho; r++ )
for( n = 0; n < numangle; n++ )
{
int base = (n+1) * (numrho+2) + r+1;
if( accum[base] > threshold &&
accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
sort_buf[total++] = base;
}

// stage 3. sort the detected lines by accumulator value
icvHoughSortDescent32s( sort_buf, total, accum );

// stage 4. store the first min(total,linesMax) lines to the output buffer
linesMax = MIN(linesMax, total);
scale = 1./(numrho+2);
for( i = 0; i < linesMax; i++ )
{
CvLinePolar line;
int idx = sort_buf[i];
int n = cvFloor(idx*scale) - 1;
int r = idx - (n+1)*(numrho+2) - 1;
line.rho = (r - (numrho - 1)*0.5f) * rho;
line.angle = n * theta;
cvSeqPush( lines, &line );
}


cvHoughLines2

说明:

  此函数是opencv图像变换函数中的一个,主要用来访问霍夫变换的两个算法———标准霍夫变换(SHT)和累计概率霍夫变换(PPHT)。

函数原型:

   CvSeq* cvHonghLines2( CvArr* image, void* line_storage, int mehtod, double rho, double theta, int threshold, double param1 =0, double param2 =0 );

参数说明:

  image:输入8-比特、单通道(二值)图像,当用CV_HOUGH_PROBABILISTIC方法检测的时候其内容会被函数改变。

  line_storage:检测到的线段存储仓.可以是内存存储仓
(此种情况下,一个线段序列在存储仓中被创建,并且由函数返回),或者是包含线段参数的特殊类型(见下面)的具有单行/单列的矩阵(CvMat*)。矩阵头为函数所修改,使得它的 cols/rows 将包含一组检测到的线段。如果 line_storage 是矩阵,而实际线段的数目超过矩阵尺寸,那么最大可能数目的线段被返回(线段没有按照长度、可信度或其它指标排序).

  method:Hough
变换变量,是下面变量的其中之一:

  CV_HOUGH_STANDARD-- 传统或标准 Hough
变换. 每一个线段由两个浮点数 (ρ, θ) 表示,其中 ρ 是直线与原点(0,0) 之间的距离,θ 线段与 x-轴之间的夹角。因此,矩阵类型必须是 CV_32FC2 type.

  CV_HOUGH_PROBABILISTIC-- 概率 Hough 变换(如果图像包含一些长的线性分割,则效率更高). 它返回线段分割而不是整个线段。每个分割用起点和终点来表示,所以矩阵(或创建的序列)类型是
CV_32SC4.

  CV_HOUGH_MULTI_SCALE-- 传统 Hough
变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的一致。

  rho:与象素相关单位的距离精度,一般取1

  theta:弧度测量的角度精度

  threshold:阈值参数。如果相应的累计值大于
threshold, 则函数返回的这个线段.

  param1:第一个方法相关的参数:

  对传统 Hough 变换,不使用(0).

  对概率 Hough 变换,它是最小线段长度.

  对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / param1 ).

  param2:第二个方法相关参数:

  对传统 Hough 变换,不使用 (0).

  对概率 Hough 变换,这个参数表示在同一条直线上进行碎线段连接的最大间隔值(gap), 即当同一条直线上的两条碎线段之间的间隔小于param2时,将其合二为一。

  对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 theta / param2).

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: