Matlab梯度和OpenCV梯度给出不同的结果
Matlab gradient and OpenCV gradient give different results
我正在尝试将 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]
是什么造成了这种差异?先感谢您。
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 会四舍五入结果。例如,如果您在 OpenCV 中得到“0.00008562
”,这在 Matlab 中显示为“0.0001
”。现在对于你的情况,你可以这样使用它:
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);
我正在尝试将 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]
是什么造成了这种差异?先感谢您。
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 会四舍五入结果。例如,如果您在 OpenCV 中得到“0.00008562
”,这在 Matlab 中显示为“0.0001
”。现在对于你的情况,你可以这样使用它:
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);