opencv-第六章-霍夫变换
霍夫线变换
霍夫直线变换的基本理论是二值图像中的任何点都可能是一些候选直线集合的一部分。如果要确定每条线进行参数化,例如一个斜率a和截距b,原始图像中的一点会变成为(a,b)平面上的轨迹,轨迹上的点对应着所有过原始图像上点的直线。如果我们将输入图像中所有非0像素转化成输出图像中的这些点集并且将其贡献相加,然后输入图像出现的直线将会在输出图像以局部最大值出现。因为我们将每个点的贡献相加,因此(a,b)平面通常被称为累加平面。
你可能认为用斜率-截距的形式来代表所有通过的点并不是一种最好的方式(因为作为斜率函数,直线的密度有相当的差异,以及相关的事实是可能的斜率间隔的范围是从负无穷到正无穷)。正是由于这个原因,在实际数值计算中使用的变换图像的参数化略微有些不同。首选的参数化方式是每一行代表极坐标(ρ, θ)中的一个点,并且隐含的直线是通过象征点,垂直于远点到此点的半径。
opencv的霍夫变换算法并没有将这个算法显式地展示给用户。而是简单地返回(ρ, θ)平面的局部最大值。然而,需要了解这个过程以便更好地理解opencv霍夫变换函数中的参数。
opencv支持两种不同形式的霍夫变换:标准霍夫变换(SHT)和累积概率霍夫变换(PPHT)。刚才所说的是SHT算法。PPHT是这种算法的一个变种,计算单独线段的方向以及范围。之所以称PPHT为“概率”的,是因为并不将累加器平面内的所有可能点累加,而只是累加其中的一部分。该想法是如果峰值将要足够高,只用一小部分时间去寻找它就足够了。这个猜想的结果可以实质性地减少计算时间。尽管有一些变量的含义是取决于用哪个算法,但可以使用opencv中的同一个函数来访问这两个算法。
cvHoughLines2
功能:
利用Hough变换在二值图像中寻找直线。
函数原型:
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
以弧度为单位角度精度,一般取CV_PI/180
threshold
阈值参数。当在一条直线上的像素点数大于threshold时,才将该直线作为检测结果显示出来。该值越大,得到直线越少。
param1
对传统 Hough 变换,不使用(0).
对概率Hough变换,它是最小线段长度.即当线段长度大于param1时,才将该线段作为检测结果显示。与上一参数类似,不过上一参数为像素数,而该参数为线段长度。
对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / param1 ).
param2
对传统 Hough 变换,不使用 (0).
对概率 Hough 变换,这个参数表示在同一条直线上进行碎线段连接的最大间隔值(gap), 即当同一条直线上的两条碎线段之间的间隔小于param2时,将其合二为一条长直线。
对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 theta / param2).
霍夫圆变换
霍夫圆变换与之前所描述的霍夫直线变换是大体上是类似的。说“大体上类似”的原因--如果想要尝试完全类似--累加平面会被三维的累加容器所代替:在这三维中,一维是x,一维是y,另一维是圆的半径r。这就意味着需要大量的内存但速度却很慢。在opencv的应用中可以通过一个比较灵活的霍夫梯度法来解决圆变换的这一问题。
霍夫梯度法的原理如下。首先对图像应用边缘检测(这里是canny),然后,边缘图像中每一个非0点,考虑其局部梯度(通过cvsobel函数计算x和y反向的sobel一阶导数得到梯度)。利用得到的梯度,由斜率指定的直线上的每一个点都在累加器中累加,这里斜率是从一个指定的最小值到指定的最大值的距离。同时,标记边缘图像中每一个非0像素的位置,然后从(二维)累加器中这些点中选择候选的中心,这些中心都大于给定阈值并且大于其所有近邻。这些候选的中心按照累加值降序排列,以便于最支持像素的中心首先出现。接下来对每一个中心,考虑所有的非0像素(回想一下这个清单在早期已经建立)。这些像素按照其与中心的距离排序。从到最大半径的最小距离算起,选择非0像素最支持的一条半径。如果一个中心受到边缘图像非0像素最充分的支持,并且到前期被选择的中心有足够的距离,它将会被保留。
这个实现可以是算法执行起来更快,或许更重要的是,能够帮助解决三维累加器中其他稀疏分布问题,这个问题会产生许多噪声并使结果不稳定。另一方面,这个算法有许多需要注意的缺点。
首先,使用sobel导数计算局部梯度--随之而来的假设是这个可以看作等同于一条局部切线--并不是一个数值稳定做法。在大多数时间这个命题可能是真的,但你可能认为这样会在输出中产生一些噪声。
其次,在边缘图像中的整个非0像素集被认为是每个中心的候选。因此,如果把累加器的阈值设置偏低,算法将要消耗比较长的时间。第三,因为每一个中心只选择一个圆,如果有同心圆,就只能选择其中的一个。
最后,因为中心是被认为是按照与其关联的累加器的值升序排列的,并且如果新的中心过于接近以前接受的中心将不会被保留。这里有一个倾向就是当有许多同心圆或者是近似同心圆时,保留最大的一个圆。(只是个“偏见”,因为从sobel导数产生了噪声,若是在无穷分辨率的平滑图像,这才是确定的)。
霍夫圆变换的函数为:
HoughCircles
利用 Hough 变换在灰度图像中找圆
CvSeq* cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1=100, double param2=100, int min_radius=0, int max_radius=0 );
image
输入 8-比特、单通道灰度图像.
circle_storage
检测到的圆存储仓. 可以是内存存储仓 (此种情况下,一个线段序列在存储仓中被创建,并且由函数返回)或者是包含圆参数的特殊类型的具有单行/单列的CV_32FC3型矩阵(CvMat*). 矩阵头为函数所修改,使得它的 cols/rows 将包含一组检测到的圆。如果 circle_storage 是矩阵,而实际圆的数目超过矩阵尺寸,那么最大可能数目的圆被返回
. 每个圆由三个浮点数表示:圆心坐标(x,y)和半径.
method
Hough 变换方式,目前只支持CV_HOUGH_GRADIENT, which is basically 21HT, described in [Yuen03].
dp
累加器图像的分辨率。这个参数允许创建一个比输入图像分辨率低的累加器。(这样做是因为有理由认为图像中存在的圆会自然降低到与图像宽高相同数量的范畴)。如果dp设置为1,则分辨率是相同的;如果设置为更大的值(比如2),累加器的分辨率受此影响会变小(此情况下为一半)。dp的值不能比1小。
Resolution of the accumulator used to detect centers of the circles. For example, if it is 1, the accumulator will have the same resolution as the input image, if it is 2 - accumulator will have twice smaller width and height, etc.
min_dist
该参数是让算法能明显区分的两个不同圆之间的最小距离。
Minimum distance between centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed.
param1
用于Canny的边缘阀值上限,下限被置为上限的一半。
The first method-specific parameter. In case of CV_HOUGH_GRADIENT it is the higher threshold of the two passed to Canny edge detector (the lower one will be twice smaller).
param2
累加器的阀值。
The second method-specific parameter. In case of CV_HOUGH_GRADIENT it is accumulator threshold at the center detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first.
min_radius
最小圆半径。
Minimal radius of the circles to search for.
max_radius
最大圆半径。
Maximal radius of the circles to search for. By default the maximal radius is set to max(image_width, image_height).
The function cvHoughCircles finds circles in grayscale image using some modification of Hough transform.
现在值得考虑的一个事实是,不管我们用什么技巧,都不能绕过圆必须被描述成三个自由度的需求(x,y和r),与此形成对比的是直线只需要两个自由度(ρ, θ) 。必然出现的结果是寻找圆的算法比我们以前看到的寻找直线的算法需要更多的内存和计算量。考虑到这一点,为了让这些消耗能在掌控之内,在环境允许范围内牢固的限制半径参数是一个好的主意。通过考虑物体是梯度边缘的集合,1981年,ballard将霍夫圆变换拓展到任意形状。