您的位置:首页 > 编程语言 > C语言/C++

Hough检测直线原理及c++代码

2016-09-28 16:32 369 查看
(I)直线篇

1 直线是如何表示的?

对于平面中的一条直线,在笛卡尔坐标系中,常见的有点斜式,两点式两种表示方法。然而在hough变换中,考虑的是另外一种表示方式:使用(r,theta)来表示一条直线。其中r为该直线到原点的距离,theta为该直线的垂线与x轴的夹角。如下图所示。



2 如果坐标系中有多个点,又怎样识别出哪些点在一条直线上呢?

使用hough变换来检测直线的思想就是:为每一个点假设n个方向的直线,通常n=180,此时检测的直线的角度精度为1°,分别计算这n条直线的(r,theta)坐标,得到n个坐标点。如果要判断的点共有N个,最终得到的(r,theta)坐标有N*n个。有关这N*n个(r,theta)坐标,其中theta是离散的角度,共有180个取值。

最重要的地方来了,如果多个点在一条直线上,那么必有这多个点在theta=某个值theta_i时,这多个点的r近似相等于r_i。也就是说这多个点都在直线(r_i,theta_i)上。
3 下面拿个例子说明: 
如果空间中有3个点,如何判断这三个点在不在一个直线上,如果在,这条直线是的位置为?



 这个例子中,对于每个点均求过该点的6条直线的(r,theta)坐标,共求了3*6个(r,theta)坐标。可以发现在theta=60时,三个点的r都近似为80.7,由此可判定这三个点都在直线(80.7,60)上。

通过 r0theta 坐标系可以更直观表示这种关系,如下图:图中三个点的(r,theta)曲线汇集在一起,该交点就是同时经过这三个点的直线。 



在实际的直线检测情况中,如果超过一定数目的点拥有相同的(r,theta)坐标,那么就可以判定此处有一条直线。在r0theta 坐标系图中,明显的交汇点就标示一条检测出的直线。

如下图,可以判定出平面上的点共构成了两条直线,即检测出两条直线。



4 代码:(该代码只能检测二值图像,非二值图像必须与处理)
IplImage *pGrayImage = cvLoadImage("C:\\Users\\徐图之\\Desktop\\source.bmp", -1);
IplImage *pCannyImage = cvCreateImage(cvGetSize(pGrayImage), IPL_DEPTH_8U, 1);
cvCanny(pGrayImage, pCannyImage, 30, 90);
cvSmooth(pCannyImage, pCannyImage);

// 线段检测(只能针对二值图像)
CvMemStorage *pcvMStorage = cvCreateMemStorage();
double fRho = 1;
double fTheta = CV_PI / 180;
int nMaxLineNumber = 50;   //最多检测条直线
double fMinLineLen = 150;   //最小线段长度
double fMinLineGap = 10;   //最小线段间隔
CvSeq *pcvSeqLines = cvHoughLines2(pCannyImage, pcvMStorage, CV_HOUGH_PROBABILISTIC, fRho, fTheta, nMaxLineNumber, fMinLineLen, fMinLineGap);

// 绘制线段
IplImage *pColorImage = cvCreateImage(cvGetSize(pGrayImage), IPL_DEPTH_8U, 3);
cvCvtColor(pCannyImage, pColorImage, CV_GRAY2BGR);

for (int i = 0; i < pcvSeqLines->total; i++)
{
CvPoint* line = (CvPoint*)cvGetSeqElem(pcvSeqLines, i);
cvLine(pColorImage, line[0], line[1], CV_RGB(255, 0, 0), 2);
}

cvNamedWindow("pstrWindowsSrcTitle", CV_WINDOW_AUTOSIZE);
cvShowImage("pstrWindowsSrcTitle", pGrayImage);
cvNamedWindow("pstrWindowsLineName", CV_WINDOW_AUTOSIZE);
cvShowImage("pstrWindowsLineName", pColorImage);
cvWaitKey(0);
cvReleaseMemStorage(&pcvMStorage);
cvDestroyWindow("pstrWindowsSrcTitle");
cvDestroyWindow("pstrWindowsLineName");

cvReleaseImage(&pGrayImage);
cvReleaseImage(&pCannyImage);
cvReleaseImage(&pColorImage);


效果图:


 


[align=left]
[/align]
[align=left]5,opencv函数参数讲解:[/align]
函数功能:检测图像中的线段

函数原型:

CvSeq* cvHoughLines2(

  CvArr* image,

  void* line_storage,

  int method,

  double rho,

  double theta,

  int threshold,

  double param1=0, double param2=0

);

参数说明:

第一个参数表示输入图像,必须为二值图像(黑白图)。

第二个参数表示存储容器,和上一篇的轮廓检测一样,可以传入CvMemStorage类型的指针。

第三个参数表示变换变量,可以取下面的值:

  CV_HOUGH_STANDARD - 传统或标准 Hough 变换. 每一个线段由两个浮点数 (ρ, θ) 表示,其中 ρ 是线段与原点 (0,0) 之间的距离,θ 线段与 x-轴之间的夹角。

  CV_HOUGH_PROBABILISTIC - 概率 Hough 变换(如果图像包含一些长的线性分割,则效率更高)。它返回线段分割而不是整个线段。每个分割用起点和终点来表示。

  CV_HOUGH_MULTI_SCALE - 传统 Hough 变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的一致。

第四个参数表示与象素相关单位的距离精度。

第五个参数表示弧度测量的角度精度。

第六个参数表示检测线段的最大条数,如果已经检测这么多条线段,函数返回。

第七个参数与第三个参数有关,其意义如下:

  对传统 Hough 变换,不使用(0).

  对概率 Hough 变换,它是最小线段长度.

  对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / param1 ).

第八个参数与第三个参数有关,其意义如下:

  对传统 Hough 变换,不使用 (0).

  对概率 Hough 变换,这个参数表示在同一条线段上进行碎线段连接的最大间隔值(gap), 即当同一条线段上的两条碎线段之间的间隔小于param2时,将其合二为一。

  对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 theta / param2).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: