3

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

任何可以实现这一点的解决方法都会很棒

4

5 回答 5

6

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

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

我们想要的是

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

所以我们需要申请

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(这是我们想要的)。

至于边界值,我没有一个非常简洁的答案。只需尝试手动计算一阶导数...

于 2014-02-07T08:34:55.590 回答
0

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).

于 2013-07-31T22:01:38.903 回答
0

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

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

于 2013-10-08T19:50:21.467 回答
0

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

于 2019-01-17T01:40:34.507 回答
0

裴的回答部分正确。Matlab 使用这些计算来计算边界:

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

所以使用下面的opencv代码来完成渐变:

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;
于 2017-05-23T15:16:59.650 回答