Ask Your Question
0

matlab gradient() to C++

asked 2013-07-09 07:42:46 -0600

carlosb gravatar image

updated 2013-07-09 08:45:46 -0600

Hello,

I am trying to port the method gradient (Matlab) to C++ with OpenCV:

I tested this in matlab:

Input:

 A =
 1     3
 4     2

[dx dy] = gradient(A, 4, 4)

Output:

dx =
0.5000    0.5000
-0.5000   -0.5000
dy =
0.7500   -0.2500
0.7500   -0.2500

I followed this example :

And I implemented this code:

float A[2][2] = {{1.0,3.0},{4.0,2.0}};
Mat src_grad = Mat(2,2,CV_32F,A);

Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
Mat grad;

/// Gradient X
Sobel( src_grad, grad_x, CV_32F, 1, 0);
convertScaleAbs( grad_x, abs_grad_x );

/// Gradient Y
Sobel( src_grad, grad_y, CV_32F, 0, 1);
convertScaleAbs( grad_y, abs_grad_y );

/// Total Gradient (approximate)
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );

But grad doesn't have the same result. The problem is in the gradient method and its second and third parameter ( gradient(A,4,4)) which specify the 'spacing'. Is it correct this code? How I can specify this spacing in this example?

Update

gradient(A,4,4). These 4s are used to specify the kernel size to calculate the derivative for each number.

It was returning matrices with values to 0. I tested a matrix 3x3 (because Sober works with a ksize=3) and now, I returns values !=0...

edit retag flag offensive close merge delete

2 answers

Sort by » oldest newest most voted
1

answered 2013-10-03 18:10:57 -0600

carlosb gravatar image

I implemented a custom function to not use the Sobel operation and emulate the gradient operation, it works:

pair<Mat,Mat> gradient(Mat & img, float spaceX, float spaceY) {

    Mat gradY = gradientY(img,spaceY);
    Mat gradX = gradientX(img,spaceX);
    pair<Mat,Mat> retValue(gradX,gradY);
    return retValue;
}

/// Internal method to get numerical gradient for x components. 
/// @param[in] mat Specify input matrix.
/// @param[in] spacing Specify input space.
static Mat gradientX(Mat & mat, float spacing) {
    Mat grad = Mat::zeros(mat.cols,mat.rows,CV_32F);

    /*  last row */
    int maxCols = mat.cols;
    int maxRows = mat.rows;

    /* get gradients in each border */
    /* first row */
    Mat col = (-mat.col(0) + mat.col(1))/(float)spacing;
    col.copyTo(grad(Rect(0,0,1,maxRows)));

    col = (-mat.col(maxCols-2) + mat.col(maxCols-1))/(float)spacing;
    col.copyTo(grad(Rect(maxCols-1,0,1,maxRows)));

    /* centered elements */
    Mat centeredMat = mat(Rect(0,0,maxCols-2,maxRows));
    Mat offsetMat = mat(Rect(2,0,maxCols-2,maxRows));
    Mat resultCenteredMat = (-centeredMat + offsetMat)/(((float)spacing)*2.0);

    resultCenteredMat.copyTo(grad(Rect(1,0,maxCols-2, maxRows)));
    return grad;
}

/// Internal method to get numerical gradient for y components. 
/// @param[in] mat Specify input matrix.
/// @param[in] spacing Specify input space.
static Mat gradientY(Mat & mat, float spacing) {
    Mat grad = Mat::zeros(mat.cols,mat.rows,CV_32F);

    /*  last row */
    const int maxCols = mat.cols;
    const int maxRows = mat.rows;

    /* get gradients in each border */
    /* first row */
    Mat row = (-mat.row(0) + mat.row(1))/(float)spacing;
    row.copyTo(grad(Rect(0,0,maxCols,1)));

    row = (-mat.row(maxRows-2) + mat.row(maxRows-1))/(float)spacing;
    row.copyTo(grad(Rect(0,maxRows-1,maxCols,1)));

    /* centered elements */
    Mat centeredMat = mat(Rect(0,0,maxCols,maxRows-2));
    Mat offsetMat = mat(Rect(0,2,maxCols,maxRows-2));
    Mat resultCenteredMat = (-centeredMat + offsetMat)/(((float)spacing)*2.0);

    resultCenteredMat.copyTo(grad(Rect(0,1,maxCols, maxRows-2)));
    return grad;
}
edit flag offensive delete link more
0

answered 2014-03-20 10:29:31 -0600

mg1906 gravatar image

updated 2014-03-20 10:32:14 -0600

Hey Carlos, I'm using your code but I want to compare the results with the ones I obtained using MATLAB. In my main function, I have:

int i, k;
Mat img;
pair<Mat,Mat> grad;
img = imread("path_to_folder", CV_LOAD_IMAGE_COLOR);
img.convertTo(img, CV_64F); //Convert image to double precision (in MATLAB we have to use im2double before calling the gradient function)
grad = gradient(img, 1.0, 1.0);
Mat_<double> gradX = grad.first;
for(i=0; i<gradX.rows; i++) {
    for(k=0; k<gradX.cols; k++) {
       cout << gradX[i][k] << " ";
    }
    cout << endl;
}

But I get an error when I run the code (when I try to print the values). What am I doing wrong? I know this is an easy question but I just started to develop code in c++ a few days ago. Thanks for your help.

edit flag offensive delete link more

Question Tools

Stats

Asked: 2013-07-09 07:42:46 -0600

Seen: 4,352 times

Last updated: Mar 20 '14