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

E_l*_*ner 3 matlab opencv gradient image image-processing

我正在尝试将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
Run Code Online (Sandbox Code Playgroud)

这是我写的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);
Run Code Online (Sandbox Code Playgroud)

但是,Gx的输出是这样的:

% first four pixels
[-27.1851  -13.4271   -3.9532   -0.0000 ... ]
% last four pixels
[... -1.7701    2.3386   12.1671   26.4513]
Run Code Online (Sandbox Code Playgroud)

这是grad_x的输出:

// first four pixels
[0, 0, 0, 0 ...]
// last four pixels
[... 20, 18, 14, 0]
Run Code Online (Sandbox Code Playgroud)

是什么造成了这种差异 先感谢您.

Der*_*man 5

Matlab的梯度算法在某种程度上与Sobel滤波不同.有关用于Matlab的详细算法,请查看此处.

因此,您可以在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
Run Code Online (Sandbox Code Playgroud)

这给出了与Matlab梯度函数完全相同的结果.请记住,Matlab会对结果进行舍入.例如,如果你0.00008562在OpenCV中得到',那么它0.0001在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); 
Run Code Online (Sandbox Code Playgroud)