Hough变换——直线检测(投票方法实现)

来源:互联网 发布:ieee 802.11 mac协议 编辑:程序博客网 时间:2024/06/05 05:42
Hough变换介绍
Hough变换介绍:
   简单来说,就是一个叫做Hough的人提出的,主要是将空间坐标转换到参数空间。比如一条直线:y = kx + b吧,我们看到这个后就会想到用x,y两个轴,然后画个图像去描述这条直线。但是还有一些人不按常规出牌,用k和b来描述一条直线。
   但是还有另外一个问题就出现了,k有不存在的啊,一条竖直的直线怎么搞?出现了无穷大了就。
   我们看到的图片是一个有限的范围,所以一定可以有办法将无穷大转换为有穷大。此时,极坐标学的好的人出现了吐舌头,我们之所以看到的图片是个范围,是因为距离是一定的。极坐标两个参数,一个是rho,一个是theta,rho表示的是距离原点的距离,显然是有限的;theta只有360度,这样就可以保证图片能在计算机中进行处理喽。
参考地址如下:
点击打开链接

Hough变换步骤:
   简单介绍完了,就该开始Hough变换喽,先不多说,直接上流程图(老师作业,赶作业嘛,较为草率偷笑,仅做参考)。


实现代码:
#include <iostream>    #include <Eigen/Dense>#include <cv.h>#include <highgui\highgui.hpp>#include <highgui\highgui_c.h>#include <cv.hpp>#define PI 3.141592654using namespace std;using namespace cv;using Eigen::MatrixXd;//函数声明部分void GetSobel(IplImage*);MatrixXd ReadImg(IplImage*);void Threshholding(IplImage* ImgSrc);void main(){int ThetaDivide = 6;//用来记录角度划分的数目int RhoDivide = 1.8;//用来记录距离划分的数目int maxRho = -999999, minRho = 999999;//用来记录Rho的最大和最小值IplImage* src = cvLoadImage("test.png", 0);//导入图片GetSobel(src);Mat srcLine = imread("test.png", 0);IplImage* Sobel = cvLoadImage("SobelResultImage.jpg", 0);//导入图片Threshholding(Sobel);IplImage* Threshold = cvLoadImage("ThreshholdingResultImg.jpg", 0);//导入图片MatrixXd PixelMatrix(Threshold->height, Threshold->width);//将阈值处理或的图片的每个像素读取到PixelMatrix矩阵中PixelMatrix = ReadImg(Threshold);IplImage* FinalLine;//二值化影像结果CvSize ImgResultSize; ImgResultSize.height = src->height; ImgResultSize.width = src->width;FinalLine = cvCreateImage(ImgResultSize, 8, 1);//此处通道一定要与图像的通道数目对应,否则程序运行将出现崩溃//寻找rho的最大值,最小值int rho;//用来记录某个点距离原点的距离ρfor (int i = 0; i < Threshold->height; i++)for (int j = 0; j < Threshold->width; j++){for (int k = 0; k < ThetaDivide; k++)//按照180个方向计算直线{rho = i * cos(k * PI / ThetaDivide) + j * sin(k * PI / ThetaDivide);if (rho < minRho)minRho = rho;if (rho > maxRho)maxRho = rho + 1;}}MatrixXd PolarLines(((maxRho - minRho) / RhoDivide + 1), ThetaDivide);for (int i = 0; i < (maxRho - minRho) / RhoDivide + 1; i++)for (int j = 0; j < ThetaDivide; j++){PolarLines(i, j) = 0;}for (int i = 0; i < Threshold->height; i++)for (int j = 0; j < Threshold->width; j++){for (int k = 0; k < ThetaDivide; k++)//按照角度划分方向计算直线{if (PixelMatrix(i, j) == 255){//cout << i << " " << j << endl;rho = i * cos(k * PI / ThetaDivide) + j * sin(k * PI / ThetaDivide);int t = PolarLines((rho - minRho) / RhoDivide, k)++;}}}int count = 0;//int maxX = -9999, maxY = -9999, minX = 9999, minY = 9999;for (int t = 0; t < (maxRho - minRho) / RhoDivide; t++)for (int k = 0; k < ThetaDivide; k++){if (PolarLines(t, k) > 80){cout << t << " " << k << " " << PolarLines(t, k) << endl;Point pt1, pt2;float a = sin(k * PI / ThetaDivide);float b = cos(k * PI / ThetaDivide);float x0 = (t * RhoDivide + minRho)*a;float y0 = (t * RhoDivide + minRho)*b;//各个参数的含义参见该文:http://b217dgy.blog.51cto.com/5704306/1318934pt1.x = cvRound(x0 + 1000 * (-b));pt1.y = cvRound(y0 + 1000 * a);pt2.x = cvRound(x0 - 1000 * (-b));pt2.y = cvRound(y0 - 1000 * a);line(srcLine, pt2, pt1, CV_RGB(255, 255, 255), 1);//最后一个参数值决定了画线的粗细count++;}}cout << count << endl;namedWindow("Hough", CV_WINDOW_AUTOSIZE);imshow("Hough", srcLine);waitKey();}void Threshholding(IplImage* ImgSrc){MatrixXd PixelMatrix(ImgSrc->height, ImgSrc->width);PixelMatrix = ReadImg(ImgSrc);//--------------------------------------------------将灰度化图像进行二值化---------------------------------------------------------IplImage* ThreshholdingResultImg;//二值化影像结果CvSize ImgResultSize; ImgResultSize.height = ImgSrc->height; ImgResultSize.width = ImgSrc->width;ThreshholdingResultImg = cvCreateImage(ImgResultSize, 8, 1);//此处通道一定要与图像的通道数目对应,否则程序运行将出现崩溃int ThreshholdValue;//用来设置阈值ThreshholdValue = 100;for (int i = 0; i < ImgSrc->height; i++){for (int j = 0; j < ImgSrc->width; j++){if (PixelMatrix(i, j) > ThreshholdValue){((uchar *)(ThreshholdingResultImg->imageData + ThreshholdingResultImg->widthStep * i))[j] = 255;}else{((uchar *)(ThreshholdingResultImg->imageData + ThreshholdingResultImg->widthStep * i))[j] = 0;}}}cvSaveImage("ThreshholdingResultImg.jpg", ThreshholdingResultImg);//---------------------------------------------------------------------------------------------------------------------------------}void GetSobel(IplImage* ImgSrc){//建立矩阵存储像素值的大小,Matrix矩阵起点下标值为0,即括号中填写的应为0MatrixXd PixelMatrix(ImgSrc->height, ImgSrc->width);PixelMatrix = ReadImg(ImgSrc);//----------------------------------------------------此处计算Sobel梯度-----------------------------------------------------------IplImage* SobelResultImgu;//滤波影像结果CvSize ImgResultSize; ImgResultSize.height = ImgSrc->height; ImgResultSize.width = ImgSrc->width;SobelResultImgu = cvCreateImage(ImgResultSize, 8, 1);//此处通道一定要与图像的通道数目对应,否则程序运行将出现崩溃for (int i = 0; i < ImgSrc->height; i++){for (int j = 0; j < ImgSrc->width; j++){int t = i + 1;int k = j + 1;int t1 = i - 1;int k1 = j - 1;if (t >= ImgSrc->height)t = t - 1;if (k >= ImgSrc->width) k = k - 1;if (t1 < 0) t1 = t1 + 1;if (k1 < 0) k1 = k1 + 1;//对像素进行Robert's梯度计算float Gx = -PixelMatrix(t1, k1) - 2 * PixelMatrix(t1, j) - PixelMatrix(t1, k) +PixelMatrix(t, k1) + 2 * PixelMatrix(t, j) + PixelMatrix(t, k);float Gy = -PixelMatrix(t1, k1) - 2 * PixelMatrix(i, k1) - PixelMatrix(t, k1) +PixelMatrix(t, k) + 2 * PixelMatrix(i, k) + PixelMatrix(t, k);((uchar *)(SobelResultImgu->imageData + SobelResultImgu->widthStep * i))[j] = sqrt(Gx * Gx + Gy * Gy);}}cvSaveImage("SobelResultImage.jpg", SobelResultImgu);//----------------------------------------------------------------------------------------------------------------------------------}MatrixXd ReadImg(IplImage* ImgSrc){MatrixXd PixelMatrix(ImgSrc->height, ImgSrc->width);for (int i = 0; i < ImgSrc->height; i++){for (int j = 0; j < ImgSrc->width; ++j)PixelMatrix(i, j) = ((uchar *)(ImgSrc->imageData + ImgSrc->widthStep * i))[j];}return PixelMatrix;}

实现后的结果:
原图


Sobel计算结果


二值化图像结果




参考资料:
   在写这些代码时,当然是参考了资料的,老师的PPT自然是参考了的(不过作为学生不能上传喽)
   不过有很多好的课程或者报告之类的,我是直接从网上下载,所以应该可以用做学习交流吧,文件放在360云盘里:
   https://yunpan.cn/cRbDan9vAqim4  访问密码 50f4
   另外就是Opencv的配置,参考的是:http://wenku.baidu.com/view/f2feccb9fd0a79563c1e723a.html

0 0
原创粉丝点击