If I apply a Sobel filter to an image in Python using scipy.ndimage.filters.convole
I get meaningful results, for example, for this simple input image img
0 255 0
0 255 0
0 255 0
the convolution
dimage.filters.convolve(img, Kx)
with Kx
-1 0 1
-2 0 2
-1 0 1
returns a meaningful gradient in x-direction:
-1020 0 1020
-1020 0 1020
-1020 0 1020
I don't know how to get a equivalent result using openCV2 in C++ though. When I define the input image by
int image_data[9] = {0, 255, 0, 0, 255, 0, 0, 255, 0};
cv::Mat image = cv::Mat(3, 3, CV_32F, image_data);
and apply the kernel by
cv::Mat gradientx;
double sobelx_data[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
cv::Mat sobelx = cv::Mat(3, 3, CV_32F, sobelx_data);
cv::filter2D(image, gradientx, -1, sobelx);
I get the following result from
for(int row=0; row<gradientx.rows; row++) {
for(int col=0; col<gradientx.cols; col++) {
std::cout << gradientx.at<int>(row,col) << std::endl;
}
}
it returns the following image
478 -2147482660 478
478 -2147482660 478
478 -2147482660 478
There seems to be an overflow problem, but I don't know why. Trying to get values from gradientx.at<double>(row,col)
produces
-1.68911e-311 8.10602e-312 8.11663e-312
-1.68911e-311 8.10602e-312 8.11663e-312
-1.68911e-311 2.122e-314 8.54412e-72
Can someone tell me why this is? Isn't filter2D
supposed to do a 2D convolution on the image, and why do I get weird values when addressing the output pixels with <double>
? Thank you.
Okay, here's your code with the types corrected (I've also added more parameters to filter2D
):
float image_data[9] = {0, 255, 0, 0, 255, 0, 0, 255, 0};
cv::Mat image = cv::Mat(3, 3, CV_32F, image_data);
std::cout << "image = " << std::endl << image << std::endl;
cv::Mat gradientx;
float sobelx_data[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
cv::Mat sobelx = cv::Mat(3, 3, CV_32F, sobelx_data);
std::cout << "sobelx = " << std::endl << sobelx << std::endl;
cv::filter2D(image, gradientx, -1, sobelx, cv::Point(-1, -1), 0,
cv::BORDER_DEFAULT);
std::cout << "gradientx = " << std::endl << gradientx << std::endl;
The result is:
image =
[0, 255, 0;
0, 255, 0;
0, 255, 0]
sobelx =
[-1, 0, 1;
-2, 0, 2;
-1, 0, 1]
gradientx =
[0, 0, 0;
0, 0, 0;
0, 0, 0]
If you look at the top of the documentation page on filtering , you'll see all of the border types that OpenCV uses. By default, filter2D
uses BORDER_REFLECT_101
. This is probably not what we want, so let's change it to BORDER_REPLICATE
.
cv::filter2D(image, gradientx, -1, sobelx, cv::Point(-1, -1), 0,
cv::BORDER_REPLICATE);
Result:
image =
[0, 255, 0;
0, 255, 0;
0, 255, 0]
sobelx =
[-1, 0, 1;
-2, 0, 2;
-1, 0, 1]
gradientx =
[1020, 0, -1020;
1020, 0, -1020;
1020, 0, -1020]
That's better, but the values are flipped. If you look at the bottom of the function description for filter2D
you'll see that it actually computes the cross correlation rather than the convolution. So we need to flip the kernel to get the correct results.
cv::Mat sobelxflip;
cv::flip(sobelx, sobelxflip, -1);
cv::filter2D(image, gradientx, -1, sobelxflip, cv::Point(-1, -1), 0,
cv::BORDER_REPLICATE);
std::cout << "gradientx = " << std::endl << gradientx << std::endl;
Result:
gradientx =
[-1020, 0, 1020;
-1020, 0, 1020;
-1020, 0, 1020]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.