OpenCV  4.10.0
开源计算机视觉
加载中...
搜索中...
无匹配项
霍夫线变换

前一个教程: Canny 边缘检测器
下一个教程: 霍夫圆变换

原作者Ana Huamán
兼容性OpenCV >= 3.0

目标

在本教程中,你将学习如何

  • 使用 OpenCV 函数 HoughLines()HoughLinesP() 检测图像中的线条。

原理

注意
以下说明属于 Bradski 和 Kaehler 所著的《学习 OpenCV》一书。

霍夫线变换

  1. 霍夫线变换是一种用于检测直线的变换。
  2. 要应用变换,首先需要边缘检测预处理。

它是如何工作的?

  1. 如你所知,图像空间中的一条直线可以用两个变量表示。例如
    1. 笛卡尔坐标系:参数:\((m,b)\)。
    2. 极坐标系:参数:\((r,\theta)\)

对于霍夫变换,我们将在极坐标系中表示直线。因此,线方程可以写成

\[y = \left ( -\dfrac{\cos \theta}{\sin \theta} \right ) x + \left ( \dfrac{r}{\sin \theta} \right )\]

整理项:\(r = x \cos \theta + y \sin \theta\)

  1. 通常对于每个点 \((x_{0}, y_{0})\),我们可以定义经过该点的直线簇为

    \[r_{\theta} = x_{0} \cdot \cos \theta + y_{0} \cdot \sin \theta\]

    这意味着每对\((r_{\theta},\theta)\)表示一条经过\((x_{0}, y_{0})\)的直线。

  2. 如果对于给定的\((x_{0}, y_{0})\)我们绘制经过该点的直线簇,我们将得到一个正弦波。例如,对于\(x_{0} = 8\)和\(y_{0} = 6\),我们得到以下曲线图(在\(\theta\) - \(r\)平面中)

我们只考虑\(r > 0\)和\(0< \theta < 2 \pi\)的点。

  1. 我们可以对图像中所有点的上操作执行相同的操作。如果两个不同点的曲线在平面 \(\theta\) - \(r\) 中相交,则表示这两个点属于同一条线。例如,接着上面的示例,并绘制另两个点的曲线:\(x_{1} = 4\),\(y_{1} = 9\) 及 \(x_{2} = 12\),\(y_{2} = 3\),得到

三个曲线在一个点 \((0.925, 9.6)\) 相交,这些坐标是参数 ( \(\theta, r\)),或者是 \((x_{0}, y_{0})\),\((x_{1}, y_{1})\) 及 \((x_{2}, y_{2})\) 所在的线的参数。

  1. 上面提到内容有什么含义?总体而言,可以通过找出曲线之间的相交点的数量来“检测”线。相交曲线越多,表示该相交点所代表的线具有更多点。通常,我们可以定义用于“检测”线的相交点的最小数量的“阈值”。
  2. 这就是霍夫线变换所执行的操作。它会跟踪图像中每个点的曲线之间的相交点。如果相交点的数量超过某个“阈值”,则会将相交点 \((\theta, r_{\theta})\) 的参数声明为线。

标准霍夫线变换和概率霍夫线变换

OpenCV 实现了两种霍夫线变换

a. 标准霍夫变换

  • 它包含我们在上一部分中详细解释的内容。它为您返回一个双元组向量 \((\theta, r_{\theta})\)
  • 在 OpenCV 中,它使用函数 HoughLines() 实现

b. 概率霍夫线变换

  • 霍夫线变换的一种更有效实现。它会输出已检测线的极值 \((x_{0}, y_{0}, x_{1}, y_{1})\)
  • 在 OpenCV 中,它使用函数 HoughLinesP() 实现

该程序的功能

  • 加载图像
  • 应用“标准霍夫线变换”和“概率霍夫线变换”。
  • 在三个窗口中显示原图像和检测到的线。

代码

解释

加载图像

使用 Canny 检测器检测图像边缘

现在我们将应用霍夫线变换。我们将讲解如何使用 OpenCV 提供的这两个函数。

标准霍夫线变换

首先,应用变换

  • 使用以下参数
    • dst:边缘检测器的输出。它应该是灰度图像(事实上是二进制图像)
    • lines:存储检测线段的 \((r,\theta)\) 参数的向量
    • rho :以像素为单位的 \((r)\) 参数分辨率。我们使用 **1** 像素。
    • theta:以弧度为单位的 \(\theta\) 参数分辨率。我们使用 **1 度** (CV_PI/180)
    • threshold:"*检测*" 一条线的最小交点数
    • srnstn:默认参数为零。有关更多详细信息,请参阅 OpenCV 参考。

然后,通过绘制线段显示结果。

概率霍夫线变换

首先,应用变换

  • 使用参数
    • dst:边缘检测器的输出。它应该是灰度图像(事实上是二进制图像)
    • lines:存储检测线段的 \((x_{start}, y_{start}, x_{end}, y_{end})\) 参数的向量
    • rho :以像素为单位的 \((r)\) 参数分辨率。我们使用 **1** 像素。
    • theta:以弧度为单位的 \(\theta\) 参数分辨率。我们使用 **1 度** (CV_PI/180)
    • threshold:"*检测*" 一条线的最小交点数
    • minLineLength:可以构成一条线的最小点数。点数少于此数量的线段将被忽略。
    • maxLineGap:同一线段中两个点之间的最大间隙。

然后,通过绘制线段显示结果。

显示原图和检测到的线段

等待用户退出程序

结果

注意
以下结果采用我们在代码章节中提及的稍加优化的版本得到。它仍然实现了与上述相同的功能,只是添加了阈值的滑动条。

使用如下输入图像 数独图像。通过使用标准霍夫线变换,我们得到以下结果:

通过使用概率霍夫线变换,我们得到以下结果:

您可能会观察到,当您更改阈值时,检测到的线段数量会有所变化。解释是显而易见的:如果您设定更高的阈值,那么检测到的线段会更少(因为您将需要更多的点来宣告检测到一条线段)。