霍夫直线变换介绍
Hough Line Transform用来做直线检测
前提条件 – 边缘检测已经完成
平面空间到极坐标空间转换 霍夫空间就是极坐标空间 x=pcosθ,y=psinθ p^2=x^2 + y^2,tanθ=y/x(x≠0) (x y为像素点在图像中的坐标,θ为x y的夹角)
霍夫空间定义 r = x*cosθ + y*sinθ (θ取值为0-360,此θ与上面的θ不一样,x y一致,r与θ的关系是一条曲线)
如果不同的像素点计算出来的 r与θ的曲线,相交于一个点,表示这些像素点都属于同一条直线
此时,相交点的 θ 表示这条直线的角度,再由此 r与θ 反推算到空间坐标
怎么找到相交点? 没有相交的像素点是黑的,相交了的是白色的,即最亮的点表示直线找到了
反推算公式 y = (-cosθ/sinθ)*x + r/sinθ (r与θ是上述的相交点的r与θ,x y为变量,即要 求的像素点在图像中的坐标)
由此公式可证明:若图像存在直线,那么就存在一个r与θ,使得直线上的点x,y不管取何值都能满足上述线性关系
y = (-cosθ/sinθ)*x + r/sinθ 可以看成是 y = k*x+m 因为 (-cosθ/sinθ)与r/sinθ可以产生任何值
对于任意一条直线上的所有点来说
变换到极坐标中,从[0~360]空间,可以得到r的大小
属于同一条直线上点在极坐标空(r, theta)必然在一个点上有最强的信号出现,
根据此反算到平面坐标中就可以得到直线上各点的像素坐标。从而得到直线
标准的霍夫变换 cv::HoughLines从平面坐标转换到霍夫空间,最终输出是 (θ与r) 表示极坐标空间
霍夫变换直线概率 cv::HoughLinesP最终输出是直线的两个点 (x0, y0, x1, y1)
cv::HoughLines(
InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长,一般取值为 1 ,不要大于图像尺寸的一半
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180 ,即表示一度
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线,设10,表示这条直线上至少要有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, // 生成极坐标时候的像素扫描步长,一般取值为 1 ,不要大于图像尺寸的一半
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180 ,即表示一度
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线,设10,表示这条直线上至少要有10个像素点
double minLineLength=0;// 最小直线长度,即不间隔的直线长度
double maxLineGap=0;// 最大间隔,即有超过这个间隔就不算直线了
) // 建议使用这个
代码
#include "../common/common.hpp"
void main(int argc, char** argv)
{
Mat src, canny, dst;
src = imread(getCVImagesPath("images/lines.png"), IMREAD_COLOR);
imshow("src", src);
// extract edge
Canny(src, canny, 100, 200);
imshow("canny", canny);
cvtColor(canny, dst, CV_GRAY2BGR);//将二值图转换为RGB图颜色空间,这里重新创建一张空Mat也行
vector<Vec4f> plines;//保存霍夫变换检测到的直线
HoughLinesP(canny, plines, 1, CV_PI / 180, 10, 0, 10);//提取边缘时,会造成有些点不连续,所以maxLineGap设大点
printf("%d\n", plines.size());// maxLineGap 为0时,99 maxLineGap为 10时,13
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("plines", dst);
waitKey(0);
}
效果图