/*
*霍夫变换-直线
霍夫变换-直线检测
霍夫变换是图像处理当中很经典的算法,通过霍夫变换可以实现传统的几何规则的几何图像的一个检测,从直线到圆扩展到其他的一些不规则的或者稍
微有点规则的几何形状检测都可以通过霍夫变换来实现,最经典的就是霍夫变换直线检测和圆检测,在opencv当中提供了API
*霍夫直线变换介绍
Hough Line Transform用来做直线检测
前提条件 – 边缘检测已经完成 Canny,输入的是一个8位的图像,输入可以是单通道和多通道的,输出是单通道的一个8位的图像,灰度图像,通过函数也可
以转换为二值图像
平面空间到极坐标空间转换 霍夫空间本质上来说就是一个极坐标空间,平面坐标就是图像的空间域
对于任意一条直线上的所有点来说
变换到极坐标中,从[0~360]空间,可以得到r的大小
霍夫变换-直线检测的原理:
通过把图像上的像素点全部变换到极坐标空间然后形成一条一条的曲线,比如有200个像素点就形成200条曲线,200条曲线中如果都相交到一个点上,这一个点就表示我们
这一个图像上面所有的这些像素点都属于同一条曲线,相交在这一点上有个最强的信号
而对应的theta和r值呢,thera就表示这个直线的角度,这就说明在平面上面的直线在极坐标空间我们给它找到了,找到了之后,拿着这个点的r跟thera我们给它重新反算到平
面坐标空间去,用公式输以不同的x得到一个y,theta跟r不变的情况下输入的x,y是在平面坐标上面的点,如果超过我们平面空间上面的点的坐标我们会舍去,如果在的,我们就
把这个像素点标记为红色或者标记为固定的颜色,最终得到的所有的在平面空间上的这些像素点形成的一个直线就是通过霍夫变换找到的直线
怎么去找曲线相交的那一点?
我们对给出的r和theta对应的每一个坐标只要曲线经过的地方我们都加一,经过最多的那一点加的1肯定最多,如果我们把它变成一张图像的话,这些点经过一次应该是很暗的,
没经过的都是黑的,相交的应该是很白的,这曲线图就是霍夫变换在霍夫空间的一个表示,它最亮的点就表示直线找到了
属于同一条直线上点在极坐标空(r, theta)必然在一个点上有最强的信号出现(就是相交的那个点),根据此反算到平面坐标中就可以得到直线上各点的像素坐标。从而得到直线
从平面坐标变换到霍夫空间(极坐标)
*相关API学习
标准的霍夫变换 cv::HoughLines从平面坐标转换到霍夫空间,最终输出是(θ, rθ)极坐标空间。找到直线的θ 和 r 值
霍夫变换直线概率 cv::HoughLinesP反算回去,最终输出是直线的两个点(x0, y0, x1, y1)的坐标。
cv::HoughLines(
InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长,这个一般取1,因为这个一般表征极坐标r的最大值,一幅图像的中心位置即宽度高度的1/2然后高度的平方和宽度的平方相加然
//后开平方就的到我们最大值,绝对不能超过最大值,步长每一次前进一步
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180,一般取值是0-180度之间,每次一度
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线,可以把它变成10,获得10个像素点,最起码这个上面有10个像素长才会被看成直线,如果你的直线足够长,
//你可以换成100,10个像素长差不多是个小线段
double srn=0;// 是否应用多尺度的霍夫变换(图像金字塔),如果不是设置0表示经典霍夫变换
double stn=0;//是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
double min_theta=0; // 表示角度扫描范围 0 ~180之间, 默认即可
double max_theta=CV_PI
) // 一般情况是有经验的开发者使用,需要自己反变换到平面空间
cv::HoughLinesP(
InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线
double minLineLength=0;// 最小直线长度,即最小多长实际上才会被认为是直线,比如输入5,小于5个像素的线段都被去掉了
double maxLineGap=0;// 最大间隔,两个直线中间如果隔了一个像素,你认不认为是一条直线
)
*/
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void Canny_Demo(int, void*);
int main()
{
Mat src, src_gray, dst;
src = imread("D:/A_Graduation/Learning/opencv/learningOpencv/1.png");
imshow("src", src);
// extract edge边缘检测 低阈值 高阈值 //先模糊,不做也没关系把,Canny本身带有模糊
Canny(src, src_gray, 150, 200); //输入的图像只要是8位的就可以了,每个通道占的位数是8位的,CV_8UC
//如果每个通道占32位的没法做,没有要求是灰度图像,
//变成灰度图像
cvtColor(src_gray, dst, CV_GRAY2BGR); //灰度变成彩色的图像
imshow("edge image", src_gray);
vector<Vec2f> lines;
//------api【HoughLines】调用------
HoughLines(src_gray, lines, 1, CV_PI / 180, 150, 0, 0);
for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0]; // 极坐标中的r长度
float theta = lines[i][1]; // 极坐标中的角度
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
// 转换为平面坐标的四个点
pt1.x = cvRound(x0 + 1000 * (-b));
pt1.y = cvRound(y0 + 1000 * (a));
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * (a));
line(dst, pt1, pt2, Scalar(0, 0, 255), 1, CV_AA);
}
// 浮点数
// vector<Vec4f> plines; //要把霍夫变换得出来的那个结果直线放到plines这个数组里面去
// HoughLinesP(src_gray, plines,1, CV_PI / 180.0, 10, 0, 10); //检测到直线了要把直线画到上面去
// Scalar color = Scalar(0, 0, 255); //给直线来个颜色
// for (size_t i = 0; i < plines.size(); i++) {
// Vec4f hline = plines[i];
// line(dst, Point(hline[0], hline[1]), Point(hline[2], hline[3]), color, 3, LINE_AA); //绘制线
// }
imshow("output", dst);
waitKey(0);
return 0;
}