3

My image

If I have an image and call the OpenCV Sobel function with

Sobel(Img,gradX,CV_16S,1,0,3);
convertScaleAbs(gradX,absGradX);
imshow("Gradient Image",absGradX);

I get a nice gradient image

I would like to use filter2D with a custom kernel to calculate my x gradient. My sobel kernel is 1 0 -1 2 0 -2 1 0 -1 now when I try this I am getting just an all black image

float  xVals[9] = {.125,0,-.125,.25,0,-.25,.125,0,-.125};
Mat xKernel = Mat(3,3,CV_32F,xVals);
Mat gradXManual,absGradXManual;
filter2D(Img,gradXManual,-1,xKernel,Point(-1,-1),0,BORDER_DEFAULT);
convertScaleAbs(gradXManual,absGradXManual);
imshow("Manual Gradient",absGradXManual);

Resulting gradient image is all black. Any ideas what I'm doing wrong? Thanks

7
  • 1
    Using your custom kernel, I get an output. Can you place what image you're using here? However, I'm using Python OpenCV, but the way to invoke the functions is practically the same as the C++ version. I used a test image I have and I get an output from both Sobel and your custom kernel. Commented Aug 20, 2014 at 0:51
  • Interesting, I did not get anything with the custom kernel. I've edited my post to include the image I used. Commented Aug 20, 2014 at 1:08
  • I'll check now. Give me one moment. Commented Aug 20, 2014 at 1:13
  • 1
    The main difference I see between the Sobel implementation and your gradient is the fact that you took the Sobel kernel by divided each element by 8. As such, any gradients you detect, you'll get a contrast reduction and that's what I see. Actually, you are basically taking the gradient result and dividing by 8 and so you are reducing the intensities of the output by a factor of 8. Try doing: float xVals[9] = {1f,0f,-1f,2f,0f,-2f,1f,0f,-1f}; the actual Sobel kernel, then run your code again. You should see a higher boost in contrast. Commented Aug 20, 2014 at 1:16
  • Ah, you are right. I was normalizing which was reducing contrast too much. Thanks! Commented Aug 20, 2014 at 1:29

1 Answer 1

3

I actually got an output from the custom kernel that you have created. I used Python OpenCV to do this, but the way of calling the functions in OpenCV are pretty much the same. To be self-contained, this is the Python code I called for your image using the Sobel and your custom kernel:

import cv2
import numpy as np
im = cv2.imread('Nj9fM.png'); #// Save image to computer first

#// Call using built-in Sobel
out1 = cv2.Sobel(im, cv2.CV_16S, 0, 1, 3)
out1 = cv2.convertScaleAbs(out1.copy())

#// Create custom kernel
xVals = np.array([0.125,0,-0.125,0.25,0,-0.25,0.125,0,-0.125]).reshape(3,3)

#// Call filter2D
out2 = cv2.filter2D(im, cv2.CV_32F, xVals, None, (-1,-1), 0, cv2.BORDER_DEFAULT)
out2 = cv2.convertScaleAbs(out2.copy())

cv2.imshow('Output 1', out1)
cv2.imshow('Output 2', out2)
cv2.waitKey(0)
cv2.destroyAllWindows()

In terms of C++:

#include <opencv2/opencv.hpp>
using namespace cv;

int main(int argc, char* argv[])
{
    Mat im = imread("Nj9fM.png", CV_LOAD_IMAGE_COLOR); // Save image to computer first

    // Call using built-in Sobel
    Mat out1, out2;
    Sobel(img, out1, CV_16S, 1, 0, 3);
    convertScaleAbs(out1, out2);

    // Create custom kernel
    Mat xVals = Mat_<float>(3, 3) << 0.125, 0, -0.125, 0.25, 0, -0.25, 0.125, 0, -0.125;

    // Call filter2D
    filter2D(im, out2, -1, xVals, Point(-1,-1), 0 ,BORDER_DEFAULT);
    convertScaleAbs(out2, out2);

    imshow("Output 1", out1);
    imshow("Output 2", out1);
    waitKey(0);
    destroyWindow("Output 1");
    destroyWindow("Output 2");
}

If you run this code, you'll actually see both images where the first one uses the built-in Sobel, while the other one uses your custom kernel. The main difference I see between the Sobel implementation and your gradient is the fact that you took the Sobel kernel by divided each element by 8. As such, any gradients you detect, you'll get a contrast reduction and that's what I see. Actually, you are basically taking the gradient result and dividing by 8 and so you are reducing the intensities of the output by a factor of 8. Try doing: float xVals2[9] = {1f,0f,-1f,2f,0f,-2f,1f,0f,-1f}; the actual Sobel kernel, then run your code again. You should see a higher boost in contrast. For Python, this would be:

xVals2 = np.array([1.,0.,-1.,2.,0,-2.,1.,0,-1.]).reshape(3,3)

Also in C++:

Mat xVals2 = Mat_<float>(3, 3) << 1f, 0f, -1f, 2f, 0f, -2f, 1f, 0f, -1f;

If you run your code using this kernel, you'll see that there's a higher contrast. You'll see that there is more noise though, as the gradient values are larger.

Sign up to request clarification or add additional context in comments.

1 Comment

By dividing the Sobel kernel by 8 you get correct estimates of the derivative.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.