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对于内部行和边界行计算梯度的方式有所不同(当然,对于列也是如此)。在边界处,这是一个简单的前向差异
我认为仅在OpenCV的整个矩阵上运行单个卷积滤波器就无法获得相同的结果。将
您必须使用参数调用Sobel 2次:
1 | xorder = 1, yorder = 0 |
和
1 | xorder = 0, yorder = 1 |
您必须选择适当的内核大小。
查看文件
MatLab实现可能仍然是不同的,理想情况下,您应该检索在那里使用的内核...
编辑:
如果需要指定自己的内核,则可以使用更通用的filter2D。您的目标深度将为CV_16S(16位带符号)。