OpenCV中的Matlab渐变等效项

Matlab gradient equivalent in opencv

我正在尝试将一些代码从Matlab迁移到Opencv,并且需要渐变函数的精确副本。 我尝试了cv :: Sobel函数,但是由于某种原因,结果cv :: Mat中的值与Matlab版本中的值不同。 我需要在单独的矩阵中进行X和Y渐变以进行进一步的计算。

可以实现此目标的任何变通办法都很好


Sobel只能计算图像像素的二阶导数,这不是我们想要的。

(f(i+1,j) + f(i-1,j) - 2f(i,j)) / 2

我们想要的是

(f(i+i,j)-f(i-1,j)) / 2

所以我们需要申请

1
2
3
4
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将边框像素与内部像素区别对待。因此,上面的代码在边框值处是错误的。可以使用BORDER_CONSTANT将边界值扩展为一个常数,不幸的是,OpenCV将该常数设为-1,并且不能将其更改为0(这就是我们想要的)。

关于边界值,我对此没有一个很好的答案。只需尝试手动计算一阶导数...


Jorrit的答案部分正确。
在某些情况下,方向导数的值可能为负,MATLAB将保留这些负数,但是OpenCV Mat会将负数设置为0。


贝i铭的回答部分正确。 Matlab将这些计算用于边界:

G(:,1) = A(:,2) - A(:,1);
G(:,N) = A(:,N) - A(:,N-1);

因此,使用以下opencv代码完成渐变:

1
2
3
4
5
6
7
8
9
10
11
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;

Matlab对于内部行和边界行计算梯度的方式有所不同(当然,对于列也是如此)。在边界处,这是一个简单的前向差异gradY(1) = row(2) - row(1)。内部行的梯度由中心差gradY(2) = (row(3) - row(1)) / 2计算。

我认为仅在OpenCV的整个矩阵上运行单个卷积滤波器就无法获得相同的结果。将cv::Sobel()ksize = 1结合使用,然后处理边框(手动或通过应用[1 -1]滤镜)。


您必须使用参数调用Sobel 2次:

1
xorder = 1, yorder = 0

1
xorder = 0, yorder = 1

您必须选择适当的内核大小。

查看文件

MatLab实现可能仍然是不同的,理想情况下,您应该检索在那里使用的内核...

编辑:

如果需要指定自己的内核,则可以使用更通用的filter2D。您的目标深度将为CV_16S(16位带符号)。