【火爐煉AI】機器學習046-影象邊緣的檢測方法
(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )
影象中各種形狀的檢測時計算機視覺領域中非常常見的技術之一,特別是影象中直線的檢測,圓的檢測,影象邊緣的檢測等,下面我們來研究一下如何快速檢測影象邊緣。
邊緣是不同區域的分界線,是周圍(區域性)畫素有顯著變化的畫素的集合,有幅值與方向兩個屬性。這個不是絕對的定義,主要記住邊緣是區域性特徵以及周圍畫素顯著變化產生邊緣。
常見邊緣檢測運算元:Roberts 、Sobel 、Prewitt、Laplacian、Log/Marr、Canny、Kirsch、Nevitia
1. Sobel運算元
Sobel運算元是影象邊緣檢測中最重要的運算元之一,在機器學習中佔有舉足輕重的作用,在技術上,它是一個離散的一階差分運算元,用來計算影象亮度函式的一階梯度之近似值。在影象的任何一點使用此運算元,將會得到該點對應的梯度向量或法向量。
在計算公式上,Sobel運算元包含有兩組3*3的矩陣,分別為橫向及縱向,將這兩個矩陣與影象做平面卷積,即可分別得到橫向及縱向的亮度差分近似值。所以這兩個運算元,一個是檢測水平邊緣的,另一個是檢測垂直邊緣的,與Prewitt運算元相比,Sobel運算元對於畫素的位置的影響做了加權,可以降低邊緣模糊程度,因此效果更好。
Sobel運算元演算法的優點是計算簡單,速度快,但是由於只採用了兩個方向的模板,只能檢測水平和垂直方向的邊緣,因此這種演算法對於紋理較為複雜的影象,其邊緣檢測效果就不是很理想。該演算法認為:凡灰度新值大於或等於閾值的畫素點都是邊緣點,這種判斷不太合理,會造成邊緣點的誤判,因為許多噪聲點的灰度值也很大。
import cv2 image=cv2.imread('E:\PyProjects\DataSet\FireAI/chair.jpg') # Sobel 運算元進行影象邊緣檢測 sobel_h=cv2.Sobel(image,cv2.CV_64F,1,0,ksize=3) sobel_v=cv2.Sobel(image,cv2.CV_64F,0,1,ksize=3) plt.figure(13,figsize=(15,30)) plt.subplot(131) plt.imshow(image,cmap='gray') # 彩色影象顯示異常,plt採用RGB模式,而cv2採用BGR模式 plt.title('raw_img') plt.subplot(132) plt.imshow(sobel_h,cmap='gray') plt.title('sobel_h') plt.subplot(133) plt.imshow(sobel_v,cmap='gray') plt.title('sobel_v') 複製程式碼

Sobel運算元需要優化的地方可能只有ksize一個引數了。ksize只能去1,3,5,7這四個數字。
2. Laplacian運算元
Laplacian運算元是N維歐幾里得空間中的一個二階微分運算元,定義為梯度grad的散度div。此處不講解這個運算元的計算和原理,只講解使用方法和效果
# Laplacian運算元進行影象邊緣檢測 lap=cv2.Laplacian(image, cv2.CV_64F) plt.figure(12,figsize=(10,30)) plt.subplot(121) plt.imshow(image,cmap='gray') # 彩色影象顯示異常,plt採用RGB模式,而cv2採用BGR模式 plt.title('raw_img') plt.subplot(122) plt.imshow(lap,cmap='gray') plt.title('Laplacian') 複製程式碼

3. Canny運算元
Canny的目標是找到一個最優的邊緣檢測演算法,最有邊緣檢測的含義是:
1,好的檢測:演算法能夠儘可能多的標識出影象中的實際邊緣。
2,好的定位:標識出的邊緣要與實際影象中的實際邊緣儘可能接近。
3,最小相應:影象中的邊緣只能標識一次,並可能存在的影象噪聲不應標識為邊緣
為了滿足這些要求,Canny使用了變分法,這是一種尋找滿足特定功能的函式的方法,最優檢測使用四個指數函式項的和表示,但是它非常近似於高斯函式的一階導數。
Canny演算法的步驟可以分為:降噪,尋找梯度,跟蹤邊緣。降噪是對原始影象與高斯平滑模板做卷積,得到的影象與原始影象相比有些輕微的模糊,這樣做的目的是單獨的畫素噪聲在經過高斯平滑處理後就變得幾乎沒有影響。
尋找梯度:Canny運算元使用4個mask檢測水平,垂直以及對角線方向的邊緣,原始影象與每個mask所作的卷積都儲存起來。對於每個點我們都標識在這個點上的最大值以及生成的邊緣方向。這樣我們就從原始影象生成了影象中每個點亮度梯度圖以及亮度梯度的方向。
跟蹤邊緣:較高的亮度梯度比較有可能是邊緣,但是沒有一個確切的值來限定多大的亮度梯度是邊緣,所以canny使用滯後閾值--高閾值和低閾值。
上述步驟完成之後,我們就得到了一個二值圖,每點表示是否是一個邊緣點。
# Canny運算元 canny = cv2.Canny(image, 50, 240) plt.figure(12,figsize=(10,30)) plt.subplot(121) plt.imshow(image,cmap='gray') # 彩色影象顯示異常,plt採用RGB模式,而cv2採用BGR模式 plt.title('raw_img') plt.subplot(122) plt.imshow(canny,cmap='gray') plt.title('Canny') 複製程式碼

Canny運算元使用的一個難點在於高閾值和低閾值的選擇,其實對於任何閾值的選擇,都面臨一個兩難問題,設定的太高,可能會漏掉部分資訊,設定的過低,會把噪聲當做重要訊號來處理,這一點,倒是很像機器學習中的準確率和召回率的關係。
Canny運算元適用於不同的場合,它的引數允許根據不同實現的特定要求進行調整以識別不同的邊緣特性。
########################小**********結###############################
1,此處講解的三個邊緣檢測運算元,使用起來都比較簡單,比較難的是理解其內在本質含義。
2,從效果上來看,我個人比較傾向於Canny運算元,因為從圖片中可以看出,其噪聲最少,得到的邊緣效果最好。
#################################################################
注:本部分程式碼已經全部上傳到( ofollow,noindex"> 我的github )上,歡迎下載。
參考資料:
1, Python機器學習經典例項,Prateek Joshi著,陶俊傑,陳小莉譯