OpenCV 4.12.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)\)相交,這些座標是\((x_{0}, y_{0})\)、\((x_{1}, y_{1})\)和\((x_{2}, y_{2})\)所在的直線的引數(\(\theta, r\))。

  1. 上述所有內容意味著什麼?這意味著通常,可以透過查詢曲線之間的交點數量來*檢測*一條直線。相交的曲線越多,表示該交點所代表的直線包含的點越多。通常,我們可以定義一個*閾值*,即*檢測*一條直線所需的最小交點數量。
  2. 這就是霍夫線變換的作用。它會跟蹤影像中每個點的曲線之間的交點。如果交點數量超過某個*閾值*,則將其宣告為一條直線,其引數為交點的\((\theta, r_{\theta})\)。

標準霍夫線變換和機率霍夫線變換

OpenCV實現了三種霍夫線變換

a. 標準霍夫變換

  • 它與我們上一節中解釋的原理基本一致。它返回一個由\(({\theta}, r_{\theta})\)對組成的向量。
  • 在OpenCV中,它由函式HoughLines()實現。

b. 機率霍夫線變換

  • 霍夫線變換的一種更高效的實現。它輸出檢測到的線的端點\((x_{0}, y_{0}, x_{1}, y_{1})\)
  • 在OpenCV中,它由函式HoughLinesP()實現。

c. 加權霍夫變換

  • 在標準霍夫變換中,它使用邊緣強度而非二進位制0或1值。
  • 在OpenCV中,它由函式HoughLines()實現,引數use_edgeval=true。
  • 請參閱samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp中的示例。

該程式做什麼?

  • 載入影像
  • 應用*標準霍夫線變換*和*機率霍夫線變換*。
  • 在三個視窗中顯示原始影像和檢測到的線條。

程式碼

解釋

載入影像

使用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: 同一條線上兩個點之間的最大允許間隙。

然後透過繪製直線來顯示結果。

顯示原始影像和檢測到的線條

等待使用者退出程式

結果

注意
以下結果是使用我們在*程式碼*部分中提到的略微更高階的版本獲得的。它仍然實現了與上述相同的功能,只是為閾值添加了軌跡條。

使用例如數獨影像作為輸入。透過使用標準霍夫線變換,我們得到以下結果:

透過使用機率霍夫線變換:

你可能會觀察到,當你改變*閾值*時,檢測到的線條數量會發生變化。解釋很明顯:如果你設定更高的閾值,將檢測到更少的線條(因為你需要更多的點才能宣告檢測到一條線)。