霍夫变换是图像处理中的一个检测直线、圆等简单几何形状的方法。它最初是用于在二值化的图像中进行直线检测的。对于图像中的一条直线而言,利用直角坐标系,可以表示为:的形式。那么,该直线上任意一点(x,y)变换到k-b参数空间将变成一个“点”。也就是说,将图像空间中所有的非零像素转换到k-b参数空间,那么它们将聚焦在一个点上。如此一来,参数空间中的一个局部峰值点就很有可能对应着原图像空间中的一条直线。不过,由于直线的斜率可能为无穷大,或者无穷小,那么,在k-b参数空间就不便于对直线进行刻画和描述。所以,研究人员提出采用极坐标参数空间进行直线检测。在极坐标系中,直线可以表述为以下形式:
上图(a)所示为原始的图像空间中一个点;(b)所示为直角坐标系当中为过同一四条直线;(c)所示为这四条直线在极坐标参数空间可以表示为四个点;
在OpenCV当中,霍夫之间检测函数并不会告诉你具体的计算步骤,而只是将极坐标空间中局部峰值点予以返回。OpenCV支持两种不同的霍夫直线变换。the Standard Hough Transform(SHT,标准霍夫变换)和 Progressive Probability Houth Transform(PPHT,渐进概率式霍夫变换)。SHT就是刚才所述的在极坐标空间进行参数表示的方法。而PPHT是SHT的改进,它是在一定的范围内进行霍夫变换,从而减少计算量,缩短计算时间。在OpenCV中,以上两种霍夫直线变换,都可以用以下函数来实现:
CvSeq* cvHoughLines2(CvArr* image, void* lineStorage, int method, double rho, double theta, int threshold, double param1=0, double param2=0);该函数的第一个参数,是输入图片(必须是二值化后的图片),第二个参数是一个指针,指向保存函数返回结果的内存空间。第三个参数method可以是CV_HOUTH_STANDARD也可以是CV_HOUTH_PROBABILISTIC或者CV_HOUTH_MULTI_SCALE,分别代表了标准霍夫变换(SHT),渐进概率式霍夫变换(PPHT)和多尺度标准霍夫变换。接下来的两个参数rho和theta设置极坐标系的精度,其中rho以像素为单位,theta以弧度为单位。threshold是用户设定的一个阈值,只有超过该阈值才被认定为是一条符合条件的直线。在SHT方法中,param1和param2是不会被使用到的,而在PPHT方法中,param1设置检测到的直线(准确点说,是线段)的最短长度,param2则设置共线的两条线段的最小分割间隔。对于多尺度的标准霍夫变换(multi-scale SHT)来说,首先根据用户设定的rho和theta来检测直线,之后,按照param1和param2的值对检测结果进行优化(即,rho=rho/param1,theta=theta/param2)。
下面,我给出利用OpenCV中hough transform的直线检测代码:
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "iostream"
using namespace std;
bool key = false;
int _tmain(int argc, _TCHAR* argv[])
{
IplImage* src = cvLoadImage("c:/img1.bmp", CV_LOAD_IMAGE_GRAYSCALE);
if (!src)
{
cout<<"src load error..."<<endl;
system("pause");
exit(-1);
}
IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
//cvCanny( src, dst, 50, 200, 3 );
cvThreshold(src, dst, 50, 255, CV_THRESH_BINARY_INV);
cvCvtColor(dst, color_dst, CV_GRAY2BGR);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* lines = 0;
int i;
if (key)
{
lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 100, 0, 0 );
for( i = 0; i < MIN(lines->total,100); i++ )
{
float* line = (float*)cvGetSeqElem(lines,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( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, CV_AA, 0 );
}
}
else
{
lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 50, 50, 10 );
for( i = 0; i < lines->total; i++ )
{
CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, CV_AA, 0 );
}
}
cvNamedWindow( "Source", 1 );
cvShowImage( "Source", src );
cvNamedWindow( "Hough", 1 );
cvShowImage( "Hough", color_dst );
cvSaveImage("c:/result.bmp", color_dst);
cvWaitKey(0);
cvReleaseImage(&src);
cvReleaseImage(&dst);
cvReleaseImage(&color_dst);
cvClearSeq(lines);
cvReleaseMemStorage(&storage);
system("pause");
return 0;
}
以上代码的执行结果为:
原图
直线检测结果