伤心客 发表于 2025-4-15 22:48:45

24.OpenCV中的霍夫直线检测

OpenCV中的霍夫直线检测

霍夫直线检测是一种基于参数变换的全局特性提取方法,它能在边沿图像中有效检测出直线,具有鲁棒性强和对噪声干扰容忍度高的特点。本文将从原理、算法实现和 OpenCV 应用三个角度对霍夫直线检测进行详细的阐述,并给出相应的 C++ 代码示例。
1. 霍夫直线检测原理

1.1 根本思想

霍夫直线检测的焦点思想是将图像空间中的每个边沿点转换到一个参数空间中,在这个参数空间中,每一条直线都可以用一组参数来唯一确定。常用的直线参数化方法采用极坐标表现,使得直线方程可以写成:
                                       ρ                            =                            x                            c                            o                            s                            θ                            +                            y                            s                            i                            n                            θ                                  ρ=xcos\theta+ysin\theta                     ρ=xcosθ+ysinθ
其中:


[*]                                        ρ                                  ρ                     ρ 表现直线到原点的垂直距离
[*]                                        θ                                  θ                     θ 表现垂直于直线的方向与 x 轴的夹角
参考图
https://i-blog.csdnimg.cn/direct/bff3e8ac16a84bd2b6b92fe0aa68474f.png#pic_center
每个图像中的边沿点(x,y)根据上述方程,会在(ρ,θ)参数空间中对应一条曲线。若图像中存在直线,那么这条直线上的所有点在参数空间中都“交汇”于一个特定的(ρ,θ)点。
1.2 参数空间与累加器

OpenCV为了统计不同边沿点对直线候选参数的支持度,算法构造了一个 累加器:


[*]构建累加器:将参数 ρρ 和 θθ 离散化为网格地域,每个网格点存储一个计数值。
[*]投票过程:对每个边沿点,按照不同 θθ 的取值计算对应的 ρρ 值,然后在累加器中相应位置加票。
[*]峰值检测:累加器中票数较高的点,即代表图像中大概存在直线,因为直线上的所有边沿点对该直线参数均“投票”。
当累加器中某一单位格的票数大于预设的阈值时,便可以认为该参数组合 (ρ,θ)(ρ,θ) 对应的直线在图像中存在。
1.3 标准与概率霍夫变换

OpenCV 提供两种常用的直线检测方法:


[*] 标准霍夫直线变换(HoughLines)
直接返回图中所有满足阈值条件的直线参数 (ρ,θ),但绘制直线时须要借助图像尺寸进行延展。
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);


[*]image:输入的二值图像(如 Canny 边沿图)。
[*]lines:输出的极坐标情势直线,Vec2f(rho, theta)。
[*]rho:距离分辨率,通常为 1 像素。
[*]theta:角度分辨率,通常为 CV_PI/180(1度)。
[*]threshold:累加器阈值,越高越严格。
[*]srn、stn:用于多尺度霍夫变换,通常为 0。
[*]min_theta 和 max_theta:可选参数,用于限制检测的角度范围。

[*] 概率霍夫直线变换(HoughLinesP)
只对部分边沿点采样,返回检测到的直线段,并同时输出每一段的起止点。该方法在大多数实际应用中速率更快,也更容易控制直线段的长度和间断情况。
对比:
void HoughLinesP(InputArray image,
               OutputArray lines,
               double rho,
               double theta,
               int threshold,
               double minLineLength = 0,
               double maxLineGap = 0);



[*]lines:输出为线段端点 (x1, y1, x2, y2) 的向量。
[*]rho:距离分辨率
[*]theta:角度分辨率
[*]minLineLength:能被认为是直线的最小长度(像素单位)。
[*]maxLineGap:同一条直线中允许的最大间断(像素单位)。

[*] 对比表:
   特性HoughLinesHoughLinesP方法范例标准霍夫变换(Standard Hough Transform)概率霍夫变换(Probabilistic Hough Transform)返回结果极坐标参数 (rho, theta)直线段的起点和终点 (x1, y1, x2, y2)扫描方式所有边沿点都参与投票从边沿点中随机抽样进行投票结果数量通常较多,须要进一步处理惩罚通常较少,结果直观性能较慢,实用于完整直线检测较快,实用于实际可见线段检测应用场景精确拟合整条直线(如无限延长线)实际图像中可见的线段,如车道线、轮廓边等
2. 算法使用步骤

下面扼要总结霍夫直线检测的主要步骤:

[*]边沿检测:通常先将彩色图像转换为灰度图,然后采用 Canny 算法等方法提取边沿,形成二值图像。
[*]参数空间映射:对边沿图中的每个像素点,遍历 θ 的离散取值,计算对应的 ρ,在累加器中累加计数。
[*]探求峰值:在累加器中找出凌驾阈值的单位格,这些位置的 (ρ,θ) 就是直线候选参数。
[*]直线重构:使用直线参数 (ρ,θ) 将直线在原图中绘制出来。
[*](可选)后处理惩罚:使用一些多少束缚或者连接算法合并那些相近的直线候选,获得更连贯的直线段。
3. OpenCV C++ 实战示例

下面给出一个使用标准霍夫直线变换(HoughLines)的 C++ 示例代码。代码通过 Canny 边沿检测获得二值图像,并对霍夫直线进行参数求解,末了在原图上绘制检测到的直线。
3.1:HoughLines参考代码

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

using namespace cv;
using namespace std;

int main()
{
    // 读取输入图像
    Mat src = imread("E:/image/ela_modified.jpg");
    if (src.empty())
    {
      cout << "无法加载图像!" << endl;
      return -1;
    }

    // 转换为灰度图并进行边缘检测
    Mat gray, edges;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    Canny(gray, edges, 50, 150, 3);

    // 使用标准霍夫直线变换进行直线检测
    vector<Vec2f> lines; // 每行元素为 (rho, theta)
    HoughLines(edges, lines, 1, CV_PI / 180, 150); // 阈值150可根据图像情况调整

    // 拷贝原图用于显示检测结果
    Mat result = src.clone();
    // 绘制检测到的直线
    for (size_t i = 0; i < lines.size(); i++)
    {
      float rho = lines, theta = lines;
      // 利用极坐标公式得到直线上的两个点,便于绘制延长直线
      double a = cos(theta), b = sin(theta);
      double x0 = a * rho, y0 = b * rho;
      Point pt1(cvRound(x0 + 1000 * (-b)),
            cvRound(y0 + 1000 * (a)));
      Point pt2(cvRound(x0 - 1000 * (-b)),
            cvRound(y0 - 1000 * (a)));
      line(result, pt1, pt2, Scalar(0, 0, 255), 2);
    }
    imshow("原图Cany", edges);
    imshow("霍夫直线检测", result);
    waitKey(0);

    return 0;
}
直线绘制:使用直线参数 ρ 和 θ 计算延长直线上任意两个远距离的点,这样能够包管直线能凌驾整个图像进行显示。
https://i-blog.csdnimg.cn/direct/85b5d387dd5b4c88be935d19225ed859.png#pic_center
3.2 HoughLinesP参考代码

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

using namespace cv;
using namespace std;

int main()
{
    // 读取输入图像
    Mat src = imread("E:/image/ela_modified.jpg");
    if (src.empty())
    {
      cout << "无法加载图像!" << endl;
      return -1;
    }

    // 转换为灰度图并进行边缘检测
    Mat gray, edges;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    Canny(gray, edges, 50, 150, 3);

    // 使用标准霍夫直线变换进行直线检测
    vector<Vec4i> linesP;
    HoughLinesP(edges, linesP, 1, CV_PI / 180, 150, 50, 30);
    // 拷贝原图用于显示检测结果
    Mat result = src.clone();
    // 绘制检测到的直线
    for (size_t i = 0; i < linesP.size(); i++) {
      Vec4i l = linesP;
      line(result, Point(l, l), Point(l, l), Scalar(0, 255, 0), 2);
    }
    imshow("原图Cany", edges);
    imshow("霍夫直线检测", result);
    waitKey(0);

    return 0;
}
https://i-blog.csdnimg.cn/direct/6e6798c798a248eb81f3c6d99cb44a3d.png#pic_center
4.总结

霍夫直线检测通过将图像中的边沿点映射到参数空间,并在累加器中统计支持度,从而实现对直线的检测。


[*]长处:对噪声具有较高的鲁棒性,能够全局搜刮直线信息。
[*]缺点:参数设置比力敏感,且标准方法只返回直线参数,须要后续转换成图像中的直线段。
借助 OpenCV,我们可以快速实现这一算法,对直线检测、门路识别、车道线提取等实际应用都有着广泛的应用前景。
在实际应用中,霍夫直线检测大概会受到以下因素的影响:


[*]边沿检测质量:如果边沿检测结果噪声较多,累加器中大概会出现大量虚假峰值。因此,预处理惩罚(如高斯模糊)和 Canny 参数的调治至关重要。
[*]参数阈值:阈值过低会导致检测到太多直线,过高则大概漏检。须要根据图像特点和应用需求调整。
[*]直线一连性:标准霍夫变换只返回直线参数,而不包含直线段的详细端点信息。若需求侧重于直线段检测,可以考虑使用概率霍夫直线变换(HoughLinesP)。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 24.OpenCV中的霍夫直线检测