OpenCV筆記(十四)——使用Sobel算子對圖像進行微分運算


1. 什么是Sobel算子

2. 為什么要對圖像做微分

3. 如何對圖像做微分

 

當我們要對圖像進行邊緣檢測的時候,我們注意到,在邊緣處像素的強度的變化率是很大的。而微分恰好是表示這種變化率的很好的方式。

在對圖像做微分的時候,我們也是對像素做卷積運算,而這里我們使用的kernel,就是Sobel算子。

在使用Sobel算子做微分的時候,我們計算行方向上的變化

G_{x} = \begin{bmatrix}
-1 & 0 & +1  \\
-2 & 0 & +2  \\
-1 & 0 & +1
\end{bmatrix} * I

和列方向上的變化,

G_{y} = \begin{bmatrix}
-1 & -2 & -1  \\
0 & 0 & 0  \\
+1 & +2 & +1
\end{bmatrix} * I

再對這兩個變化求平方和的開方,

G = \sqrt{ G_{x}^{2} + G_{y}^{2} }

或者絕對值相加

G = |G_{x}| + |G_{y}|

就得到一幅表現圖像邊緣的圖像。當然這樣的計算是結果是近似的而非精確的。

OpenCV提供了一種更快速而且更近似於精確值的方法,就是使用Scharr算子來代替Sobel算子,

G_{x} = \begin{bmatrix}
-3 & 0 & +3  \\
-10 & 0 & +10  \\
-3 & 0 & +3
\end{bmatrix}

G_{y} = \begin{bmatrix}
-3 & -10 & -3  \\
0 & 0 & 0  \\
+3 & +10 & +3
\end{bmatrix}

另外,Sobel算子一般與高斯平滑結合起來使用,所以我們得到的結果也稍微有些抵抗噪聲的效果。

 

OpenCV給出的實例代碼如下:

 1 int main( int, char** argv )
 2 {
 3 
 4   Mat src, src_gray;
 5   Mat grad;
 6   const char* window_name = "Sobel Demo - Simple Edge Detector";
 7   int scale = 1;
 8   int delta = 0;
 9   int ddepth = CV_16S;
10 
11   /// Load an image
12   src = imread( argv[1] );
13 
14   if( !src.data )
15     { return -1; }
16 
17   GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
18 
19   /// Convert it to gray
20   cvtColor( src, src_gray, COLOR_RGB2GRAY );
21 
22   /// Create window
23   namedWindow( window_name, WINDOW_AUTOSIZE );
24 
25   /// Generate grad_x and grad_y
26   Mat grad_x, grad_y;
27   Mat abs_grad_x, abs_grad_y;
28 
29   /// Gradient X
30   //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
31   Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
32   convertScaleAbs( grad_x, abs_grad_x );
33 
34   /// Gradient Y
35   //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
36   Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
37   convertScaleAbs( grad_y, abs_grad_y );
38 
39   /// Total Gradient (approximate)
40   addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
41 
42   imshow( window_name, grad );
43 
44   waitKey(0);
45 
46   return 0;
47 }

在第9行我們令ddepth為CV_16S,是因為我們在計算微分的過程中,值會超過0~255這一范圍。

在第32行和第37行,我們就把16位的mat轉換為8位的了。注意,這種轉換不是簡單地截取低8位的地址,而是取所能表示的最大值。如1024,則被轉換為255,如-128,則被轉換為0。而0到255之間的不變。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM