1. 程式人生 > >OpenCV Canny邊緣檢測

OpenCV Canny邊緣檢測

目標

在本章中,我們將瞭解

  • Canny邊緣檢測的概念
  • OpenCV函式用於:cv2.Canny()

理論

Canny邊緣檢測是一種流行的邊緣檢測演算法。它是由約翰·F·坎尼於1986年開發的。這是一個多階段的演算法。

降噪

由於邊緣檢測對影象中的噪聲很敏感,第一步是用5x5高斯濾波器去除影象中的噪聲。 

影象強度梯度的求取

然後在水平方向和垂直方向用Sobel核對平滑後的影象進行濾波,得到水平方向的一階導數(G_x)和垂直方向(G_y)從這兩幅影象中,我們可以找到每個畫素的邊緣梯度和方向如下:

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

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

非極大抑制

在獲得梯度幅值和方向後,對影象進行全面掃描,以消除可能不構成邊緣的任何不需要的畫素。為此,在每個畫素上,檢查畫素是否是其鄰域內沿梯度方向的區域性最大值。檢查下面的影象:

Non-Maximum Suppression

A點在邊緣(垂直方向)。梯度方向是正常的邊緣。點B和C呈梯度方向。因此,用點B和點C檢查點A,看看它是否形成區域性最大值。如果是,則考慮到下一階段,否則就會被抑制(將為零)。

簡而言之,你得到的結果是一幅帶有“薄邊”的二值影象。

遲滯閾值

這個階段決定了哪些是邊緣,哪些是真正的邊,哪些不是邊。為此,我們需要兩個閾值,MinVal和MaxVal。任何強度梯度大於MaxVal肯定是邊,而小於MinVal肯定是非邊緣的,所以被丟棄了。處於這兩個閾值之間的人根據其連通性分為邊緣或非邊緣。如果它們連線到“確定邊緣”畫素,則它們被視為邊緣的一部分。否則,它們也會被丟棄。見下圖:

Hysteresis Thresholding

邊緣A在MaxVal,因此被認為是“確定邊緣”。雖然邊緣C在MaxVal下面,但是它與邊A相連,因此也被認為是有效邊,我們得到了這條全曲線。但是邊緣B,雖然它在上面MinVal並且與邊緣C的區域相同,它沒有連線到任何“確定邊”,因此被丟棄。所以我們必須相應地選擇MinVal和MaxVal,得到正確的結果。

這一階段也消除了小畫素噪聲的假設,邊緣是長線。所以我們最終得到的是影象中的強邊。

OpenCV中的Canny邊緣檢測

OpenCV將上述所有功能都放在一個函式中,cv2.Canny()。我們會看看如何使用它。第一個引數是我們的輸入影象。第二個和第三個引數分別是我們的MinVal和MaxVal。第三個引數是aperture_size。它是用於查詢影象梯度的Sobel核的大小。預設情況下是3。最後一個引數是L2gradient ,它指定了求梯度幅值的公式。如果是True,它使用上面提到的更精確的方程,否則它使用這個函式:Edge\_Gradient \; (G) = |G_x| + |G_y|

。預設情況下,它是False。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('messi5.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()

見以下結果:

Canny Edge Detection