OpenCV系列 邊緣檢測之Canny

2021-09-12 02:16:19 字數 3610 閱讀 4842

最近在做邊緣檢測方面的一些工作,在網路上也找了很多有用的資料,感謝那些積極分享知識的先輩們,自己在理解canny邊緣檢測演算法的過程中也走了一些彎路,在程式設計實現的過程中,也遇到了乙個讓我懷疑人生的bug(日了狗狗)。就此寫下此文,作為後記,也希望此篇文章可以幫助那些在理解canny演算法的道路上暫入迷途的童鞋。廢話少說,上乾貨。

canny邊緣檢測是從不同視覺物件中提取有用的結構資訊並大大減少要處理的資料量的一種技術,目前已廣泛應用於各種計算機視覺系統。canny發現,在不同視覺系統上對邊緣檢測的要求較為類似,因此,可以實現一種具有廣泛應用意義的邊緣檢測技術。邊緣檢測的一般標準包括:

1)        以低的錯誤率檢測邊緣,也即意味著需要盡可能準確的捕獲影象中盡可能多的邊緣。

2)        檢測到的邊緣應精確定位在真實邊緣的中心。

3)        影象中給定的邊緣應只被標記一次,並且在可能的情況下,影象的雜訊不應產生假的邊緣。

為了滿足這些要求,canny使用了變分法。canny檢測器中的最優函式使用四個指數項的和來描述,它可以由高斯函式的一階導數來近似。

在目前常用的邊緣檢測方法中,canny邊緣檢測演算法是具有嚴格定義的,可以提供良好可靠檢測的方法之一。由於它具有滿足邊緣檢測的三個標準和實現過程簡單的優勢,成為邊緣檢測最流行的演算法之一。

canny邊緣檢測演算法可以分為以下5個步驟:

1)        使用高斯濾波器,以平滑影象,濾除雜訊。

2)        計算影象中每個畫素點的梯度強度和方向。

3)        應用非極大值(non-maximum suppression)抑制,以消除邊緣檢測帶來的雜散響應。

4)        應用雙閾值(double-threshold)檢測來確定真實的和潛在的邊緣。

5)        通過抑制孤立的弱邊緣最終完成邊緣檢測。

下面詳細介紹每一步的實現思路。

為了盡可能減少雜訊對邊緣檢測結果的影響,所以必須濾除雜訊以防止由雜訊引起的錯誤檢測。為了平滑影象,使用高斯濾波器與影象進行卷積,該步驟將平滑影象,以減少邊緣檢測器上明顯的雜訊影響。大小為(2k+1)x(2k+1)的高斯濾波器核的生成方程式由下式給出:

下面是乙個sigma = 1.4,尺寸為3x3的高斯卷積核的例子(需要注意歸一化):

若影象中乙個3x3的視窗為a,要濾波的畫素點為e,則經過高斯濾波之後,畫素點e的亮度值為:

其中*為卷積符號,sum表示矩陣中所有元素相加求和。

重要的是需要理解,高斯卷積核大小的選擇將影響canny檢測器的效能。尺寸越大,檢測器對雜訊的敏感度越低,但是邊緣檢測的定位誤差也將略有增加。一般5x5是乙個比較不錯的trade off。

影象中的邊緣可以指向各個方向,因此canny演算法使用四個運算元來檢測影象中的水平、垂直和對角邊緣。邊緣檢測的運算元(如roberts,prewitt,sobel等)返回水平gx和垂直gy方向的一階導數值,由此便可以確定畫素點的梯度g和方向theta 。

其中g為梯度強度, theta表示梯度方向,arctan為反正切函式。下面以sobel運算元為例講述如何計算梯度強度和方向。

x和y方向的sobel運算元分別為:

其中sx表示x方向的sobel運算元,用於檢測y方向的邊緣; sy表示y方向的sobel運算元,用於檢測x方向的邊緣(邊緣方向和梯度方向垂直)。在直角座標系中,sobel運算元的方向如下圖所示。

圖3-1 sobel運算元的方向

若影象中乙個3x3的視窗為a,要計算梯度的畫素點為e,則和sobel運算元進行卷積之後,畫素點e在x和y方向的梯度值分別為: 

其中*為卷積符號,sum表示矩陣中所有元素相加求和。根據公式(3-2)便可以計算出畫素點e的梯度和方向。

非極大值抑制是一種邊緣稀疏技術,非極大值抑制的作用在於「瘦」邊。對影象進行梯度計算後,僅僅基於梯度值提取的邊緣仍然很模糊。對於標準3,對邊緣有且應當只有乙個準確的響應。而非極大值抑制則可以幫助將區域性最大值之外的所有梯度值抑制為0,對梯度影象中每個畫素進行非極大值抑制的演算法是:

1)        將當前畫素的梯度強度與沿正負梯度方向上的兩個畫素進行比較。

2)        如果當前畫素的梯度強度與另外兩個畫素相比最大,則該畫素點保留為邊緣點,否則該畫素點將被抑制。

通常為了更加精確的計算,在跨越梯度方向的兩個相鄰畫素之間使用線性插值來得到要比較的畫素梯度,現舉例如下:

圖3-2 梯度方向分割

如圖3-2所示,將梯度分為8個方向,分別為e、ne、n、nw、w、sw、s、se,其中0代表00~45o,1代表450~90o,2代表-900~-45o,3代表-450~0o。畫素點p的梯度方向為theta,則畫素點p1和p2的梯度線性插值為: 

因此非極大值抑制的偽**描寫如下:

需要注意的是,如何標誌方向並不重要,重要的是梯度方向的計算要和梯度運算元的選取保持一致。

在施加非極大值抑制之後,剩餘的畫素可以更準確地表示影象中的實際邊緣。然而,仍然存在由於雜訊和顏色變化引起的一些邊緣畫素。為了解決這些雜散響應,必須用弱梯度值過濾邊緣畫素,並保留具有高梯度值的邊緣畫素,可以通過選擇高低閾值來實現。如果邊緣畫素的梯度值高於高閾值,則將其標記為強邊緣畫素;如果邊緣畫素的梯度值小於高閾值並且大於低閾值,則將其標記為弱邊緣畫素;如果邊緣畫素的梯度值小於低閾值,則會被抑制。閾值的選擇取決於給定輸入影象的內容。

雙閾值檢測的偽**描寫如下:

到目前為止,被劃分為強邊緣的畫素點已經被確定為邊緣,因為它們是從影象中的真實邊緣中提取出來的。然而,對於弱邊緣畫素,將會有一些爭論,因為這些畫素可以從真實邊緣提取也可以是因雜訊或顏色變化引起的。為了獲得準確的結果,應該抑制由後者引起的弱邊緣。通常,由真實邊緣引起的弱邊緣畫素將連線到強邊緣畫素,而雜訊響應未連線。為了跟蹤邊緣連線,通過檢視弱邊緣畫素及其8個鄰域畫素,只要其中乙個為強邊緣畫素,則該弱邊緣點就可以保留為真實的邊緣。

抑制孤立邊緣點的偽**描述如下:

通過以上5個步驟即可完成基於canny演算法的邊緣提取,圖5-1是該演算法的檢測效果圖,希望對大家有所幫助。

圖5-1 canny邊緣檢測效果

opencv之邊緣檢測

canny檢測 發展 canny 的目標是找到乙個最優的邊緣檢測演算法,最優邊緣檢測的含義是 好的檢測 演算法能夠盡可能多地標識出影象中的實際邊緣。好的定位 標識出的邊緣要盡可能與實際影象中的實際邊緣盡可能接近。最小響應 影象中的邊緣只能標識一次,並且可能存在的影象雜訊不應標識為邊緣。為了滿足這些要...

Opencv 邊緣檢測

2018 7 5 凌晨 萬萬要認真,今晚抄書都能抄錯,是在該打。書上的一行 graysrc cv2.cvtcolor blurredsrc,cv2.color bgr2gray 硬生生被我抄成了 graysrc cv2.cvtcolor blurredsrc,cv2.color bayer bgr2...

opencv 邊緣檢測

include stdafx.h include using namespace cv using namespace std int edgethresh 1 宣告 原始,灰度,和 canny邊緣 mat image,cedge mat gray,edge void ontrackbar int,...