OpenCV笔记(十四)——使用Sobel算子对图像进行微分运算
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之间的不变。