Matlab gradient equivalent in opencv

matlab opencv gradient derivative

3912 просмотра

5 ответа

98 Репутация автора

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 Источник Размещён: 31.07.2013 06:18

Ответы (5)


0 плюса

12722 Репутация автора

You have to call Sobel 2 times, with arguments:

xorder = 1, yorder = 0

and

xorder = 0, yorder = 1

You have to select the appropriate kernel size.

See documentation

It might still be that the MatLab implementation was different, ideally you should retrieve which kernel was used there...

Edit:

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

0 плюса

132 Репутация автора

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 cv::Sobel() with ksize = 1, then treat the borders (either manually or by applying a [ 1 -1 ] filter).

Автор: Atze Kaputtnik Размещён: 08.10.2013 07:50

5 плюса

69 Репутация автора

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

0 плюса

51 Репутация автора

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:

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 Smit Размещён: 23.05.2017 03:16

0 плюса

1 Репутация автора

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
Вопросы из категории :
32x32