1. 什么是Sobel算子
2. 為什么要對圖像做微分
3. 如何對圖像做微分
當我們要對圖像進行邊緣檢測的時候,我們注意到,在邊緣處像素的強度的變化率是很大的。而微分恰好是表示這種變化率的很好的方式。
在對圖像做微分的時候,我們也是對像素做卷積運算,而這里我們使用的kernel,就是Sobel算子。
在使用Sobel算子做微分的時候,我們計算行方向上的變化
和列方向上的變化,
再對這兩個變化求平方和的開方,
或者絕對值相加
就得到一幅表現圖像邊緣的圖像。當然這樣的計算是結果是近似的而非精確的。
OpenCV提供了一種更快速而且更近似於精確值的方法,就是使用Scharr算子來代替Sobel算子,
另外,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之間的不變。