1. 程式人生 > >python opencv入門 Hough直線變換(27)

python opencv入門 Hough直線變換(27)

內容來自OpenCV-Python Tutorials 自己翻譯整理

目標:
理解概念
在圖片中檢測直線
學習函式cv2.HoughLines(),cv2.HoughLinesP()

原理:
霍夫變換在檢測各種形狀的技術中十分流行,如果能用數學表示式寫出圖形的公式,就可以使用霍夫變換來進行檢測。

待檢測的物體可以存在一些破壞和變型。

直線的表示式為y=mx+c或者用極座標表示為,ρ=xcosθ+ysinθ

ρ表示從原點到直線的垂直距離,θ表示直線的垂線與橫軸順時針方向的夾角。
這裡寫圖片描述

直線在原點下方,ρ是正值,角度小於180。直線在原點上方經過,角度不是大於180度,而是小於180度,但是ρ值取負值。垂直的時候角度為0,水平的時候角度為90度。

霍夫變換是如何實現的?
每條直線都可以用(ρ,θ)表示。
首先建立一個2D陣列或者累加器(用來儲存兩個引數),初始化陣列為0。行表示ρ,列表示θ。陣列的大小決定了結果是否準確。如果要精度為1度,那麼需要180列。
ρ值最大為圖片對角線的距離。如果精度要求達到畫素級別,那麼行數應該等於影象對角線的長度。

如果有一個100×100的水平直線在影象中央(在第50行的位置)。取直線上第一個點(x,y),將點帶入方程,遍歷θ值從0到180.求出對應的ρ值,這樣得到敵對(ρ,θ),如果該值再建立的2D陣列(累加器)中的對應位置上也存在,那個該位置加1。所以累加器中位置(50,90)=1。(一個點可能在多條直線當中,所以一個點可能對應多個值加1)。取直線第二個點,重複上述過程。更新累加器中的值。此時(50,90)的值為2。對直線上每個點都按照這種方式操作,最後(50,90)的值肯定最大。這就說明有一條直線。

(注意上面能選取到直線上的點的原因是因為選取的影象邊緣資訊點)

opencv中的霍夫變換
使用函式cv2.HoughLines(),返回(ρ,θ),ρ的單位是畫素,θ是弧度。
輸入引數:第一個引數是二值化影象,進行霍夫變換之前要進行二值化或者canny邊緣檢測。第二第三個引數代表ρ和θ的精度。第四個引數是閾值,只有當累加器中的值高於閾值時才被當成是直線。

import cv2
import numpy as np
img = cv2.imread('18.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50
,150,apertureSize = 3) lines = cv2.HoughLines(edges,1,np.pi/180,200) for rho,theta in lines[0]: a = np.cos(theta) b = np.sin(theta) x0 = a*rho y0 = b*rho x1 = int(x0 + 1000*(-b)) y1 = int(y0 + 1000*(a)) x2 = int(x0 - 1000*(-b)) y2 = int(y0 - 1000*(a)) cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2) cv2.imwrite('houghlines3.jpg',img)

這裡寫圖片描述

概率霍夫變換

上面的過程可以看到一條直線需要兩個引數,這需要大量計算。概率檢測是一種優化,它不是對每一個點都檢測,而是在影象中隨機選取點集合進行運算,檢測直線足夠用,但是要降低閾值。

這裡寫圖片描述

函式為 cv2.HoughLinesP()

引數為minLineLength表示直線長度的閾值,少於此長度的會被忽略。MaxLineGap兩天直線的間隔,小於此值會被當成一條直線。

返回值為直線的起點和終點。

這裡寫圖片描述