iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
Software Development

從像素到 Computer Vision:30 天理解數位影像處理系列 第 16

Day 16 | Canny Edge Detection:經典的邊緣偵測方法

  • 分享至 

  • xImage
  •  

前面的幾篇,我們討論了

Mean Filter

Gaussian Filter

Gradient

Sobel

Laplacian

而今天要介紹的 Canny Edge Detection

在看完這篇之後,也許會發現原來前面學的很多東西,都是 Canny 的一部分。

Canny Edge Detection 不是一個全新的演算法,而是把前面介紹過的概念全部串在一起。

這也是它成為經典邊緣偵測方法的原因。

為什麼不直接用 Sobel?

介紹 Sobel 時,我們已經可以找到圖片中亮度變化大的地方。

那是不是直接把 Sobel 的結果當作邊緣就好了?

事實上,如果真的這樣做,通常會出現很多問題。

例如:

  • 邊緣太粗。
  • 雜訊也被當成邊緣。
  • 同一條邊界可能出現好幾條線。

如果直接拿來分析圖片,效果不會太好。

因此 Canny 的目的,就是把真正重要的邊緣留下來,然後把其他干擾全部去掉。

Canny 的步驟

Step 1:先降低雜訊

第一步先使用 Gaussian Filter

Original

↓

Gaussian Blur

如果圖片本身很多雜訊,後面所有 Gradient 都會受到影響。

因此,Canny 一開始就先把圖片平滑。

這也是我們 Day 10 學 Gaussian Filter 的原因。

Step 2:計算 Gradient

接著,利用 Sobel Operator

分別計算:

  • X 方向 Gradient
  • Y 方向 Gradient

得到每個 Pixel 的亮度變化。

Gradient X

+

Gradient Y

↓

Gradient Magnitude

到這裡,我們會知道哪些地方變化很劇烈,但這些區域不一定都是我們最後要保留的邊緣。

Step 3:Non-Maximum Suppression

這個步驟的工作非常簡單:

假設有一條很粗的邊緣。

Canny 會沿著 Gradient 的方向,比較附近 Pixel 的 Gradient Magnitude,只保留局部最大的那個 Pixel。

其他比較弱的 Pixel 就會被抑制。

因此,原本很粗的邊緣,就會變成細細的一條線。

Step 4:Double Threshold

為什麼需要這一步呢?

因為並不是所有邊緣都一樣重要。

如果 Gradient 非常大,代表它很可能是真正的邊界。

如果 Gradient 很小,可能只是雜訊。

因此,Canny 設定兩個 Threshold。

Gradient

↓

Strong Edge

Weak Edge

Not Edge

把 Pixel 分成三類:Strong Edge、Weak Edge 和 Not Edge。

Strong Edge 會直接保留,Weak Edge 則交給下一步判斷它是不是和 Strong Edge 連在一起。

Step 5:Edge Tracking by Hysteresis

來到了最後一步,Edge Tracking by Hysteresis。

這裡的 Hysteresis(遲滯),可以先簡單理解成:

不只看一個 Pixel 有多強,而是根據它和其他 Edge 的連接關係來決定要不要保留。

還記得前一步的 Double Threshold 嗎?

我們把 Edge 分成:

  • Strong Edge
  • Weak Edge
  • Not Edge

這時候,Weak Edge 就會遇到一個問題:

它本身不夠強。

但它真的就是雜訊嗎?不一定。

有些 Weak Edge 雖然 Gradient 比較小,但其實是某條完整邊緣的一部分。

所以 Canny 不會直接把所有 Weak Edge 都刪掉。

而是會繼續追蹤它和 Strong Edge 之間的連接關係。

如果一個 Weak Edge 和 Strong Edge 連接。

那它很可能也是同一條邊界的一部分,因此會保留下來。

相反地,如果一個 Weak Edge 沒有和任何 Strong Edge 連接。

那它比較可能只是雜訊,因此會被刪除。

這就是 Hysteresis 的概念。

它不是單純使用一個 Threshold 決定「留下」或「刪除」。

而是使用兩個 Threshold,搭配 Edge 之間的連接關係來做判斷。

經過這一步,就能在保留完整邊緣的同時降低雜訊造成的誤判。

實作:使用 Canny

OpenCV 已經幫我們把剛剛提到的整個流程都包好了。

import cv2
import matplotlib.pyplot as plt

img = cv2.imread("dog.jpeg", cv2.IMREAD_GRAYSCALE)

edges = cv2.Canny(img, 100, 200)

其中:

  • 第一個 Threshold 是 Low Threshold。
  • 第二個 Threshold 是 High Threshold。

接著比較結果。

plt.figure(figsize=(10,4))

plt.subplot(1,2,1)
plt.imshow(img, cmap="gray")
plt.title("Original")
plt.axis("off")

plt.subplot(1,2,2)
plt.imshow(edges, cmap="gray")
plt.title("Canny")
plt.axis("off")

plt.tight_layout()
plt.show()

結果長這樣:

https://ithelp.ithome.com.tw/upload/images/20260902/20181780FQO1OQs07h.png

可以看到,最後留下來的幾乎都是清楚且連續的邊界。

Canny 為什麼這麼成功?

Canny 並不是靠某一個很厲害的新演算法完成的,而是把很多方法組合起來:

  • Gaussian Filter 去除雜訊。
  • Sobel 計算 Gradient。
  • Non-Maximum Suppression 讓邊緣變細。
  • Double Threshold 過濾弱邊緣。
  • Hysteresis 保留真正連續的輪廓。

每一步都在解決前一步留下來的問題。

因此最後得到的邊緣品質,會比單獨使用 Sobel 或 Laplacian 都更好。

今天總結

今天介紹了 Canny Edge Detection。

前面介紹的 Gaussian Filter、Gradient、Sobel,共同組成了 Canny 的核心流程。

這也是 Canny 能成為經典邊緣偵測演算法的重要原因。

不過,找到邊緣之後如果想把圖片中的物體和背景真正分開,又該怎麼做?

明天我們會來介紹一個經典方法:Threshold(二值化)

看看如何利用亮度,把圖片切分成黑與白兩個世界。


上一篇
Day 15 | Laplacian:除了亮度變化,還能觀察什麼?
下一篇
Day 17 | Threshold:怎麼把圖片分成黑白兩個世界?
系列文
從像素到 Computer Vision:30 天理解數位影像處理25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言