霍夫变换检测直线

一、概念

Hough直线检测的基本原理在于利用点与线的对偶性,即图像空间中的直线与参数空间中的点是一一对应的,因此将图像空间中的直线检测问题转换到参数空间中对点的检测问题,通过在参数空间里寻找峰值来完成直线检测任务。

注意:

  1. 参数空间是极坐标系,不是k和b组成的笛卡尔坐标系,目的是为了兼容垂直于x轴的直线;
  2. 参数空间不是连续的,而是被离散量化为一个个等大小网格单元,首先直线的方向θ离散化为有限个等间距的离散值,参数ρ也就对应离散化为有限个值。

二、实施步骤

2.1 Hough直线检测步骤

  1. 离散化θ;
  2. 依据图像坐标中的x,y以及θ,求ρ;
  3. 统计离线参数空间中(ρ,θ)出现的次数,最大的即为待检测的直线。

2.1 使用Hough直线检测算法的一般步骤

  1. 彩色图像->灰度图
  2. 去噪(高斯核)
  3. 边缘提取(梯度算子、拉普拉斯算子、canny、sobel)
  4. Hough直线检测

2.3 Hough直线检测的优缺点

优点:抗干扰能力强,对图像中直线的殘缺部分、噪声以及其它共存的非直线结构不敏感,能容忍特征边界描述中的间隙,并且相对不受图像噪声的影响。

缺点:时间复杂度和空间复杂度都很高,并且在检测过程中只能确定直线方向,丢失了线段的长度信息,且由于霍夫检测过程中进行了离散化,因此检测精度受参数离散间隔制约。

三、OpenCV中函数接口介绍

3.1 标准Hough直线检测、多尺度Hough直线检测

CV_EXPORTS_W void HoughLines( InputArray image, OutputArray lines, 
  double rho, double theta, int threshold, 
  double srn = 0, double stn = 0, 
  double min_theta = 0, double max_theta = CV_PI );
  
  //InputArray image:输入图像,必须是8位单通道图像。 
  //OutputArray lines:检测到的线条参数集合。 
  //double rho:以像素为单位的距离步长。 
  //double theta:以弧度为单位的角度步长。 
  //int threshold:累加计数值的阈值参数,当参数空间某个交点的累加计数的值超过该阈值,则认为该交点对应了图像空间的一条直线。 
  //double srn:默认值为0,用于在多尺度霍夫变换中作为参数rho的除数,rho=rho/srn。 
  //double stn:默认值为0,用于在多尺度霍夫变换中作为参数theta的除数,theta=theta/stn。
  //如果srn和stn同时为0,就表示HoughLines函数执行标准霍夫变换,否则就是执行多尺度霍夫变换。

说明:
输出的内容是一个 std::vector<cv::Vec2f> 类型的向量,每个cv::Vec2f 表示一条直线,包含两个浮点数元素:

  1. ρ:点到坐标原点的距离(以像素为单位)。
  2. θ:从x轴到垂线与直线交点的角度(以弧度为单位)。

如果想要在图像空间中进行展示,需进行转换,代码如下:

    // 在原图上绘制检测到的直线
    for (size_t i = 0; i < lines.size(); i++) {
        float r = lines[i][0];
        float theta = lines[i][1];
        double cosTheta = cos(theta);
        double sinTheta = sin(theta);
        double x0 = cosTheta * r;
        double y0 = sinTheta * r;
        cv::Point pt1, pt2;
        pt1.x = cvRound(x0 + 1000 * (-sinTheta)); //1000是任意选定的值
        pt1.y = cvRound(y0 + 1000 * (cosTheta));
        pt2.x = cvRound(x0 - 1000 * (-sinTheta));
        pt2.y = cvRound(y0 - 1000 * (cosTheta));
        cv::line(src, pt1, pt2, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
    }

3.2 渐进概率式霍夫变换

CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines, 
  double rho, double theta, int threshold, 
  double minLineLength = 0, double maxLineGap = 0 ); 
  
  //InputArray image:输入图像,必须是8位单通道图像。 
  //OutputArray lines:检测到的线条参数集合。 
  //double rho:直线搜索时的距离步长,以像素为单位。 
  //double theta:直线搜索时的角度步长,以弧度为单位。 
  //int threshold:累加计数值的阈值参数,当参数空间某个交点的累加计数的值超过该阈值,则认为该交点对应了图像空间的一条直线。 
  //double minLineLength:默认值为0,表示最小线段长度阈值(像素)。 
  //double maxLineGap:线段上最近两点之间的阈值.默认值为0,表示直线断裂的最大间隔距离阈值。即如果有两条线段是在一条直线上,但它们之间有间隙,那么如果这个间隔距离小于该值,则被认为是一条线段,否则认为是两条线段。 

说明:
输出的内容是一个 std::vector<cv::Vec4f> 类型的向量,每个cv::Vec4f是一条直线,由具有四个元素的矢量(x1, y1, x2, y2)表示,其中(x1, y1)表示线段的起点,(x2, y2)表示线段的终点。

参考文章

posted @ 2024-06-11 14:18  珠峰上吹泡泡  阅读(29)  评论(0编辑  收藏  举报