2013年1月9日 星期三

EmguCV Image Process: Filtering the Images part 4

中正大學夕陽
EmguCV Image Process: Filtering the Images

參考OpenCV 2 Computer Vision Application Programming Cookbook第六章

介紹內容如下:

Filtering images using low-pass filters

Eiltering images using a median filter

Applying directional filters to detect edges

Computing the Laplacian of an image

上一篇介紹到Sobel filter

這裡來看看Sobel filter的一些原理

Sobel operator是用來做邊緣偵測的linear filter

基礎的3X3 kernel如下圖所示:


因此Sobel operator會計算影像在水平方向與垂直方向梯度的近似值

也就是用來量測影像中水平或是垂直方向的變化

透過這樣一個小的區塊,並移動到影像中每一個pixel去做計算

也因為在kernel中有負值

所以在計算後所產生的值就會有正有負

所計算出來的範圍遠遠超過一般影像儲存的格式的大小

所以在函式Sobel後的結果都是32位元深度的影像

那如果要轉換成熟悉的8位元深度

就必須採用上一篇所介紹的方法來實作了!!


而在kernel大小(apertureSize)的設定上

若是設定成1,則會以1X3或3X1的kernel來計算

而設定3、5、7,就是以3X3、5X5、7X7的kernel計算

而在xorder、yorder上的設定可以自己多方嘗試看看

一般的設定都是一個為0,另一個為1的方式設定

而在實作二值化時

閥值的選取也相當重要

閥值設定的太小,影像中就會包含太多細小的邊緣

但若是設定的太大,影像中偵測到的邊緣就可能出現斷裂的現象


而利用Sobel operator計算出來的結果

可以視為一個2D vector (2D向量),其中會有norm與direction (長度與方向)

前一篇所介紹兩張影像的絕對值相加的算法稱為:L1 norm

而向量的norm是以Euclidean norm來計算

以幾何意義來說就是賦予了這個向量有長度、距離的觀念

而Euclidean norm最簡單的公式就是:



也能透過三角函數求出夾角的角度:


而透過cvCartToPolar也就能幫你求出長度與角度

Image<Gray, Byte> image = new Image<Gray, Byte>("image.jpg");
//horizontal filter
Image<Gray, float> sobelX = image.Sobel(1, 0, 3);
//vertical filter
Image<Gray, float> sobelY = image.Sobel(0, 1, 3);
//angle image
Image<Gray, float> angle = new Image<Gray, float>(image.Width, image.Height);
//magnitude image
Image<Gray, float> magnitude = new Image<Gray, float>(image.Width, image.Height);
//Compute the L2 norm and direction of the gradient
CvInvoke.cvCartToPolar(sobelX, sobelY, magnitude, angle, true);
若是在cvCartToPolar最後的參數中帶入false

則計算出來是以radian (弧度)為單位

帶入true才會是以degree (角度)為單位

計算出來的結果會存到magnitude與angle這兩張影像中

magnitude存放的就是norm的值

angle存放的就是degree的值

而直接把出來的結果存成影像:

magnitude

angle


而利用kernel運算來達到邊緣偵測的方法還有很多種

像是Roberts operator 是建立在2X2的kernel上:


而Scharr operator 則可以更精確地計算出梯度的方向:


而利用之前所介紹的Sobel方法是可以使用Scharr operator來計算的

就是把apertureSize設為-1

//horizontal filter
Image<Gray, float> scharrX = image.Sobel(1, 0, -1);
//vertical filter
Image<Gray, float> scharrY = image.Sobel(0, 1, -1);

結果如下:

 scharrY

scharrX


在所有這些具有方向性的filters都試著計算first-order derivative(一階導數)

因此在影像中在亮度的灰階值中有大量的變化的區域會計算出比較大的值

而在亮度上比較平滑的區域則會計算出比較小的值

也就是為什麼當filters去計算影像的導數時會被稱為high-pass filters

而下一篇將介紹另一種邊緣偵測的方法:Laplacian operator

沒有留言:

張貼留言