1.Canny邊緣偵測

1.1. 簡介

Canny邊緣檢測是一種使用多級邊緣檢測演算法偵測邊緣的方法。實作步驟如下:

  1. 去除雜訊:因為雜訊會影響檢測的準確度,因此使用高斯濾波去除雜訊。
  2. 計算梯度的幅度與方向。
  3. 非極大值之抑制:最相關的像素留下,其他歸零。
  4. 確定邊緣:利用雙設定值演算法進行。


1.2. 實作重點摘要

Canny演算法使用高斯濾波去除雜訊。濾波器越大,邊緣資訊對雜訊的敏感度越低,定位錯誤也會增加。

而非極大值之抑制,簡言之就是在計算過程中將與邊緣最相關的像素留下,其他像素值歸零。如下圖所示,A所在的地方離邊緣最近,計算出的相關數值也會最大,因此A會被保留,而B、C兩點都會被歸零。

source:OpenCV-Python Tutorials:Canny Edge Detection


最後,會透過設定maxVal和minVal兩個值來確定邊緣。可能情況有3種:

  • 若邊緣像素值 >= maxVal,則標記為強邊緣。
  • 若 minVal < 邊緣像素值 < maxVal,則標記為虛邊緣。接著判斷是否與強邊緣連接,若有則視為邊緣,若無,則將其抑制。
  • 若邊緣像素值 <= minVal,則抑制目前邊緣像素(歸零)。


如下圖所示,B和C都是虛邊緣,C有與強邊緣A相連結,所以會被保留。而B未與A相連結,則會被捨棄。

source:OpenCV-Python Tutorials:Canny Edge Detection


1.3. 程式相關種點說明

img_edge = cv2.Canny(img, minVal, maxVal, apertureSize, L2gradient)

  • img_edge為輸出影像。img為輸入影像。
  • minVal, maxVal為設定值。
  • apertureSize為Sobel大小,通常使用預設即可。
  • L2gradient為計算梯度的範數,若設為True,則使用L2範數計算兩個方向導數的平方和再取平方根。預設為False,使用L1範數計算兩個方向導數之絕對值相加。


1.4. 輸出結果分析

我們可透過設定值和範數的不同來觀察輸出結果。

1.4.1. 設定值 (minVal, maxVal)

當設定值的值越小,輸出結果的細節會越多。在本例中,我們以 (32, 128) 和 (128, 200) 來比較。"img_canny_L1_low"參數為(32, 128) ,"img_canny_L1"參數為(128, 200),從下圖來看,"img_canny_L1_low" 所保留的細節明顯高於 "img_canny_L1"。

<source:Greatway9999>


1.4.2. 範數 (L1、L2)

L2範數計算兩個方向導數的平方和再取平方根。L1範數計算兩個方向導數之絕對值相加。

使用L2範數計算,結果會更精確,因此,和L1範數計算結果相比,L2範數計算結果的細節相較少。右圖為L2輸出結果,其細節確實比中間圖片 (L1輸出結果) 少,特別是帽穗的部分。

<source:Greatway9999>


1.5. 完整程式

# Canny邊緣檢測

# 使用高斯濾波去除雜訊。濾波器越大,邊緣資訊對雜訊的敏感度越低,定位錯誤也會增加。


# 設定maxVal和minVal兩個值來確定邊緣。

# 若邊緣像素值 >= maxVal,則標記為強邊緣。

# 若 minVal < 邊緣像素值 < maxVal,則標記為虛邊緣。接著判斷是否與強邊緣連接,若有則視為邊緣,若無,則將其抑制。

# 若邊緣像素值 <= minVal,則抑制目前邊緣像素(歸零)。


import numpy as np

import cv2

img = cv2.imread('Lenna.jpg', cv2.IMREAD_GRAYSCALE)


#img_edge = cv2.Canny(img, minVal, maxVal, apertureSize, L2gradient)

# img_edge為輸出影像。img為輸入影像。

# minVal, maxVal為設定值。

# apertureSize為Sobel大小。

# L2gradient為計算梯度的範數,若設為True,則使用L2範數計算兩個方向導數的平方和再取平方根。預設為False,使用L1範數計算兩個方向導數之絕對值相加。


img_canny_L1 = cv2.Canny(img, 128, 200)

img_canny_L2 = cv2.Canny(img, 128, 200, L2gradient = True)


img_canny_L1_low = cv2.Canny(img, 32, 128)


cv2.imshow('img', img)

cv2.imshow('img_canny_L1',img_canny_L1)

cv2.imshow('img_canny_L2',img_canny_L2)

cv2.imshow('img_canny_L1_low',img_canny_L1_low)


cv2.waitKey()

cv2.destroyAllWindows()


#Canny邊緣偵測

---

參考資料:

0 留言