Hough变换检测直线求助
请用C语言写一段hough变换直线检测代码,一定要是基于opencv的!!!感激不尽。。。水笔,骗分党滚开。...
请用C语言写一段hough变换直线检测代码,一定要是基于opencv的!!!感激不尽。。。
水笔,骗分党滚开。 展开
水笔,骗分党滚开。 展开
展开全部
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 代码:
在matlab中提供了hough变换的代码,有hough,houghlines,houghpeaks,具体的使用可以在help中查到。
(II)圆篇
继使用hough变换检测出直线之后,顺着坐标变换的思路,提出了一种检测圆的方法。
1 如何表示一个圆?
与使用(r,theta)来表示一条直线相似,使用(a,b,r)来确定一个圆心为(a,b)半径为 r 的圆。
2 如何表示过某个点的所有圆?
某个圆过点(x1,y1),则有:(x1-a1)^2 + (y1-b1)^2 = r1^2 。
那么过点(x1,y1)的所有圆可以表示为(a1(i),b1(i),r1(i)),其中r1∈(0,无穷),每一个 i 值都对应一个不同的圆,(a1(i),b1(i),r1(i))表示了无穷多个过点(x1,y1)的圆。
3 如何确定多个点在同一个圆上?
如(2)中说明,过点(x1,y1)的所有圆可以表示为(a1(i),b1(i),r1(i)),过点(x2,y2)的所有圆可以表示为(a2(i),b2(i),r2(i)),过点(x3,y3)的所有圆可以表示为(a3(i),b3(i),r3(i)),如果这三个点在同一个圆上,那么存在一个值(a0,b0,r0),使得 a0 = a1(k)=a2(k)=a3(k) 且b0 = b1(k)=b2(k)=b3(k) 且r0 = r1(k)=r2(k)=r3(k),即这三个点同时在圆(a0,b0,r0)上。
对于平面中的一条直线,在笛卡尔坐标系中,常见的有点斜式,两点式两种表示方法。然而在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 代码:
在matlab中提供了hough变换的代码,有hough,houghlines,houghpeaks,具体的使用可以在help中查到。
(II)圆篇
继使用hough变换检测出直线之后,顺着坐标变换的思路,提出了一种检测圆的方法。
1 如何表示一个圆?
与使用(r,theta)来表示一条直线相似,使用(a,b,r)来确定一个圆心为(a,b)半径为 r 的圆。
2 如何表示过某个点的所有圆?
某个圆过点(x1,y1),则有:(x1-a1)^2 + (y1-b1)^2 = r1^2 。
那么过点(x1,y1)的所有圆可以表示为(a1(i),b1(i),r1(i)),其中r1∈(0,无穷),每一个 i 值都对应一个不同的圆,(a1(i),b1(i),r1(i))表示了无穷多个过点(x1,y1)的圆。
3 如何确定多个点在同一个圆上?
如(2)中说明,过点(x1,y1)的所有圆可以表示为(a1(i),b1(i),r1(i)),过点(x2,y2)的所有圆可以表示为(a2(i),b2(i),r2(i)),过点(x3,y3)的所有圆可以表示为(a3(i),b3(i),r3(i)),如果这三个点在同一个圆上,那么存在一个值(a0,b0,r0),使得 a0 = a1(k)=a2(k)=a3(k) 且b0 = b1(k)=b2(k)=b3(k) 且r0 = r1(k)=r2(k)=r3(k),即这三个点同时在圆(a0,b0,r0)上。
展开全部
人家要求的是基于opencv的代码:
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
const char *pstrWindowsSrcTitle = "原图";
const char *pstrWindowsLineName = "线段检测";
// 从文件中加载原图
IplImage *pSrcImage = cvLoadImage("d:\\5.jpg", CV_LOAD_IMAGE_UNCHANGED);
// 灰度图
IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
// 边缘图
IplImage *pCannyImage = cvCreateImage(cvGetSize(pSrcImage), 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 = 50; //最小线段长度
double fMinLineGap = 10; //最小线段间隔
CvSeq *pcvSeqLines = cvHoughLines2(pCannyImage, pcvMStorage, CV_HOUGH_PROBABILISTIC, fRho, fTheta, nMaxLineNumber, fMinLineLen, fMinLineGap);
// 绘制线段
IplImage *pColorImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 3);
cvCvtColor(pCannyImage, pColorImage, CV_GRAY2BGR);
int i;
for(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, pSrcImage);
cvNamedWindow(pstrWindowsLineName, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsLineName, pColorImage);
cvWaitKey(0);
cvReleaseMemStorage(&pcvMStorage);
cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsLineName);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&pGrayImage);
cvReleaseImage(&pCannyImage);
cvReleaseImage(&pColorImage);
return 0;
}
兄弟,别人的回答,和我的回答,哪个才是你要求,你看着办。。。
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
const char *pstrWindowsSrcTitle = "原图";
const char *pstrWindowsLineName = "线段检测";
// 从文件中加载原图
IplImage *pSrcImage = cvLoadImage("d:\\5.jpg", CV_LOAD_IMAGE_UNCHANGED);
// 灰度图
IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
// 边缘图
IplImage *pCannyImage = cvCreateImage(cvGetSize(pSrcImage), 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 = 50; //最小线段长度
double fMinLineGap = 10; //最小线段间隔
CvSeq *pcvSeqLines = cvHoughLines2(pCannyImage, pcvMStorage, CV_HOUGH_PROBABILISTIC, fRho, fTheta, nMaxLineNumber, fMinLineLen, fMinLineGap);
// 绘制线段
IplImage *pColorImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 3);
cvCvtColor(pCannyImage, pColorImage, CV_GRAY2BGR);
int i;
for(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, pSrcImage);
cvNamedWindow(pstrWindowsLineName, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsLineName, pColorImage);
cvWaitKey(0);
cvReleaseMemStorage(&pcvMStorage);
cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsLineName);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&pGrayImage);
cvReleaseImage(&pCannyImage);
cvReleaseImage(&pColorImage);
return 0;
}
兄弟,别人的回答,和我的回答,哪个才是你要求,你看着办。。。
本回答被提问者采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
希望可以帮助到你
如果有帮助,请采纳
/*
函数功能:通过hough变换检测直线
参数说明:imgBinaryIn,表示二值图象
width,表示图象宽
height,表示图象高
houghBuf,表示hough变换需要的缓冲区指针
houghWidth,表示hough变换需要的缓冲区的宽
houghHeight,表示hough变换需要的缓冲区的高
radiusResolution,表示hough变换的极坐标半径的检测分辨率
angleResolution,表示hough变换的角度检测分辨率
radius,表示返回hough变换检测出来的最长直线的极半径
angle,表示返回hough变换检测出来的最长直线的角度
*/
void ImageAlgorithm::HoughTransForm(unsigned char * imgBinaryIn,int width,int height,int *houghBuf,int houghWidth,int houghHeight,float radiusResolution,float angleResolution,float *radius,float *angle)
{
int i,j;
for(i=0;i<houghHeight;i++)
{
for (j=0;j<houghWidth;j++)
{
*(houghBuf+i*houghWidth+j) = 0;
}
}
int r,a;
float tempR,tempA;
//遍历图象数据
for(i=0;i<height;i++)
{
for(j=0;j<width;j++)
{
if(*(imgBinaryIn+i*width+j)==1)
{
//a代表角度的循环变量,在变换空间累加数组的垂直方向上
for(a=0;a<houghHeight;a++)
{
//按照给定变换角度的分辨率,求取角度
tempA = (a-houghHeight/2)*angleResolution;
//根据当前遍历的角度及x,y值求取对应极坐标
tempR = (j-width/2)*cos(tempA*2*PI/360) + (i-height/2)*sin(tempA*2*PI/360);
r = tempR/radiusResolution;
//累加数组
*(houghBuf+a*houghWidth+r+houghWidth/2)+=1;
}
}
}
}
//求累加数组的极大值,并记录此时的数组坐标
int max,maxR,maxA;
max = *(houghBuf+0*houghWidth+0);
maxR = 0;
maxA = 0;
for(a=0;a<houghHeight;a++)
{
for(r=0;r<houghWidth;r++)
{
if(max<=*(houghBuf+a*houghWidth+r))
{
max = *(houghBuf+a*houghWidth+r);
maxR = r;
maxA = a;
}
}
}
//将极大值位置转换成极坐标半径和角度,并通过参数返回
*radius = (maxR-houghWidth/2)*radiusResolution;
*angle = (maxA-houghHeight/2)*angleResolution;
}
如果有帮助,请采纳
/*
函数功能:通过hough变换检测直线
参数说明:imgBinaryIn,表示二值图象
width,表示图象宽
height,表示图象高
houghBuf,表示hough变换需要的缓冲区指针
houghWidth,表示hough变换需要的缓冲区的宽
houghHeight,表示hough变换需要的缓冲区的高
radiusResolution,表示hough变换的极坐标半径的检测分辨率
angleResolution,表示hough变换的角度检测分辨率
radius,表示返回hough变换检测出来的最长直线的极半径
angle,表示返回hough变换检测出来的最长直线的角度
*/
void ImageAlgorithm::HoughTransForm(unsigned char * imgBinaryIn,int width,int height,int *houghBuf,int houghWidth,int houghHeight,float radiusResolution,float angleResolution,float *radius,float *angle)
{
int i,j;
for(i=0;i<houghHeight;i++)
{
for (j=0;j<houghWidth;j++)
{
*(houghBuf+i*houghWidth+j) = 0;
}
}
int r,a;
float tempR,tempA;
//遍历图象数据
for(i=0;i<height;i++)
{
for(j=0;j<width;j++)
{
if(*(imgBinaryIn+i*width+j)==1)
{
//a代表角度的循环变量,在变换空间累加数组的垂直方向上
for(a=0;a<houghHeight;a++)
{
//按照给定变换角度的分辨率,求取角度
tempA = (a-houghHeight/2)*angleResolution;
//根据当前遍历的角度及x,y值求取对应极坐标
tempR = (j-width/2)*cos(tempA*2*PI/360) + (i-height/2)*sin(tempA*2*PI/360);
r = tempR/radiusResolution;
//累加数组
*(houghBuf+a*houghWidth+r+houghWidth/2)+=1;
}
}
}
}
//求累加数组的极大值,并记录此时的数组坐标
int max,maxR,maxA;
max = *(houghBuf+0*houghWidth+0);
maxR = 0;
maxA = 0;
for(a=0;a<houghHeight;a++)
{
for(r=0;r<houghWidth;r++)
{
if(max<=*(houghBuf+a*houghWidth+r))
{
max = *(houghBuf+a*houghWidth+r);
maxR = r;
maxA = a;
}
}
}
//将极大值位置转换成极坐标半径和角度,并通过参数返回
*radius = (maxR-houghWidth/2)*radiusResolution;
*angle = (maxA-houghHeight/2)*angleResolution;
}
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询