前面的幾篇,我們討論了
Mean Filter
Gaussian Filter
Gradient
Sobel
Laplacian
而今天要介紹的 Canny Edge Detection。
在看完這篇之後,也許會發現原來前面學的很多東西,都是 Canny 的一部分。
Canny Edge Detection 不是一個全新的演算法,而是把前面介紹過的概念全部串在一起。
這也是它成為經典邊緣偵測方法的原因。
介紹 Sobel 時,我們已經可以找到圖片中亮度變化大的地方。
那是不是直接把 Sobel 的結果當作邊緣就好了?
事實上,如果真的這樣做,通常會出現很多問題。
例如:
如果直接拿來分析圖片,效果不會太好。
因此 Canny 的目的,就是把真正重要的邊緣留下來,然後把其他干擾全部去掉。
第一步先使用 Gaussian Filter。
Original
↓
Gaussian Blur
如果圖片本身很多雜訊,後面所有 Gradient 都會受到影響。
因此,Canny 一開始就先把圖片平滑。
這也是我們 Day 10 學 Gaussian Filter 的原因。
接著,利用 Sobel Operator。
分別計算:
得到每個 Pixel 的亮度變化。
Gradient X
+
Gradient Y
↓
Gradient Magnitude
到這裡,我們會知道哪些地方變化很劇烈,但這些區域不一定都是我們最後要保留的邊緣。
這個步驟的工作非常簡單:
假設有一條很粗的邊緣。
Canny 會沿著 Gradient 的方向,比較附近 Pixel 的 Gradient Magnitude,只保留局部最大的那個 Pixel。
其他比較弱的 Pixel 就會被抑制。
因此,原本很粗的邊緣,就會變成細細的一條線。
為什麼需要這一步呢?
因為並不是所有邊緣都一樣重要。
如果 Gradient 非常大,代表它很可能是真正的邊界。
如果 Gradient 很小,可能只是雜訊。
因此,Canny 設定兩個 Threshold。
Gradient
↓
Strong Edge
Weak Edge
Not Edge
把 Pixel 分成三類:Strong Edge、Weak Edge 和 Not Edge。
Strong Edge 會直接保留,Weak Edge 則交給下一步判斷它是不是和 Strong Edge 連在一起。
來到了最後一步,Edge Tracking by Hysteresis。
這裡的 Hysteresis(遲滯),可以先簡單理解成:
不只看一個 Pixel 有多強,而是根據它和其他 Edge 的連接關係來決定要不要保留。
還記得前一步的 Double Threshold 嗎?
我們把 Edge 分成:
這時候,Weak Edge 就會遇到一個問題:
它本身不夠強。
但它真的就是雜訊嗎?不一定。
有些 Weak Edge 雖然 Gradient 比較小,但其實是某條完整邊緣的一部分。
所以 Canny 不會直接把所有 Weak Edge 都刪掉。
而是會繼續追蹤它和 Strong Edge 之間的連接關係。
如果一個 Weak Edge 和 Strong Edge 連接。
那它很可能也是同一條邊界的一部分,因此會保留下來。
相反地,如果一個 Weak Edge 沒有和任何 Strong Edge 連接。
那它比較可能只是雜訊,因此會被刪除。
這就是 Hysteresis 的概念。
它不是單純使用一個 Threshold 決定「留下」或「刪除」。
而是使用兩個 Threshold,搭配 Edge 之間的連接關係來做判斷。
經過這一步,就能在保留完整邊緣的同時降低雜訊造成的誤判。
OpenCV 已經幫我們把剛剛提到的整個流程都包好了。
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("dog.jpeg", cv2.IMREAD_GRAYSCALE)
edges = cv2.Canny(img, 100, 200)
其中:
接著比較結果。
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()
結果長這樣:

可以看到,最後留下來的幾乎都是清楚且連續的邊界。
Canny 並不是靠某一個很厲害的新演算法完成的,而是把很多方法組合起來:
每一步都在解決前一步留下來的問題。
因此最後得到的邊緣品質,會比單獨使用 Sobel 或 Laplacian 都更好。
今天介紹了 Canny Edge Detection。
前面介紹的 Gaussian Filter、Gradient、Sobel,共同組成了 Canny 的核心流程。
這也是 Canny 能成為經典邊緣偵測演算法的重要原因。
不過,找到邊緣之後如果想把圖片中的物體和背景真正分開,又該怎麼做?
明天我們會來介紹一個經典方法:Threshold(二值化)。
看看如何利用亮度,把圖片切分成黑與白兩個世界。