首頁 > 軟體

Python OpenCV Canny邊緣檢測演演算法的原理實現詳解

2022-07-17 18:01:37

Gaussian smoothing

總的來說,Canny邊緣檢測可以分為四個步驟:

由於邊緣檢測對噪聲敏感,因此對影象應用高斯平滑以幫助減少噪聲。
具體做法是,採用一個5*5的高斯平滑濾波器對影象進行濾波處理。

Computing the gradient magnitude and orientation

對平滑後的影象,在水平、垂直兩個方向上使用Sobel運算元(如下圖)計算梯度大小,得到兩個方向上的一階導數Gx與Gy。

在得到兩個方向上的梯度之後,對這兩個向量求和,得到這一點處的梯度大小與方向。

採用四捨五入,將梯度方向確定為上下左右與四個對角線方向之一(45°的倍數)。

Non-maxima suppression

在得到梯度大小與方向之後,對影象進一步掃描,去除不構成邊緣的不重要的畫素資訊,這裡採用的方法是非極大值抑制——在每個畫素處,檢查畫素是否在其梯度方向的鄰域中是區域性最大值,只保留區域性最大值的梯度。

在上圖中,點A位於邊緣上。梯度方向與邊緣方向垂直。為了確定要不要保留A點作為邊緣,需要將A點處的梯度大小與B、C兩點的梯度大小比較,如果A點的梯度大小不是區域性最大,則將該點抑制。

因此,從結果上講,NMS其實是將B、C兩點抑制了,它們不會出現在結果中,因此這一步的效果是“thin edges”。

Hysteresis thresholding

定義上界與下界兩個閾值,並規定:

  • 任何梯度強度大於上界的畫素都是邊;
  • 任何梯度強度小於下界的畫素都不是邊;
  • 任何梯度介於兩個閾值之間的可能是邊,此時考察它們的連通性,如果它們和第一種情況(確定是邊緣的畫素)相連線,就認為它們是邊緣,否則認為它們不是邊緣。

在上圖中,A點在maxVal閾值之上,確定是邊緣。C介於兩個閾值之間,但與A相連,因此它也是邊緣。B介於兩個閾值之間,它所在的曲線上並沒有任何畫素點的梯度強度在maxVal之上,因此它不是邊緣。

需要指出的是,上面四步操作之後得到的是strong edges。

OpenCV實現

OpenCV提供了cv.Canny()方法,該方法將輸入的原始影象轉換為邊緣影象。

該方法的原型為:

cv.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]) -> 	edges
cv.Canny(dx, dy, threshold1, threshold2[, edges[, L2gradient]]) -> edges

image引數是array格式的輸入影象。threshold1與threshold2分別是我們的下界閾值與上界閾值。apertureSize是用於查詢影象梯度的Sobel核的大小,預設為3。L2gradient指定了求梯度幅值的公式,是一個布林型變數,預設為False。當它為True時,使用L2,否則使用L1。

下面是具體程式碼:

def canny_detect(image_path, show=True):
    # 讀取影象
    image = cv2.imread(image_path, 0)
    # 獲取結果
    edges = cv2.Canny(image, 100, 200)
    if show:
        # 繪製原圖
        plt.subplot(121)
        plt.imshow(image, cmap='gray')
        plt.title('Original Image')
        plt.xticks([])
        plt.yticks([])
        # 繪製邊緣圖
        plt.subplot(122)
        plt.imshow(edges, cmap='gray')
        plt.title('Edge Image')
        plt.xticks([])
        plt.yticks([])

        plt.show()
    return edges
canny_detect('images/2.jpeg')

效果:

到此這篇關於Python OpenCV Canny邊緣檢測演演算法的原理實現詳解的文章就介紹到這了,更多相關Python OpenCV Canny邊緣檢測 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com