opencv-Hough霍夫变换

Hough变换是图像处理中从图像中识别几何形状的基本方法之一 

原理看视频:

https://www.bilibili.com/video/BV16i4y1R7kf?spm_id_from=333.999.0.0  

霍夫直线检测

  1. 标准的霍夫变换 cv::HoughLines从平面坐标转换到霍夫空间,最终输出是  表示极坐标空间
  2. 霍夫变换直线概率 cv::HoughLinesP最终输出是直线的两个点

霍夫线变换是一种用来寻找直线的方法. 在使用霍夫线变换之前, 首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像

OpenCV支持三种不同的霍夫线变换,它们分别是:
标准霍夫变换(Standard Hough Transform,SHT),
多尺度霍夫变换(Multi-Scale Hough Transform,MSHT),
累计概率霍夫变换(Progressive Probabilistic Hough Transform ,PPHT)

在OpenCV中,我们可以用HoughLines函数来调用标准霍夫变换SHT和多尺度霍夫变换MSHT。
而HoughLinesP函数用于调用累计概率霍夫变换PPHT。累计概率霍夫变换执行效率很高,所有相比于HoughLines函数,我们更倾向于使用HoughLinesP函数 

HoughLinesP寻找直线

10.jpg

 

 

#include<opencv2/opencv.hpp>
#include<iostream>

int main(int argc, char** argv) {

    cv::Mat src = cv::imread("D:/bb/tu/10.jpg");
    if (!src.data)
    {
        printf("图像读取失败...\n");
        return -1;
    }
    cv::imshow("src", src);
    cv::Mat canny, dst;
    Canny(src, canny, 50, 255);  //获取边缘
    imshow("canny", canny);
    cvtColor(canny, dst, cv::COLOR_GRAY2BGR);//将二值图转换为RGB图颜色空间
    std::vector<cv::Vec4f> plines;//保存霍夫变换检测到的直线
    HoughLinesP(canny, plines, 1, CV_PI / 180, 10, 0, 10);//霍夫变换---寻找直线
    //提取边缘时,会造成有些点不连续,所以maxLineGap设大
    /*
    参数1:InputArray src 输入图像,必须8-bit的灰度边缘图像
    参数2:输出的极坐标来表示直线,经过调用HoughLinesP函数后后存储了检测到的线条的输出矢量,
            每一条线由具有四个元素的矢量(x_1,y_1, x_2, y_2) 表示,其中,(x_1, y_1)和(x_2, y_2) 是
            每个检测到的线段的起点和结束点。
    参数3:double rho 生成极坐标时的像素扫描步长,一般取值为1
    参数4:double theta 生成极坐标时的角度步长,一般取值CV_PI/180,即表示一度
    参数5:int threshold 阈值,只有获得足够交点的极坐标点才被看成是直线
    参数6:double minLineLength=0  最小直线长度,有默认值0,表示最低线段的长度,比这个
        设定参数短的线段就不能被显现出来
    参数7:double maxLineGap=0 最大间隔,有默认值0,允许将同一行点与点之间连接起来的最大的距离
        【间隔小于等于这个数,就认为是连续直线】

    */
    std::cerr << plines.size() << std::endl;//检测到的直线数量
    cv::Scalar color = cv::Scalar(0, 0, 255);//设置颜色
    for (size_t i = 0; i < plines.size(); i++) {
        cv::Vec4f hline = plines[i];//提取直线坐标
        line(dst, cv::Point(hline[0], hline[1]), cv::Point(hline[2], hline[3]), color, 1, cv::LINE_AA);//绘制直线

    }
    cv::imshow("检测到的直线", dst);






    cv::waitKey(0);
    return 0;
}

 

HoughLines寻找直线

#include<opencv2/opencv.hpp>
#include<iostream>

int main(int argc, char** argv) {

    cv::Mat src = cv::imread("D:/bb/tu/10.jpg");
    if (!src.data)
    {
        printf("图像读取失败...\n");
        return -1;
    }
    cv::imshow("src", src);
    cv::Mat canny, dst;
    Canny(src, canny, 50, 255);  //获取边缘
    imshow("canny", canny);
    cvtColor(canny, dst, cv::COLOR_GRAY2BGR);//将二值图转换为RGB图颜色空间
    std::vector<cv::Vec4f> plines;//保存霍夫变换检测到的直线
    HoughLines(canny, plines, 1, CV_PI / 180, 10, 0, 0);//霍夫变换---寻找直线

    /*
    参数1:InputArray src 输入图像,必须8-bit的灰度边缘图像
    参数2:OutputArray lines 输出的极坐标来表示直线,经过调用HoughLines函数后储存了霍
        夫线变换检测到线条的输出矢量。每一条线由具有两个元素的矢量(ρ,θ)表示,其
        中,ρ是离坐标原点((0,0)(也就是图像的左上角)的距离。 θ是弧度线条旋转角度
        (0~ 垂直线,π/2~水平线)。
    参数3:double rho 生成极坐标时的像素扫描步长,一般取值为1,不要大于图像尺寸的一半
    参数4:double theta 生成极坐标时的角度步长,一般取值CV_PI/180,即表示一度
    参数5:int threshold 阈值,只有获得足够交点的极坐标点才被看成是直线,大于阈值的线段
        才可以被确认为直线
    参数6:double srn=0 是否应用多尺度的霍夫变换;设置0表示经典霍夫变换,
        多尺度表示的是使用图像金字塔,即多尺度图上进行霍夫变换
    参数7:stn,默认值为 0。也是多尺度霍夫线变换才会用到的参数。对于多尺度霍夫线变换,
        平面  -  中 θ 轴的单位长度 = theta / stn。如果 srn、stn 同时为 0,就表示使用
        经典霍夫变换,否则两个参数都应该为正数

    */
    std::cerr << plines.size() << std::endl;//检测到的直线数量
    cv::Scalar color = cv::Scalar(0, 0, 255);//设置颜色
    for (size_t i = 0; i < plines.size(); i++) {
        cv::Vec4f hline = plines[i];//提取直线坐标
        line(dst, cv::Point(hline[0], hline[1]), cv::Point(hline[2], hline[3]), color, 1, cv::LINE_AA);//绘制直线

    }
    cv::imshow("检测到的直线", dst);






    cv::waitKey(0);
    return 0;
}

 

寻找圆 

2.jpg

 

  

#include<opencv2/opencv.hpp>]
#include<iostream>

int main(int argc, char** argv) {

    cv::Mat src = cv::imread("D:/bb/tu/2.jpg");
    if (!src.data)
    {
        printf("图像读取失败...\n");
        return -1;
    }
    cv::imshow("src", src);
    cv::Mat gray_src, dst;
    medianBlur(src, dst, 5);//因为霍夫圆检测对噪声比较敏感,故须先做中值滤波
    cvtColor(dst, gray_src, cv::COLOR_BGR2GRAY);
    

    imshow("gray", gray_src);
    std::vector<cv::Vec3f> circles;//用Vec3f:一个圆需要三个数:圆心x y 半径r
    HoughCircles(gray_src, circles, cv::HOUGH_GRADIENT, 1, 10, 150, 50, 50, 100);//寻找圆
    /*
    参数1:输入图像 ,必须是8位的单通道灰度图像
    参数2:输出结果,发现的圆信息    
    参数3:目前opencv只有霍夫梯度法一种方法可用,该参数填HOUGH_GRADIENT即可
    参数4:double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数
        允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例如,如
        果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度
    参数5:为霍夫变换检测到的圆的圆心之间的最小距离
    参数6:它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,
        它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半
    参数7:也是第三个参数method设置的检测方法的对应的参数,对当前唯一的方法霍夫梯度法HOUGH_GRADIENT,
        它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能
        通过检测的圆就更加接近完美的圆形了
    参数8:表示圆半径的最小值
    参数9:表示圆半径的最大值
    */

    std::cerr << circles.size() << std::endl;//找到的圆的数量

    //画出圆和圆心
    for (size_t i = 0; i < circles.size(); i++)
    {
        cv::Vec3f cc = circles[i];
        std::cout << "=" << std::endl << cc << std::endl;//查看图像中圆的信息
        circle(src, cv::Point(cc[0], cc[1]), cc[2], cv::Scalar(0, 0, 255), 2, cv::LINE_AA);//画圆
        circle(src, cv::Point(cc[0], cc[1]), 2, cv::Scalar(255, 0, 0), 2, cv::LINE_AA);//标记出圆心(这里把圆的半径设为2,并把标记线的粗细设为2,刚好画出一个实心的圆心)
    }
    imshow("result", src);



    cv::waitKey(0);
    return 0;
}

 

 

 

 

 

 

 

 

posted @ 2021-12-27 09:43  天子骄龙  阅读(233)  评论(0编辑  收藏  举报