Matlab gradient equivalent in opencv
I am trying to migrate some code from Matlab to Opencv and need an exact replica of the gradient function. I have tried the cv::Sobel function but for some reason the values in the resulting cv::Mat are not the same as the values in the Matlab version. I need the X and Y gradient in separate matrices for further calculations.
Any workaround that could achieve this would be greatАвтор: Arpan Shah Источник Размещён: 12.11.2019 09:56
Sobel can only compute the second derivative of the image pixel which is not what we want.
(f(i+1,j) + f(i-1,j) - 2f(i,j)) / 2
What we want is
(f(i+i,j)-f(i-1,j)) / 2
So we need to apply
Mat kernelx = (Mat_<float>(1,3)<<-0.5, 0, 0.5); Mat kernely = (Mat_<float>(3,1)<<-0.5, 0, 0.5); filter2D(src, fx, -1, kernelx) filter2D(src, fy, -1, kernely);
Matlab treats border pixels differently from inner pixels. So the code above is wrong at the border values. One can use BORDER_CONSTANT to extent the border value out with a constant number, unfortunately the constant number is -1 by OpenCV and can not be changed to 0 (which is what we want).
So as to border values, I do not have a very neat answer to it. Just try to compute the first derivative by hand...Автор: Pei Guo Размещён: 07.02.2014 08:34
You have to call Sobel 2 times, with arguments:
xorder = 1, yorder = 0
xorder = 0, yorder = 1
You have to select the appropriate kernel size.
It might still be that the MatLab implementation was different, ideally you should retrieve which kernel was used there...
If you need to specify your own kernel, you can use the more generic filter2D. Your destination depth will be CV_16S (16bit signed).Автор: Antonio Размещён: 31.07.2013 10:01
Matlab computes the gradient differently for interior rows and border rows (the same is true for the columns of course). At the borders, it is a simple forward difference
gradY(1) = row(2) - row(1). The gradient for interior rows is computed by the central difference
gradY(2) = (row(3) - row(1)) / 2.
I think you cannot achieve the same result with just running a single convolution filter over the whole matrix in OpenCV. Use
ksize = 1, then treat the borders (either manually or by applying a [ 1 -1 ] filter).
Pei's answer is partly correct. Matlab uses these calculations for the borders:
G(:,1) = A(:,2) - A(:,1); G(:,N) = A(:,N) - A(:,N-1);
so used the following opencv code to complete the gradient:
Автор: Jorrit Smit Размещён: 23.05.2017 03:16
static cv::Mat kernelx = (cv::Mat_<double>(1, 3) << -0.5, 0, 0.5); static cv::Mat kernely = (cv::Mat_<double>(3, 1) << -0.5, 0, 0.5); cv::Mat fx, fy; cv::filter2D(Image, fx, -1, kernelx, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE); cv::filter2D(Image, fy, -1, kernely, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE); fx.col(fx.cols - 1) *= 2; fx.col(0) *= 2; fy.row(fy.rows - 1) *= 2; fy.row(0) *= 2;
Jorrit's answer is partly correct. In some cases, the value of the directional derivative may be negative, and MATLAB will retain these negative numbers, but OpenCV Mat will set the negative number to 0.Автор: Harry Lee Размещён: 17.01.2019 01:40