OpenCV之图像处理(二十一) 霍夫变换-直线检测

霍夫直线变换介绍
    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);
    }

效果图

这里写图片描述

猜你喜欢

转载自blog.csdn.net/huanghuangjin/article/details/81165826