原理
Canny邊緣檢測是一種常用的邊緣檢測算法。由 John F. Canny提出
這是一個多階段的算法,我們將經歷每個階段。
1.降低噪音
由於邊緣檢測容易受到圖像中噪聲的影響,第一步是用5x5高斯濾波器去除圖像中的噪聲。我們在前幾章已經見過了。
2.尋找圖像的強度梯度
然后對平滑后的圖像進行水平方向和垂直方向的Sobel核濾波,得到水平方向(Gx)和垂直方向(Gy)的一階導數。這兩幅圖像中,我們可以發現每個像素的邊緣梯度和方向如下:
梯度方向總是垂直於邊緣,它是四角之一,代表垂直、水平和兩個對角線方向。
3.非極大值抑制
得到梯度大小和方向后,對圖像進行全面掃描,去除非邊界點。在每個像素處,看這個點的梯度是不是周圍具有相同梯 度方向的點中最大的,查看下圖:
點A在邊緣上(垂直方向)。梯度方向垂直於邊緣。點B和點C在梯度方向上,因此,點A與點B和點C進行檢查,看它是否形成局部最大值,如果是,則將其考慮到下一階段,否則將抑制它(使其為零)。
簡而言之,您得到的結果是一個具有“細邊”的二進制圖像。
4.滯后閾值
現在要確定那些邊界才是真正的邊界,為此,我們需要兩個閾值,minVal和maxVal。任何強度梯度大於maxVal的邊都肯定是邊,小於minVal的邊肯定是非邊,所以丟棄。位於這兩個閾值之間的根據它們的連接性對邊緣或非邊緣進行分類(如果介於兩者之間的話,就要看這個點是 否與某個被確定為真正的邊界點相連,如果是就認為它也是邊界點,如果不是 就拋棄。如下圖:
A 高於閾值 maxVal 所以是真正的邊界點。C 雖然低於 maxVal 但高於minVal 並且與 A 相連,所以也被認為是真正的邊界點。而 B 就會被拋棄,因 為他不僅低於 maxVal 而且不與真正的邊界點相連。所以選擇合適的 maxVal 和 minVal 對於能否得到好的結果非常重要。 在這一步一些小的噪聲點也會被除去,因為我們假設邊界都是一些長的線段。
OpenCV中的Canny邊緣檢測
OpenCV將所有這些都放在一個函數cv.Canny中。第一個參數是輸入圖像。第二個和第三個參數分別是minVal和maxVal。第三個參數是aperture_size,它是用來尋找圖像梯度的Sobel內核的大小,默認值是3。最后一個參數是L2gradient,它指定了求梯度大小的方程。
函數:
edges=cv.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]])
edges=cv.Canny(dx, dy, threshold1, threshold2[, edges[, L2gradient]])
參數:
dx | 16-bit 輸入圖像的x導數 (CV_16SC1 or CV_16SC3). |
dy | 16-bit 輸入圖像的y導數 (和dx有相同類型). |
edges | 輸出的邊緣地圖; 單通道8-bit 圖像, 與輸入圖像有相同大小。 |
threshold1 | 第一個閾值,低閾值 |
threshold2 | 第二個閾值,高閾值 |
L2gradient | 如果為真,則使用更精確的L2范數進行計算(即兩個方向的倒數的平方和再開方),否則使用L1范數(直接將兩個方向導數的絕對值相加)。 |
舉例:
import numpy as np import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('4.jpg', 0) edges = cv.Canny(img, 100, 200) plt.subplot(121), plt.imshow(img, 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()