1 原理
Canny 邊緣檢測是一種非常流行的邊緣檢測算法,是 John F.Canny 在1986 年提出的。它是一個(gè)有很多步構(gòu)成的算法,我們接下來會(huì)逐步介紹。
1.1. 噪聲去除
由于邊緣檢測很容易受到噪聲影響,所以第一步是使用 5x5 的高斯濾波器去除噪聲,這個(gè)前面我們已經(jīng)學(xué)過了.opencv圖像平滑 - 簡書
1.2.?計(jì)算圖像梯度
對平滑后的圖像使用Sobel算子計(jì)算水平方向和豎直方向的一階導(dǎo)數(shù)(圖像梯度)(Gx和Gy)。根據(jù)得到的這兩幅梯度圖找到邊界的梯度和方向。公式如下:

梯度的方向一般總是與邊界垂直。梯度方向被歸為四類:垂直,水平,和兩條對角線。
1.3. 非極大值抑制
在獲得梯度的方向和大小之后,應(yīng)該對整幅圖像做一個(gè)掃描,去除那些非邊界上的點(diǎn)。對每一個(gè)像素進(jìn)行檢查,看這個(gè)點(diǎn)的梯度是不是周圍具有相同梯度方向的點(diǎn)中最大的。如下圖所示:

現(xiàn)在得到的是一個(gè)包含“窄邊界”的二值圖像。
1.4. 滯后閾值
現(xiàn)在要確定那些邊界才是真正的邊界。這時(shí)我們需要設(shè)置兩個(gè)閾值:minVal 和 maxVal。當(dāng)圖像的灰度梯度高于 maxVal 時(shí)被認(rèn)為是真的邊界,那些低于 minVal 的邊界會(huì)被拋棄。如果介于兩者之間的話,就要看這個(gè)點(diǎn)是否與某個(gè)被確定為真正的邊界點(diǎn)相連,如果是就認(rèn)為它也是邊界點(diǎn),如果不是就拋棄。如下圖:

A 高于閾值 maxVal 所以是真正的邊界點(diǎn),C 雖然低于 maxVal 但高于minVal 并且與 A 相連,所以也被認(rèn)為是真正的邊界點(diǎn)。而 B 就會(huì)被拋棄,因?yàn)樗粌H低于 maxVal 而且不與真正的邊界點(diǎn)相連。所以選擇合適的 maxVal和 minVal 對于能否得到好的結(jié)果非常重要。在這一步一些小的噪聲點(diǎn)也會(huì)被除去,因?yàn)槲覀兗僭O(shè)邊界都是一些長的線段。
2.? OpenCV中的Canny邊界檢測
在 OpenCV 中只需要一個(gè)函數(shù):cv2.Canny(),就可以完成以上幾步。讓我們看如何使用這個(gè)函數(shù)。這個(gè)函數(shù)的第一個(gè)參數(shù)是輸入圖像。第二和第三個(gè)分別是 minVal 和 maxVal。第三個(gè)參數(shù)設(shè)置用來計(jì)算圖像梯度的 Sobel卷積核的大小,默認(rèn)值為 3。最后一個(gè)參數(shù)是 L2gradient,它可以用來設(shè)定求梯度大小的方程。如果設(shè)為 True,就會(huì)使用我們上面提到過的方程,否則使用方程:

代替,默認(rèn)值為 False。
img = cv2.imread('opencv_logo.jpg',0)
edges = cv2.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()
