霍夫变换可以用于查找图片中存在的直线或圆,常用于车道线检测、路牌检测等中。其基本理论是二值化图像上的任何点都有可能是一些候选直线集合的一部分。在平面直角坐标系(x-y)中,一条直线可以用下式表示。
y=kx+b
对于直线上一个确定的点(x_0,y_0),有:y_0=kx_0+b
这表示参数平面(k-b)中的一条直线。因此,图像中的一个点对应参数平面中的一条直线,图像中的一条直线对应参数平面中的一个点。对图像上所有的点作霍夫变换,最终所要检测的直线对应的一定是参数平面中直线相交最多的那个点。这样就在图像中检测出了直线。在实际应用中,直线通常采用参数方程:
opencv中集合了两种霍夫变换:标准霍夫变换(SHT)和累计概率霍夫变换(PPHT)。函数如下:
CvSeq *cvHounghLines2 (
CvArr* image,
void* line_storage, // 保存结果位置的指针
int method,
double rho,
double theta,
int threshold,
double param1 = 0,
double param2 = 0
);
rho, theta用来设置直线所需的分辨率。rho的单位是像素,theta的单位是弧度。
SHT中没有使用param1、param2参数。对于PPHT,param1设置为将要返回的线段的最小长度,param2设置为一条直线上分离线段不能连成一条直线的分割像素点数。而在多尺度的HT,这两个参数是用来芝麻应呗计算的直线参数中较高的分辨率。
对于SHT,可以使用下列命令得到返回的检测直线:
float * line = (float *) cvGetSeqElem(lines,i);
对于PPHT,则有:
CvPoint * line = (CvPoint *) cvGetSeqElem(lines,i);
下面给出完整的霍夫变换检测直线示例:
#include <stdio.h>
#include <cv.h>
#include "highgui.h"
int main()
{
cvNamedWindow("grayimg",1);
cvNamedWindow("edges",1);
cvNamedWindow("hough",1);
cvMoveWindow("grayimg",0,0);
cvMoveWindow("edges",300,60);
cvMoveWindow("hough",30,120);
IplImage * img = cvLoadImage("e:/3.jpg");
IplImage * gray = NULL,*edges = NULL, *houghimg = NULL;
CvSize size;
size.width = img->width;
size.height = img->height;
CvMemStorage * storage = cvCreateMemStorage(0);
CvSeq *lines = 0;
gray = cvCreateImage(size,img->depth,1);
edges = cvCreateImage(size,img->depth,1);
houghimg = cvCreateImage(cvGetSize(img),img->depth,img->nChannels);
cvCvtColor(img,gray,CV_RGB2GRAY);
cvCanny(gray,edges,50,100,3); //先找出二值图像的边缘
cvCopy(img,houghimg);
lines = cvHoughLines2(edges,storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180,10,20,10 );
//printf("%d\n",lines->total);
int index; // index 为直线索引
for (index = 0; index < lines->total; index ++)
{
CvPoint *line = (CvPoint *)cvGetSeqElem(lines,index);
cvLine(houghimg,line[0],line[1],CV_RGB(255,0,0),3,8);
}
cvShowImage("grayimg",gray);
cvShowImage("edges",edges);
cvShowImage("hough",houghimg);
cvWaitKey();
cvDestroyAllWindows();
cvReleaseImage( &gray );
cvReleaseImage(&img);
cvReleaseImage( &edges );
system("pause");
return 0;
}
实验结果:实验中的参数将会影响检测到的直线数量。