一、基本 原理
Hough变换是一种使用表决原理的参数估计技术。其原理是利用图像空间和Hough参数空间的点-线对偶性,把图像空间中的检测问题转换到参数空间。通过在参数空间里进行简单的累加统计,然后在Hough参数空间寻找累加器峰值的方法检测直线。Hough变换的实质是将图像空间内具有一定关系的像元进行聚类,寻找能把这些像元用某一解析形式联系起来的参数空间累积对应点。在参数空间不超过二维的情况下,这种变换有着理想的效果。Hough变换是图像处理中从图像中识别几何形状的基本方法一。Hough变换在于利用点与线的对偶性,将原始图像空间的给定的曲线通过曲线表达形式变为参数空间的一个点。这样就把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题。也即把检测整体特性转化为检测局部特性。比如直线、椭圆、圆、弧线等。
二、基本思想
设已知一黑白图像上画了一条直线,要求出这条直线所在的位置。我们知道,直线的方程可以用y=k*x+b 来表示,其中k和b是参数,分别是斜率和截距。过某一点(x0,y0)的所有直线的参数都会满足方程y0=kx0+b。即点(x0,y0)确定了一族直线。方程y0=kx0+b在参数k--b平面上是一条直线,(你也可以是方程b=-x0*k+y0对应的直线)。这样,图像x--y平面上的一个前景像素点就对应到参数平面上的一条直线。我们举个例子说明解决前面那个问题的原理。设图像上的直线是y=x, 我们先取上面的三个点:A(0,0), B(1,1), C(2,2)。可以求出,过A点的直线的参数要满足方程b=0, 过B点的直线的参数要满足方程1=k+b, 过C点的直线的参数要满足方程2=2k+b, 这三个方程就对应着参数平面上的三条直线,而这三条直线会相交于一点(k=1,b=0)。 同理,原图像上直线y=x上的其它点(如(3,3),(4,4)等) 对应参数平面上的直线也会通过点(k=1,b=0)。这个性质就为我们解决问题提供了方法,就是把图像平面上的点对应到参数平面上的线,最后通过统计特性来解决问题。假如图像平面上有两条直线,那么最终在参数平面上就会看到两个峰值点,依此类推。
简而言之,Hough变换思想为:在原始图像坐标系下的一个点对应了参数坐标系中的一条直线,同样参数坐标系的一条直线对应了原始坐标系下的一个点,然后,原始坐标系下呈现直线的所有点,它们的斜率和截距是相同的,所以它们在参数坐标系下对应于同一个点。这样在将原始坐标系下的各个点投影到参数坐标系下之后,看参数坐标系下有没有聚集点,这样的聚集点就对应了原始坐标系下的直线。
在实际应用中,y=k*x+b形式的直线方程没有办法表示x=c形式的直线(这时候,直线的斜率为无穷大)。所以实际应用中,是采用参数方程p=x*cos(theta)+y*sin(theta)。这样,图像平面上的一个点就对应到参数p---theta平面上的一条曲线上,其它的还是一样。
三、Hough变换推广
1、已知半径的圆
其实Hough变换可以检测任意的已知表达形式的曲线,关键是看其参数空间的选择,参数空间的选择可以根据它的表达形式而定。比如圆的表达形式为 ,所以当检测某一半径的圆的时候,可以选择与原图像空间同样的空间作为参数空间。那么圆图像空间中的一个圆对应了参数空间中的一个点,参数空间中的一个点对应了图像空间中的一个圆,圆图像空间中在同一个圆上的点,它们的参数相同即a,b相同,那么它们在参数空间中的对应的圆就会过同一个点(a,b),所以,将原图像空间中的所有点变换到参数空间后,根据参数空间中点的聚集程度就可以判断出图像空间中有没有近似于圆的图形。如果有的话,这个参数就是圆的参数。
2、未知半径的圆
对于圆的半径未知的情况下,可以看作是有三个参数的圆的检测,中心和半径。这个时候原理仍然相同,只是参数空间的维数升高,计算量增大。图像空间中的任意一个点都对应了参数空间中的一簇圆曲线 ,其实是一个圆锥型。参数空间中的任意一个点对应了图像空间中的一个圆。
3、椭圆
椭圆有5个自由参数,所以它的参数空间是5维的,因此他的计算量非常大,所以提出了许多的改进算法。
四、总结
图像空间中的在同一个圆,直线,椭圆上的点,每一个点都对应了参数空间中的一个图形,在图像空间中这些点都满足它们的方程这一个条件,所以这些点,每个投影后得到的图像都会经过这个参数空间中的点。也就是在参数空间中它们会相交于一点。所以,当参数空间中的这个相交点的越大的话,那么说明元图像空间中满足这个参数的图形越饱满。越象我们要检测的东西。
Hough变换能够查找任意的曲线,只要你给定它的方程。Hough变换在检验已知形状的目标方面具有受曲线间断影响小和不受图形旋转的影响的优点,即使目标有稍许缺损或污染也能被正确识别。
五、改进方法
Hough变换的实质是将图像空间内具有一定关系的像元进行聚类,寻找能把这些像元用某一解析形式联系起来的参数空间累积对应点。在参数空间不超过二维的情况下,这种变换有着理想的效果。但是,一旦参数空间增大,计算量便会急剧上升,同时耗费巨大的存储空间,耗时也随之猛增。就此,多年来国内外众多学者针对具体情况对常规Hough变换进行了多方面的探索,并提出了许多有价值的改进方法。
1)扩展应用范围,提出多种参数化的方法
在早期的研究中,Hough变换由只检测图像中的直线扩展到检测圆弧、二次曲线和任意曲线构成的形状;线条的参数化方法也由最初的截距型参数发展到斜率倾角和截距型参数、双Hough空间型参数、以及检测圆的圆心坐标、半径型参数和检测物体复杂形状的基于模板的多维关键点参数等。
2)提高实时性,提出多种减少计算量的方法
针对Hough变换计算量大的不足,相继提出了四分树结构的Hough变换、以梯度信息为引导的Hough变换、分层Hough变换、自适应Hough变换、快速自适应Hough变换、随机Hough变换(RHT)等;对于高维Hough变换采用降维处理,数据结构多采用动态量化空间等。
3)增强抗干扰能力,提高检测精度
Hough变换提取精度问题始终受到普遍关注,例如Hough变换的离散化误差、混叠干扰、抗噪声干扰性能等。就此类问题的研究例如,Kiryati、Buckstein提出采用最佳Kaider窗函数对参数域进行平滑滤波以减少混叠误差;Hunt、Nolte等人应用信号检测理论对Hough变换的抗干扰性能和基于最大后验概率的最佳算法进行了抗干扰性能比较,并指出了影响Hough变换抗干扰性能的原因。
4)多种峰值检测方法
Hough变换中参数空间的峰值检测是一个聚类检测问题,阈值的选取是成功与否的关键所在。其中,一种方法是对图像空间进行加权,以改变参数空间的峰值分布;一种方法是直接对参数空间进行极大值的搜索。
六、程序源码
下面分享的是hough线变换和hough圆变换的程序,部分函数的详细说明在下一篇blog列出。
hough线变换:
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
#include <math.h>
int main(int argc, char** argv)
{
IplImage* src = cvLoadImage("2.jpg",1);
IplImage* image=cvCreateImage(cvGetSize(src),src->depth,1);
cvCvtColor(src,image,CV_BGR2GRAY);
cvSmooth(image, image, CV_GAUSSIAN, 5, 5 );
cvCanny( image, image, 0, 30, 3 );
//霍夫线检测
CvMemStorage* storage1 = cvCreateMemStorage(0);
CvSeq* results1 = cvHoughLines2(image, storage1, CV_HOUGH_STANDARD, 2, CV_PI/180, 100, 0, 0);
for( int i = 0; i < MIN(results1->total,100); i++ )
{
float* line = (float*)cvGetSeqElem(results1,i);
float rho = line[0];
float theta = line[1];
CvPoint 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(y0 - 1000*(a));
cvLine(src, pt1, pt2, CV_RGB(0,255,0), 1, CV_AA, 0 );
}
cvNamedWindow( "cvHough", 1);
cvShowImage( "cvHough", src);
cvWaitKey(0);
return 0;
}
hough圆变换:
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
#include <math.h>
int main(int argc, char** argv)
{
IplImage* src = cvLoadImage("2.jpg",1);
IplImage* image=cvCreateImage(cvGetSize(src),src->depth,1);
cvCvtColor(src,image,CV_BGR2GRAY);
cvSmooth(image, image, CV_GAUSSIAN, 5, 5 );
int i=0;
//霍夫圆检测
CvMemStorage* storage2 = cvCreateMemStorage(0);
CvSeq* results2 = cvHoughCircles(image, storage2, CV_HOUGH_GRADIENT, 2, image->width/10,55,50,0,80);
for( i = 0; i < results2->total; i++ )
{
float* p = (float*) cvGetSeqElem( results2, i );
CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
cvCircle(src,pt, cvRound( p[2] ),CV_RGB(255,0,0) );
}
cvNamedWindow( "cvHough", 1);
cvShowImage( "cvHough", src);
cvWaitKey(0);
return 0;
}
七、运行结果
【注】原理复制他处,添加了部分内容。