該文章轉載於:http://blog.csdn.net/hitwengqi/article/details/6877638
cvSobel可用於邊緣檢測,即簡單的梯度算法(邊緣提取算法)。
(以下兩段摘自網絡)
首先,我們來開一下計算機是如何檢測邊緣的。以灰度圖像爲例,它的理論基礎是這樣的,如果出現一個邊緣,那麼圖像的灰度就會有一定的變化,爲了方便假設由黑漸變爲白代表一個邊界,那麼對其灰度分析,在邊緣的灰度函數就是一個一次函數y=kx,對其求一階導數就是其斜率k,就是說邊緣的一階導數是一個常數,而由於非邊緣的一階導數爲零,這樣通過求一階導數就能初步判斷圖像的邊緣了。通常是X方向和Y方向的導數,也就是梯度。理論上計算機就是通過這種方式來獲得圖像的邊緣。
但是,具體應用到圖像中你會發現這個導數是求不了的,因爲沒一個準確的函數讓你去求導,而且計算機在求解析解要比求數值解麻煩得多,所以就想到了一種替代的方式來求導數。就是用一個3×3的窗口來對圖像進行近似求導。拿對X方向求導爲例,某一點的導數爲第三行的元素之和減去第一行元素之和,這樣就求得了某一點的近似導數。其實也很好理解爲什麼它就近似代表導數,導數就代表一個變化率,從第一行變爲第三行,灰度值相減,當然就是一個變化率了。這就是所謂的Prewitt算子。這樣近似X方向導數就求出來了。Y方向導數與X方向導數求法相似,只不過是用第三列元素之和減去第一列元素之和。X方向和Y方向導數有了,那麼梯度也就出來了。這樣就可以找出一幅圖中的邊緣了。 還有一個問題,由於求的是3×3中心點的導數,所以給第二列加了一個權重,它的權重爲2,第一列和第三列的權重爲1,好了,這就是Sobel算子了。相比Prewitt算子,Sobel的抗噪能力更強。如圖所示:這樣,中心點的X方向導數就求出來了。
舉個例子吧。,X點以Sobel方式求導數ΔX=1×50+2×30+1×50-(1×50+2×30+1×50)=0。這樣可以看出這個點不是邊界。
--------------------------------------------------------------------------------------------------
該函數如下:
Sobel
使用擴展 Sobel 算子計算一階、二階、三階或混合圖像差分
void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );
- src
- 輸入圖像.
- dst
- 輸出圖像.
- xorder
- x 方向上的差分階數
- yorder
- y 方向上的差分階數
- aperture_size
- 擴展 Sobel 核的大小,必須是 1, 3, 5 或 7。 除了尺寸爲 1, 其它情況下, aperture_size ×aperture_size 可分離內核將用來計算差分。對 aperture_size=1的情況, 使用 3x1 或 1x3 內核 (不進行高斯平滑操作)。這裏有一個特殊變量 CV_SCHARR (=-1),對應 3x3 Scharr 濾波器,可以給出比 3x3 Sobel 濾波更精確的結果。Scharr 濾波器係數是:
- 對 x-方向 或矩陣轉置後對 y-方向。
函數 cvSobel 通過對圖像用相應的內核進行卷積操作來計算圖像差分:
由於Sobel 算子結合了 Gaussian 平滑和微分,所以,其結果或多或少對噪聲有一定的魯棒性。通常情況,函數調用採用如下參數 (xorder=1, yorder=0, aperture_size=3) 或 (xorder=0, yorder=1, aperture_size=3) 來計算一階 x- 或 y- 方向的圖像差分。第一種情況對應:
核。
第二種對應:
或者
核的選則依賴於圖像原點的定義 (origin 來自 IplImage 結構的定義)。由於該函數不進行圖像尺度變換,所以和輸入圖像(數組)相比,輸出圖像(數組)的元素通常具有更大的絕對數值(譯者注:即像素的位深)。爲防止溢出,當輸入圖像是 8 位的,要求輸出圖像是 16 位的。當然可以用函數 cvConvertScale 或 cvConvertScaleAbs 把運算結果(dst)轉換爲 8 位的。除了8-位圖像,函數也接受 32-位 浮點數圖像。所有輸入和輸出圖像都必須是單通道的,並且具有相同的圖像尺寸或者ROI尺寸。
--------------------------------------------------------------------------------------------------/*code*/
- #include <highgui.h>
- #include <cv.h>
- int main(int argc, char ** argv)
- {
- IplImage* src, *dst;
- src = cvLoadImage( argv[1] );
- dst = cvCreateImage( cvGetSize( src ), IPL_DEPTH_16S, 3 );
- //這裏有錯誤,應該再將dst轉爲灰度,再送去sobel處理
- cvNamedWindow( "src", 0 );
- cvShowImage( "src", src );
- cvNamedWindow( "sobel", 0 );
- cvSobel( src, dst, 0, 1, 7 ); //sobel
- cvShowImage( "sobel", dst );
- cvWaitKey(0);
- cvReleaseImage( &src );
- cvReleaseImage( &dst );
- return 0;
- }
--------------------------------------------------------------------------------------------------
/*result*/after sobel
aperture_size == 7.