我试图将Matlab代码转换为OpenCV,它执行输入图像的渐变计算。但是对于完全相同的输入图像,结果矩阵是不同的。
以下是我要转换的Matlab代码:
gradientsigma = 1;
sze = fix(6*gradientsigma); if ~mod(sze, 2); sze = sze + 1; end
f = fspecial('gaussian', sze, gradientsigma); % Generate Gaussian filter
[fx, fy] = gradient(f); % Gradient of Gaussian
Gx = filter2(fx, im); %Gradient of the image in x
Gy = filter2(fy, im); % ... and y
这是我写的OpenCV代码:
cv::Mat grad_x, grad_y;
cv::Sobel(im, grad_x, CV_32FC1, 1, 0, 3, 1, 0, cv::BORDER_DEFAULT);
cv::Sobel(im, grad_y, CV_32FC1, 0, 1, 3, 1, 0, cv::BORDER_DEFAULT);
然而,Gx的输出是这样的:
% first four pixels
[-27.1851 -13.4271 -3.9532 -0.0000 ... ]
% last four pixels
[... -1.7701 2.3386 12.1671 26.4513]
这是grad_x的输出:
// first four pixels
[0, 0, 0, 0 ...]
// last four pixels
[... 20, 18, 14, 0]
造成这种差异的原因是什么?先感谢您。
答案 0 :(得分:5)
Matlab的梯度算法在某种程度上与Sobel滤波不同。有关用于Matlab的详细算法,请查看here。
因此,您可以在OpenCV中轻松实现该算法,如下所示:
//image is your input image, I assume it is of float type
//xGradient is the gradient output calculated along x-direction
//yGradient is the gradient output calculated along y-direction
void gradient(cv::Mat image, cv::Mat xGradient, cv::Mat yGradient)
{
int rows = image.rows;
int cols = image.cols;
float xGrad = 0.0;
float yGrad = 0.0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (j == 0)
{
xGrad = image.at<float>(i, j + 1) - image.at<float>(i, j);
}
else if (j == cols - 1)
{
xGrad = image.at<float>(i, j) - image.at<float>(i, j - 1);
}
else
{
xGrad = 0.5 * (image.at<float>(i, j + 1) - image.at<float>(i, j - 1));
}
if (i == 0)
{
yGrad = image.at<float>(i + 1, j) - image.at<float>(i, j);
}
else if (i == rows - 1)
{
yGrad = image.at<float>(i, j) - image.at<float>(i - 1, j);
}
else
{
yGrad = 0.5 * (image.at<float>(i + 1, j) - image.at<float>(i - 1, j));
}
xGradient.at<float>(i, j) = xGrad;
yGradient.at<float>(i, j) = yGrad;
} // end of j- loop
} // end of i-loop
} // end of gradient function definition
这给出了与Matlab梯度函数完全相同的结果。请记住,Matlab会对结果进行舍入。例如,如果你得到0.00008562
&#39;在OpenCV中,这显示为&#39; 0.0001
&#39;在Matlab中。现在针对您的情况,您可以像这样使用它:
int sze = 6 * round(gradientsigma);
if (sze % 2 == 0)
{
sze += 1;
}
//Generate Gaussian filter
cv::Mat gaussKernelX = cv::getGaussianKernel(sze, gradientsigma, CV_32FC1);
cv::Mat gaussKernelY = cv::getGaussianKernel(sze, gradientsigma, CV_32FC1);
cv::Mat gaussKernel = gaussKernelX * gaussKernelY.t();
cv::Mat fx, fy;
cv::Mat kernelx = (cv::Mat_<float>(1, 3) << -0.5, 0, 0.5);
cv::Mat kernely = (cv::Mat_<float>(3, 1) << -0.5, 0, 0.5);
cv::filter2D(gaussKernel, fx, -1, kernelx);
cv::filter2D(gaussKernel, fy, -1, kernely);
gradient(gaussKernel, fx, fy); // Gradient of Gaussian
cv::Mat grad_x = cv::Mat::zeros(im.size(), CV_32FC1);
cv::Mat grad_y = cv::Mat::zeros(im.size(), CV_32FC1);
//Gradient of the image in x direction
cv::filter2D(im, grad_x, -1, fx, cv::Point(-1, -1), 0, cv::BORDER_DEFAULT);
//Gradient of the image in y direction
cv::filter2D(im, grad_y, -1, fy, cv::Point(-1, -1), 0, cv::BORDER_DEFAULT);