1. 程式人生 > >【翻譯:OpenCV-Python教程】坎尼邊緣檢測

【翻譯:OpenCV-Python教程】坎尼邊緣檢測

⚠️由於自己的拖延症,3.4.3翻到一半,OpenCV釋出了4.0.0了正式版,所以接下來是按照4.0.0翻譯的。

⚠️除了版本之外,其他還是照舊,Canny Edge Detection,原文

目標

在這一節,我們將學到:

  • 坎尼邊緣檢測的概念
  • OpenCV對此的函式:cv.Canny()

理論

坎尼邊緣檢測是一個很受歡迎的邊緣檢測演算法。它是被 John F. Canny 發明的:

  1. 它是一個多階段的演算法,我們將會把每個階段都過一遍。
  2. 降低噪聲

    由於邊緣檢測容易受到影象噪聲的影響,第一步是用5x5高斯濾波器去除影象中的噪聲。我們在前幾章已經看到了這一點。

  3. 找到影象的強烈梯度

    (通過上一步高斯)平滑後的影象,在通過索貝爾核心在水平和垂直方向濾波,來獲取兩個方向的一階導數(Gx)和(Gy)。從這兩個影象我們可以找到每個畫素邊緣的梯度和方向,如下:

    Edge\_Gradient \;(G) = \sqrt{G_x^2 + G_y^2} \\Angle \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg)

    梯度方向總是垂直於邊緣。圓角為代表垂直、水平和兩個對角線方向的四個角之一。

  4. 非極大值抑制

    在獲取到了梯度的幅值和方向之後,對影象進行全掃描,去除可能不構成邊緣的不需要的畫素。要達到這個目的,遍歷每個畫素,如果畫素是梯度方向上其鄰域內的區域性最大值,則該畫素點通過檢測。檢視下面的圖示:

    nms.jpg

    點A處於邊緣之上(在垂直方向上的邊緣)。梯度方向垂直於邊緣,點B和點C在梯度方向上,因此點A得通過點B和點C在水平方向上來檢測。如果如此(A點確實是區域性最大值得話),那麼就進入下個環節,否則就抑制A點(把A點設定為0(這樣A點就和經過前幾步處理的背景色一樣了))。

    簡單來說,你這一步得到的結果就是一張具有“細邊”的二元影象。

  5. 滯後閾值法

    這一個步驟,決定了(之前計算出來通過檢測的點組成的)所有的邊緣,哪些是真正的邊緣,哪些不是。要達到這個目的,我們需要最大、最小兩個閾值。任何強度梯度大於最大閾值的邊被認為是邊緣,小於最小閾值的邊一定是非邊邊緣,所以丟棄掉。位於這兩個閾值之間的邊界,根據它們的連通性分為邊緣和非邊緣。如果它們被連線到“確定邊緣”畫素,它們被認為是邊緣的一部分。否則,它們也會被丟棄。見下圖:

    hysteresis.jpg

    邊緣A在最大閾值之上,因為我們認為它是確定邊緣。儘管邊緣C在最大閾值之下(同時在最小閾值之上),但它與A邊緣是連通的,所以C也被認為是有效的邊緣我們也得到了完整的弧線。而B邊雖然在最小閾值之上,處於和C邊相同的區域,但卻並未與(像A邊這樣的)確定邊緣連通,所以它就被丟棄了。因此,我們必須相應地選擇最大閾值和最小閾值來得到正確的結果,這是非常重要的。

    加入邊緣是長線段的話,這一個步驟還會消除一些小畫素的噪聲。

因此我們最終得到的是影象中的強邊界。

OpenCV裡的坎尼邊緣檢測

OpenCV 把上面的所有步驟放進了同一個方法中,cv.Canny()。我們來看看怎麼使用它。第一個引數是輸入影象。第二和第三個引數分別是我們的最大和最小閾值。第三個引數是孔徑大小,它是用於尋找影象梯度的索貝爾核心的大小,預設情況下是3。最後 L2gradient 引數指定了求梯度大小的方程。如果為True,則使用之前講的公式,算出來更準確。否則使用這個函式:邊梯度(G) = |Gx| + |Gy|。預設情況下,這個值是False。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.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()

看看以下結果:

canny1.jpg

 

額外資源

Exercises

  • 寫一個小應用來做坎尼邊緣檢測,用兩個拖動條來控制最大最小閾值,這樣你就可以理解這兩個閾值對結果造成的影響。

上篇:【翻譯:OpenCV-Python教程】影象梯度

下篇:【翻譯:OpenCV-Python教程】