python中opencv Canny邊緣檢測

Canny邊緣檢測

Canny邊緣檢測是一種使用多級邊緣檢測算法檢測邊緣的方法。

OpenCV提供瞭函數cv2.Canny()實現Canny邊緣檢測。

Canny邊緣檢測基礎

Canny邊緣檢測分為如下幾個步驟:

  • 去噪。噪聲會影響邊緣檢測的準確性,因此首先要將噪聲過濾掉。
  • 計算梯度的幅度與方向
  • 非極大值抑制,即適當地讓邊緣“變瘦”
  • 確定邊緣。使用雙閾值算法確定最終的邊緣信息

高斯濾波去除圖像噪聲

圖像邊緣非常容易受到噪聲的幹擾,因此為瞭避免檢測到錯誤的邊緣信息,通常需要對圖像進行濾波以去除噪聲。

濾波的目的是平滑一些紋理較弱的非邊緣區域,以便得到更準確的邊緣。在實際處理過程中,通常采用高斯濾波去除圖像中的噪聲。在濾波過程中,通過濾波器對像素點周圍的像素計算加權平均值,獲取最終濾波結果。對於高斯濾波器,越臨近中心的點,權值越大。

濾波器的大小也是可變的,高斯核的大小對於邊緣檢測的效果具有很重要的作用。濾波器的核越大,邊緣信息對於噪聲的敏感度就越低。不過,核越大,邊緣檢測的定位錯誤也會隨之增加。通常來說,一個5×5的核能夠滿足大多數的情況

計算梯度

關註梯度的方向,梯度的方向與邊緣的方向是垂直的。

邊緣檢測算子返回水平方向的Gx和垂直方向的Gy。

梯度的幅度G和方向Θ(用角度值表示)為:

atan2(·)表示具有兩個參數的arctan函數。

梯度的方向總是與邊緣垂直的,通常就近取值為水平(左、右)、垂直(上、下)、對角線(右上、左上、左下、右下)等8個不同的方向。

在計算梯度時,我們會得到梯度的幅度和角度(代表梯度的方向)兩個值。

梯度的表示法: 其中,每一個梯度包含幅度和角度兩個不同的值。為瞭方便觀察,這裡使用瞭可視化表示方法。

左上角頂點的值“2↑”實際上表示的是一個二元數對“(2, 90)”,表示梯度的幅度為2,角度為90°。

非極大值抑制

在獲得瞭梯度的幅度和方向後,遍歷圖像中的像素點,去除所有非邊緣的點。

在具體實現時,逐一遍歷像素點,判斷當前像素點是否是周圍像素點中具有相同梯度方向的最大值,並根據判斷結果決定是否抑制該點。

通過以上描述可知,該步驟是邊緣細化的過程。針對每一個像素點:

  • 如果該點是正/負梯度方向上的局部最大值,則保留該點。
  • 如果不是,則抑制該點(歸零)。

(梯度方向垂直於邊緣)

“正/負梯度方向上”是指相反方向的梯度方向。

對於同一個方向的若幹個邊緣點,基本上僅保留瞭一個,因此實現瞭邊緣細化的目的。

應用雙閾值確定邊緣

完成上述步驟後,圖像內的強邊緣已經在當前獲取的邊緣圖像內。但是,一些虛邊緣可能也在邊緣圖像內。

這些虛邊緣可能是真實圖像產生的,也可能是由於噪聲所產生的。對於後者,必須將其剔除。設置兩個閾值,其中一個為高閾值maxVal,另一個為低閾值minVal。根據當前邊緣像素的梯度值(指的是梯度幅度)與這兩個閾值之間的關系,判斷邊緣的屬性。

具體步驟為:

  • 如果當前邊緣像素的梯度值大於或等於maxVal,則將當前邊緣像素標記為強邊緣。
  • 如果當前邊緣像素的梯度值介於maxVal與minVal之間,則將當前邊緣像素標記為虛邊緣(需要保留)。
  • 如果當前邊緣像素的梯度值小於或等於minVal,則抑制當前邊緣像素。

在上述過程中,我們得到瞭虛邊緣,需要對其做進一步處理。一般通過判斷虛邊緣與強邊緣是否連接,來確定虛邊緣到底屬於哪種情況。

通常情況下,如果一個虛邊緣:

  • 與強邊緣連接,則將該邊緣處理為邊緣。
  • 與強邊緣無連接,則該邊緣為弱邊緣,將其抑制。

高閾值maxVal和低閾值minVal不是固定的,需要針對不同的圖像進行定義。

Canny函數及使用

OpenCV提供瞭函數cv2.Canny()來實現Canny邊緣檢測,其語法形式如下:

edges = cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])

  • edges為計算得到的邊緣圖像。
  • image為8位輸入圖像。
  • threshold1表示處理過程中的第一個閾值。
  • threshold2表示處理過程中的第二個閾值。
  • apertureSize表示Sobel算子的孔徑大小。
  • L2gradient為計算圖像梯度幅度(gradient magnitude)的標識。其默認值為False。如果為True,則使用更精確的L2范數進行計算(即兩個方向的導數的平方和再開方),否則使用L1范數(直接將兩個方向導數的絕對值相加)。

**例子:**使用函數cv2.Canny()獲取圖像的邊緣,並嘗試使用不同大小的threshold1和threshold2,觀察獲取到的邊緣有何不同。

import cv2
o=cv2.imread("./img/hand1.png", cv2.IMREAD_GRAYSCALE)
r1=cv2.Canny(o,128,200)
r2=cv2.Canny(o,32,128)
cv2.imshow("original", o)
cv2.imshow("result1", r1)
cv2.imshow("result2", r2)
cv2.waitKey()
cv2.destroyAllWindows()

當函數cv2.Canny()的參數threshold1和threshold2的值較小時,能夠捕獲更多的邊緣信息。

到此這篇關於python中opencv Canny邊緣檢測的文章就介紹到這瞭,更多相關opencv Canny內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: