注意
下面的解释属于Bradski和Kaehler 的“ 学习OpenCV ”一书。
你可以很容易地注意到,在边缘,像素强度以臭名昭着的方式发生变化。表达变化的一个好方法是使用衍生工具。梯度的高变化表示图像的重大变化。
公式
假设要运行的图像是:I
虽然有时使用以下简单的方程:
注意
当内核的大小是3
,上面显示的Sobel内核可能会产生明显的不准确(毕竟Sobel只是导数的近似值)。OpenCV通过使用cv :: Scharr函数解决了大小为3的内核的不精确性。这与标准的Sobel功能一样快,但更准确。它实现以下内核:
您可以在OpenCV参考(cv :: Scharr)中查看此功能的更多信息。此外,在下面的示例代码中,您会注意到,在cv :: Sobel函数的代码之上,还有一个注释的cv :: Scharr函数的代码。取消注释(并且显然评论Sobel的内容)应该给你一个这个功能如何工作的想法。
#include
#include
using namespace cv;
int main(int argc, char** argv) {
Mat src = imread("C:/usr/opencv-test/Testpictures/sight.jpg"); // by default
Mat dst, gray_src;
if (src.empty())
{
printf("image load failed!\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
GaussianBlur(src, dst, Size(3, 3), 0, 0); //高斯模糊,使平滑
cvtColor(dst, gray_src, CV_BGR2GRAY); //转为灰度
//Sobel求x,y梯度
Mat grad_x, grad_y, grad_xy;
//Sobel(gray_src, grad_x, CV_16S, 1, 0, 3); //经典Sobel算子
//Sobel(gray_src, grad_y, CV_16S, 0, 1, 3);
Scharr(gray_src, grad_x, CV_16S, 1, 0, 3); //改进Sobel算子
Scharr(gray_src, grad_y, CV_16S, 0, 1, 3);
convertScaleAbs(grad_x, grad_x); //可能为负,取绝对值,确保显示
convertScaleAbs(grad_y, grad_y);
addWeighted(grad_x, 0.5, grad_y, 0.5, 0, grad_xy); //混合x,y梯度
imshow("grad_xy", grad_xy);
//imshow("output image", gray_src);
waitKey(0);
return 0;
}
Mat src, src_gray; Mat grad; const char* window_name = "Sobel Demo - Simple Edge Detector"; int scale = 1; int delta = 0; int ddepth = CV_16S;
String imageName("../data/lena.jpg"); // by default if (argc > 1) { imageName = argv[1]; } src = imread( imageName, IMREAD_COLOR ); // Load an image if( src.empty() ) { return -1; }
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
cvtColor(src,src_gray,COLOR_BGR2GRAY);
Mat grad_x, grad_y; Mat abs_grad_x, abs_grad_y; //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT ); Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT ); Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
该函数采用以下参数:
请注意,为了计算x方向的梯度,我们使用: 。我们以y方式做类似的事情。
convertScaleAbs(grad_x,abs_grad_x); convertScaleAbs(grad_y,abs_grad_y);
最后,我们试图接近梯度通过将两个方向的梯度(注意,这是不是在所有的精确计算!但它有利于我们的目的)。
addWeighted(abs_grad_x,0.5,abs_grad_y,0.5,0,grad);
最后,我们展示我们的结果:
imshow(window_name,grad);
waitKey(0);
这是将我们的基本检测器应用于sight.jpg的输出: