Hough变换直线检测
http://blog.csdn.net/kezunhai
霍夫变换是图像变换中的经典算法之一,主要用来从图像中分离出具有某种相同特征的几何形状(如,直线,圆等)。霍夫变换寻找直线与圆的方法相比与其它方法可以更好的减少噪声干扰。Hough变换的基本原理在于利用点与线的对偶性,将原始图像空间的曲线通过转换到参数空间的一个点。
从图中可以看到,x-y坐标和K-b坐标有点——线的对偶性。x-y坐标中的P1、P2对应于k-b坐标中的L1、L2;而k-b坐标中的P0对应于x-y坐标中的直线L0。而考虑到当K值为无穷大时,给计算带来的不变,股采用极坐标的形式来表示,则有:
P = x*cos(a)+y*sin(a)
在极坐标a-p中为一条正弦曲线(P = c*sin(a+theta),a取(0-180°)。
为了检测出直角坐标X-Y中由点构成的直线,可以将极坐标A-P量化成许多的小格。根据直角坐标中每个点的坐标(x,y),在a=0-180°内以小格的不长计算各个P值,所得的值落在小格内,则对应的累加器加1。当直角坐标中的全部点都变换后,对小格进行检验,计数值最大的小格,其(a,p)值对应直角坐标所求的直线。这样就把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题,也即把检测整体特性转化为检测局部特性。
Opencv库中自带有HoughLines直线检测函数,主要实现了标准的Hough变换和基于概率的Hough变换(同时也实现多尺度的Hough变换)。
int main() { IplImage *srcRGB = cvLoadImage("f:\\images\\chess1.jpg"); IplImage *src = cvCreateImage(cvSize(srcRGB->width,srcRGB->height),IPL_DEPTH_8U,1); cvCvtColor(srcRGB,src,CV_RGB2GRAY); IplImage *dst = cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,src->nChannels); IplImage *color_dst = cvCloneImage(srcRGB);cvSetZero(color_dst); CvMemStorage *storage = cvCreateMemStorage(); CvSeq *lines = 0; cvCanny(src,dst,40,90); cvCvtColor(dst,color_dst,CV_GRAY2RGB); #if 1 lines = cvHoughLines2(dst, storage, CV_HOUGH_STANDARD,1 ,CV_PI/180, 150 ,0 ,0); for(int i = 0;i<MIN(lines->total,100);i++){ float *line = (float*)cvGetSeqElem(lines,i); float rho = line[0]; float threta = line[1]; CvPoint pt1, pt2; // 这个地方的计算公式,在文章下面介绍。 double a = cos(threta),b = sin(threta); 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(color_dst,pt1,pt2,CV_RGB(255,0,0),1,8); } #else lines = cvHoughLines2(dst, storage, CV_HOUGH_PROBABILISTIC,1, CV_PI/180, 100, 50, 10); for(int i = 0;i<lines->total; ++i){ CvPoint *line = (CvPoint*)cvGetSeqElem(lines,i); cvLine(color_dst,line[0],line[1],CV_RGB(255,0,0),1,8); } #endif cvShowImage("source",src); cvShowImage("Hough",color_dst); cvShowImage("dst",dst); cvWaitKey(0); }Hough变换不仅可以检测直线,而且还可以检测圆、椭圆和矩形等规则几何图形。除此以外,学者对Hough变换进行泛化,提出了广义Hough变换,广义Hough变换在Opencv也进行了实现。其实现代码如下:
void cv::GeneralizedHough::setTemplate(InputArray _templ, int cannyThreshold, Point templCenter) { Mat templ = _templ.getMat(); CV_Assert(templ.type() == CV_8UC1); CV_Assert(cannyThreshold > 0); Canny(templ, edges_, cannyThreshold / 2, cannyThreshold); Sobel(templ, dx_, CV_32F, 1, 0); Sobel(templ, dy_, CV_32F, 0, 1); if (templCenter == Point(-1, -1)) templCenter = Point(templ.cols / 2, templ.rows / 2); setTemplateImpl(edges_, dx_, dy_, templCenter); } void cv::GeneralizedHough::setTemplate(InputArray _edges, InputArray _dx, InputArray _dy, Point templCenter) { Mat edges = _edges.getMat(); Mat dx = _dx.getMat(); Mat dy = _dy.getMat(); if (templCenter == Point(-1, -1)) templCenter = Point(edges.cols / 2, edges.rows / 2); setTemplateImpl(edges, dx, dy, templCenter); } void cv::GeneralizedHough::detect(InputArray _image, OutputArray positions, OutputArray votes, int cannyThreshold) { Mat image = _image.getMat(); CV_Assert(image.type() == CV_8UC1); CV_Assert(cannyThreshold > 0); Canny(image, edges_, cannyThreshold / 2, cannyThreshold); Sobel(image, dx_, CV_32F, 1, 0); Sobel(image, dy_, CV_32F, 0, 1); detectImpl(edges_, dx_, dy_, positions, votes); } void cv::GeneralizedHough::detect(InputArray _edges, InputArray _dx, InputArray _dy, OutputArray positions, OutputArray votes) { cv::Mat edges = _edges.getMat(); cv::Mat dx = _dx.getMat(); cv::Mat dy = _dy.getMat(); detectImpl(edges, dx, dy, positions, votes); }该算法可以用模板来表示几何形状,从而实现其形状的提取。Hough变换是一种比较广泛使用的几何形状提取算法,近年来,也出现了其他的一些几何形状提取算法,如针对直线提取的就有LSD(Line Segment detector)等。
参考资料:
1、opencv 霍夫变换检测直线
2、http://rosettacode.org/wiki/Example:Hough_transform/C
作者:kezunhai出处:http://blog.csdn.net/kezunhai欢迎转载或分享,但请务必声明文章出处。