Hough变换原理及应用
来源:互联网 发布:售电软件哪家好 编辑:程序博客网 时间:2024/05/16 10:13
霍夫变换原理介绍可参见冈萨勒斯的《数字图像处理》第二版476页。
在xy平面上的一点(x0,y0)要转换为极坐标下的(θ,ρ):
x0 = ρcosθ
y0 = ρsinθ
那么
x0cosθ = ρcosθcosθ
y0sinθ = ρsinθsinθ
可得
x0cosθ + y0sinθ = ρ
那么xy坐标平面到极坐标θρ平面的转换公式为:
xcosθ + ysinθ = ρ
可以看出xy平面上的一点在极坐标θρ平面上的投影为一条正弦曲线,那么n个点对应n条正弦曲线,这n条曲线如果有m条曲线线交于一点(θ0,ρ0),那么这m条曲线对应在xy平面下的m个点就在同一直线上,而θ0就是这条直线的法线与x轴的夹角,ρ0为原点到直线的距离。
如果理解了霍夫变换的原理,接下来就可以看一下变换源码了。
下面是OpenCV自带的标准霍夫变换函数:
static voidicvHoughLinesStandard( const CvMat* img, float rho, float theta, int threshold, CvSeq *lines, int linesMax ){ cv::AutoBuffer<int> _accum, _sort_buf; cv::AutoBuffer<float> _tabSin, _tabCos; const uchar* image; int step, width, height; int numangle, numrho; int total = 0; int i, j; float irho = 1 / rho; double scale; CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 ); image = img->data.ptr; step = img->step; width = img->cols; height = img->rows; numangle = cvRound(CV_PI / theta); numrho = cvRound(((width + height) * 2 + 1) / rho); _accum.allocate((numangle+2) * (numrho+2)); _sort_buf.allocate(numangle * numrho); _tabSin.allocate(numangle); _tabCos.allocate(numangle); int *accum = _accum, *sort_buf = _sort_buf; float *tabSin = _tabSin, *tabCos = _tabCos; memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) ); float ang = 0; for(int n = 0; n < numangle; ang += theta, n++ ) { tabSin[n] = (float)(sin((double)ang) * irho); tabCos[n] = (float)(cos((double)ang) * irho); } // stage 1. fill accumulator for( i = 0; i < height; i++ ) for( j = 0; j < width; j++ ) { if( image[i * step + j] != 0 ) for(int n = 0; n < numangle; n++ ) { int r = cvRound( j * tabCos[n] + i * tabSin[n] ); r += (numrho - 1) / 2; accum[(n+1) * (numrho+2) + r+1]++; } } // stage 2. find local maximums for(int r = 0; r < numrho; r++ ) for(int n = 0; n < numangle; n++ ) { int base = (n+1) * (numrho+2) + r+1; if( accum[base] > threshold && accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] && accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] ) sort_buf[total++] = base; } // stage 3. sort the detected lines by accumulator value icvHoughSortDescent32s( sort_buf, total, accum ); // stage 4. store the first min(total,linesMax) lines to the output buffer linesMax = MIN(linesMax, total); scale = 1./(numrho+2); for( i = 0; i < linesMax; i++ ) { CvLinePolar line; int idx = sort_buf[i]; int n = cvFloor(idx*scale) - 1; int r = idx - (n+1)*(numrho+2) - 1; line.rho = (r - (numrho - 1)*0.5f) * rho; line.angle = n * theta; cvSeqPush( lines, &line ); }}
步骤为:
1、将θ离散值的sin、cos的计算结果存在数组中,便于下一步使用。
2、将原图中灰度值不为0的点变换到θρ空间的正弦曲线,而θρ空间相当于一个累加器。
3、将累加器的值进行排序,使用的是最大邻域值法,可以看出邻域很小,邻域小计算速度就快。
4、输出累加器中值最大的几个值。
参见上面的源码写出自己的代码与之比较。
原图:
源码:
<pre name="code" class="cpp">#include "stdafx.h"#include <cv.h>#include <opencv2\highgui\highgui.hpp>using namespace cv;int _tmain(int argc, _TCHAR* argv[]){Mat src = imread("E:\\VC++Projects\\road.jpg");Mat gray = Mat::zeros(src.size(),CV_8UC1);cvtColor(src, gray, CV_BGR2GRAY);// 求得x和y方向的一阶微分Mat sobelx;Mat sobely;Sobel(gray, sobelx, CV_32F, 1, 0, 3);Sobel(gray, sobely, CV_32F, 0, 1, 3);gray.release();// 求得梯度和方向Mat norm;Mat dir;cartToPolar(sobelx, sobely, norm, dir);sobelx.release();sobely.release();// 转换为8位单通道图像double normMax;minMaxLoc(norm, NULL, &normMax);Mat grad;norm.convertTo(grad, CV_8UC1, 255.0/normMax, 0);// OpenCV自带大津阈值函数处理Mat cvOstu;threshold(grad, cvOstu, 0, 255, CV_THRESH_BINARY|CV_THRESH_OTSU);norm.release();dir.release();grad.release();//vector<Vec2f> lines;//HoughLines( cvOstu, lines, 1, CV_PI/180, 100 );//for( size_t i = 0; i < 10/*lines.size()*/; i++ )//{//float rho = lines[i][0];//float theta = lines[i][1];//double a = cos(theta), b = sin(theta);//double x0 = a*rho, y0 = b*rho;//Point pt1(cvRound(x0 + 1000*(-b)),//cvRound(y0 + 1000*(a)));//Point pt2(cvRound(x0 - 1000*(-b)),//cvRound(y0 - 1000*(a)));//line( src, pt1, pt2, Scalar(0,0,255), 1, 8 );//}vector<Vec4i> lines2;HoughLinesP( cvOstu, lines2, 1, CV_PI/180, 80, 30, 10 );for( size_t i = 0; i < 10/*lines2.size()*/; i++ ){line( src, Point(lines2[i][0], lines2[i][1]),Point(lines2[i][2], lines2[i][3]), Scalar(0,255,0), 1, 8 );}namedWindow("src");imshow("src", src);namedWindow("binary");imshow("binary", cvOstu);waitKey(0);return 0;}
使用标准霍夫变换结果:
使用概率霍夫变换的结果:
看到上面的结果,会发现虽然找出了直线,但是可能结果并不是想要的,比如在几条直线过于接近(θ,ρ的差值很小)的只显示一条。那么必须扩大最大值的搜素邻域,当然扩大搜索邻域会增加搜索时间。根据自己的要求,采用合适的方法!
0 0
- Hough变换原理及应用
- Hough变换的原理及应用
- 直线hough变换原理及实现
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理简介
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理
- Hough变换原理
- java数组操作工具类
- cumulative
- Linux下打印驱动的问与答
- win7安装centos7,win7不能引导
- 详细介绍 javascript:void(0)的使用
- Hough变换原理及应用
- Java中写入文件时换行符是用“\r\n"还是"\n”?
- memcached一些整理
- 数据库中字段类型 要特别注意
- 一笔画问题(搜索)
- 动画详解
- AtomicInteger介绍
- app推广新招,让你的用户主动分享
- document.getElementsByName()与 getElementById()、getElementsByTagName()的区别和parentNode.removeChild的作用