Matlab渐变和OpenCV渐变给出不同的结果

时间:2015-02-11 07:44:14

标签: image matlab opencv image-processing gradient

我试图将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]

造成这种差异的原因是什么?先感谢您。

1 个答案:

答案 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);