邊緣檢測
常見運算元
邊緣檢測是影像處理和計算機視覺中的一個基本任務,目的是識別影像中物體的邊界。邊緣是影像中亮度變化顯著的區域,通常標誌著物體、表面或形狀的邊界。邊緣檢測對於後續的影像分析任務,如特徵提取、目標識別和影像分割等,都是非常重要的。
常見邊緣檢測演算法:
- Roberts運算元:基於對角線方向的差分,使用兩個2x2的卷積核來檢測邊緣。
- Prewitt運算元:使用3x3的卷積核,對影像進行水平和垂直方向的差分,以檢測邊緣。
- Sobel運算元:也是基於3x3的卷積核,但設計得更加精細,可以同時檢測水平和垂直方向的邊緣。
- Kirsch運算元:使用8個不同方向的3x3卷積核來檢測邊緣,可以檢測8個方向上的邊緣。
- Robinson運算元:類似於Kirsch運算元,使用8個3x3的卷積核,但核的值有所不同。
- Canny運算元:被認為是最優秀的邊緣檢測運算元之一,它透過高斯濾波、梯度計算、非極大值抑制和雙閾值檢測等步驟來檢測邊緣。
- Laplacian運算元:基於二階導數,用於檢測影像中的邊緣,但對噪聲較為敏感。
- Zero-Crossing運算元:基於拉普拉斯運算元,透過檢測拉普拉斯運算元的零交叉點來確定邊緣位置。
- Shen-Castan濾波器:結合了Canny運算元和Laplacian運算元的特點,透過非線性對映和閾值處理來檢測邊緣。
- 結構化森林:一種較新的邊緣檢測方法,使用深度學習技術來檢測邊緣。
邊緣檢測演算法的選擇:
- 簡單性:對於需要快速響應的應用,可能會選擇Roberts、Prewitt或Sobel運算元。
- 準確性:對於需要高精度邊緣檢測的應用,Canny運算元通常是首選。
- 抗噪聲能力:Canny運算元和結構化森林等演算法具有較強的抗噪聲能力。
- 計算資源:對於計算資源有限的情況,可能會選擇計算量較小的演算法。
每種演算法都有其特定的應用場景和優缺點,選擇合適的演算法需要根據具體的應用需求和條件來決定。
Canny運算元
Canny運算元是一種經典的邊緣檢測演算法,由John F. Canny在1986年提出。它的目標是在保留影像原有屬性的同時,顯著減少影像的資料規模,找到最優的邊緣檢測解。Canny運算元以其準確性高、低錯誤率、單一性和高效性而聞名,被廣泛應用於各種計算機視覺系統中。以下是Canny運算元的主要步驟和特點:
- 高斯濾波去噪:Canny演算法的第一步是使用高斯濾波器平滑影像,以去除噪聲。噪聲和邊緣都屬於高頻訊號,高斯模糊可以減少噪聲對邊緣檢測的影響。高斯核的大小會影響邊緣檢測的效能,核越大,對噪聲的抑制越強,但邊緣的定位誤差也可能增加。
- 計算梯度強度和方向:Canny演算法使用Sobel運算元來計算影像的梯度幅度和方向。梯度的方向通常與邊緣垂直,梯度的方向被歸為四類:垂直、水平和兩個對角線(即,0度、45度、90度和135度四個方向)。
- 非極大值抑制:在計算出梯度幅度和方向後,Canny運算元透過非極大值抑制技術來過濾掉非邊緣畫素,使得邊緣更加清晰。這個過程保留了每個畫素點上梯度強度的極大值,過濾掉其他的值。
- 雙閾值檢測:經過非極大值抑制後,影像中仍然有很多噪聲點。Canny演算法使用雙閾值技術,設定一個閾值上界和閾值下界,大於上界的認為是強邊緣,小於下界的不是邊緣,兩者之間的是候選項(弱邊緣),需進行進一步處理。
- 滯後技術跟蹤邊緣:最後,Canny運算元使用滯後技術來跟蹤邊緣。如果某一畫素位置和強邊界相連的弱邊界則認為是邊緣,其他的弱邊界則被刪除。
Canny運算元的優勢在於其能夠準確地找到影像中真實的邊緣位置,並能夠將邊緣與噪聲區分開,同時保持邊緣的連續性和精確性。它適用於實時邊緣檢測,並且在MATLAB、OpenCV等常用影像處理工具中已有內建的Canny運算元API。
使用OpenCV進行Canny邊緣檢測的Python程式碼如下:
首先,確保你已經安裝了OpenCV庫。如果沒有安裝,可以透過pip安裝:
xxxxxxxxxx
pip install opencv-python
然後,你可以使用以下程式碼進行邊緣檢測:
xxxxxxxxxx
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 讀取影像(注意路徑替換,並使用`cv2.IMREAD_GRAYSCALE`引數以灰度模式讀取影像)
image = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE)
# 檢查影像是否成功載入
if image is None:
print("Error: Image not found")
else:
# 應用高斯模糊,減少影像噪聲,有助於Canny運算元更準確地檢測邊緣。
blurred_image = cv2.GaussianBlur(image, (5, 5), 0)
# 使用Canny運算元檢測邊緣
# 引數分別為:高閾值和低閾值(閾值決定了哪些邊緣被認為是真實的邊緣)
edges = cv2.Canny(blurred_image, 50, 150)
# 顯示原圖和邊緣檢測結果
plt.figure(figsize=(10, 5))
plt.subplot(121), plt.imshow(image, 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()
Kirsch運算元
Kirsch運算元是一種邊緣檢測演算法,由R. Kirsch提出。它透過使用8個特定的3x3模板對影像進行卷積操作來檢測邊緣,這些模板代表了8個不同的方向,能夠對影像上的8個特定邊緣方向作出最大響應。在運算中,取這8個方向的最大值作為影像的邊緣輸出。
Kirsch運算元的特點:
- 多方向響應:Kirsch運算元的8個模板可以檢測影像中的多個方向的邊緣,這使得它在保持細節和抗噪聲方面都有較好的效果。
- 邊緣強度與方向:在計算邊緣強度的同時可以得到邊緣的方向,各方向間的夾角為45º。
- 最大響應值:對於影像上的每一個畫素點,Kirsch運算元透過卷積求導數,並取8個方向中的最大值作為該點的邊緣輸出。
Kirsch運算元的模板:
Kirsch運算元的8個模板如下所示,每個模板對應一個特定的方向,用於檢測該方向上的邊緣強度:
這些模板透過與影像進行卷積操作來計算每個畫素點的梯度幅度,然後選擇最大梯度幅度的方向作為該點的邊緣方向。Kirsch運算元在影像處理領域,尤其是在邊緣檢測方面,因其有效性和魯棒性而被廣泛應用。
根據搜尋結果,以下是使用Python和OpenCV實現Kirsch運算元進行邊緣檢測的程式碼示例:
xxxxxxxxxx
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 讀取影像
image = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE)
# 檢查影像是否成功載入
if image is None:
print("Error: Image not found")
else:
# 自定義Kirsch運算元的8個卷積核
m1 = np.array([[5, 5, 5], [-3, 0, -3], [-3, -3, -3]])
m2 = np.array([[-3, 5, 5], [-3, 0, 5], [-3, -3, -3]])
m3 = np.array([[-3, -3, 5], [-3, 0, 5], [-3, -3, 5]])
m4 = np.array([[-3, -3, -3], [-3, 0, 5], [-3, 5, 5]])
m5 = np.array([[-3, -3, -3], [-3, 0, -3], [5, 5, 5]])
m6 = np.array([[-3, -3, -3], [5, 0, -3], [5, 5, -3]])
m7 = np.array([[5, -3, -3], [5, 0, -3], [5, -3, -3]])
m8 = np.array([[5, 5, -3], [5, 0, -3], [-3, -3, -3]])
filterlist = [m1, m2, m3, m4, m5, m6, m7, m8] # 將各個方向的卷積核放到一起便於統一操作
# 建立三維陣列,第0維表示各個方向卷積後的值
filtered_list = np.zeros((8, image.shape[0], image.shape[1]))
# 對影像進行卷積操作
for k in range(8):
out = cv2.filter2D(image, cv2.CV_16S, filterlist[k])
filtered_list[k] = out
# 取八個方向中的最大值作為影像該點濾波之後的新的畫素值
final = np.max(filtered_list, axis=0)
# 將畫素值大於255的點等於255,小於255的點等於0
final[np.where(final >= 255)] = 255
final[np.where(final < 255)] = 0
# 顯示原圖和邊緣檢測結果
plt.figure(figsize=(10, 5))
plt.subplot(121), plt.imshow(image, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(final, cmap='gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
# 顯示影像
plt.show()
Kirsch運算元和Canny運算元區別
Kirsch運算元和Canny運算元都是影像處理中用於邊緣檢測的演算法,但它們在實現和特點上存在一些區別:
-
原理和方法:
- Kirsch運算元:基於一階導數的方法,使用8個方向的卷積核來檢測邊緣,每個卷積核對應一個方向,能夠檢測8個方向的邊緣強度。
- Canny運算元:非微分邊緣檢測運算元,它是一個多階段的最佳化運算元,包括高斯濾波、梯度計算、非極大值抑制和雙閾值檢測等步驟。
-
對噪聲的敏感性:
- Kirsch運算元:由於考慮了多個方向的畫素突變,對噪聲的抑制能力不如Canny運算元,銳化效果可能不是很理想。
- Canny運算元:首先使用高斯濾波器平滑影像以去除噪聲,因此對噪聲不敏感,不容易受到噪聲干擾。
-
邊緣定位:
- Kirsch運算元:邊緣定位不如Canny運算元精確,因為它是基於一階導數的,而Canny運算元結合了梯度的方向和幅度。
- Canny運算元:邊緣定位較準確,常用於噪聲較多,灰度漸變的影像。
-
計算複雜度:
- Kirsch運算元:由於使用了8個卷積核,計算複雜度相對較高。
- Canny運算元:雖然實現較為複雜,但通常被認為是最有效的邊緣檢測方法之一,尤其是在實際專案如車道線檢測中。
-
應用場景:
- Kirsch運算元:適用於簡單場景下的邊緣檢測,尤其是當需要快速響應時。
- Canny運算元:被廣泛用於諸如車道線檢測等實際專案中,是最有效的邊緣檢測方法之一。
總的來說,Canny運算元在邊緣檢測的準確性、魯棒性以及對噪聲的抑制方面表現更好,而Kirsch運算元則在計算速度上可能有一定優勢,尤其是在對實時性要求較高的應用中。
結構化森林
結構化森林(Structured Forests)是一種基於深度學習的邊緣檢測方法,它在影像處理領域中被用來快速且有效地識別影像中的邊緣。以下是結構化森林的一些關鍵特點和應用場景:
- 快速邊緣檢測:結構化森林能夠快速預測區域性掩模的邊緣,這對於實時或近實時的邊緣檢測應用非常有用。
- 深度學習的應用:結構化森林結合了深度學習技術,透過訓練一個結構化的隨機森林模型來識別影像中的邊緣。這種方法可以處理複雜的影像特徵,並在多種場景下表現出良好的效能。
- 提高檢測準確性:結構化森林在實驗中顯示出,它不僅提高了檢測的準確性,而且減少了計算時間。這對於需要高效邊緣檢測的應用場景非常重要。
- 複雜背景下的應用:在複雜相似背景下,結構化森林能夠有效地區分相似和隨機的裂縫特徵,這對於結構健康監測等領域尤為重要。
- 與其他演算法的結合:結構化森林可以與其他影像處理技術結合使用,例如與Hough變換結合用於海天線檢測。這種方法可以較好地忽略區域性干擾邊緣,強化邊界提取,對複雜海天背景下的海天線檢測具備魯棒性和高準確性。
- OpenCV中的實現:在OpenCV庫中,結構化森林被實現為一個快速的邊緣檢測工具。它可以透過提供預訓練的模型檔案來使用,這個模型檔案可以在GitHub的opencv_extra倉庫中找到。
- 程式碼實現:在實際應用中,結構化森林的邊緣檢測可以透過幾行程式碼實現。首先,需要將輸入影像轉換為浮點型別,併除以255進行歸一化。然後,使用
createStructuredEdgeDetection
函式建立一個邊緣檢測物件,並呼叫detectEdges
方法來檢測邊緣。最後,可以透過非極大值抑制(NMS)進一步處理邊緣圖,以得到更清晰的邊緣。
結構化森林因其快速、準確和在複雜背景下的有效性,成為了邊緣檢測領域中一個有前景的方法。
在OpenCV中,結構化森林(Structured Forests)邊緣檢測可以透過以下步驟進行呼叫和實現。這裡提供一個簡單的Python程式碼示例,展示如何使用OpenCV中的結構化森林進行邊緣檢測:
x
import cv2
import numpy as np
# 讀取影像 (注意路徑替換,並使用`cv2.IMREAD_GRAYSCALE`引數以灰度模式讀取影像)
image = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE)
# 檢查影像是否成功載入
if image is None:
print("Error: Image not found")
else:
# 建立結構化森林邊緣檢測器
structured_forest = cv2.createStructuredEdgeDetection()
# 檢測邊緣
edges = structured_forest.detectEdges(image)
# 應用非極大值抑制(NMS)來細化邊緣
# flags=cv2.Canny_NORM_L2_GRADIENT來應用非極大值抑制,這有助於細化邊緣。
edges_nms = structured_forest.detectEdges(image, flags=cv2.Canny_NORM_L2_GRADIENT)
# 顯示原始影像和邊緣檢測結果
cv2.imshow('Original Image', image)
cv2.imshow('Edges', edges)
cv2.imshow('Edges NMS', edges_nms)
# 等待按鍵後關閉視窗
cv2.waitKey(0)
cv2.destroyAllWindows()