简体   繁体   English

在C ++中通过OpenCV应用内核

[英]Applying a kernel with OpenCV in C++

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 如果我使用scipy.ndimage.filters.convole将Sobel滤镜应用于Python中的图像,例如,对于此简单的输入图像img ,我将获得有意义的结果。

0 255 0
0 255 0
0 255 0

the convolution 卷积

dimage.filters.convolve(img, Kx)

with Kx Kx

-1 0 1
-2 0 2
-1 0 1

returns a meaningful gradient in x-direction: 在x方向上返回有意义的渐变:

-1020 0 1020
-1020 0 1020
-1020 0 1020

I don't know how to get a equivalent result using openCV2 in C++ though. 我不知道如何在C ++中使用openCV2获得等效的结果。 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 尝试从gradientx.at<double>(row,col)获取值会产生

-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> ? filter2D不应该在图像上进行2D卷积吗?为什么用<double>寻址输出像素时会得到怪异的值? Thank you. 谢谢。

Okay, here's your code with the types corrected (I've also added more parameters to filter2D ): 好的,这是校正了类型的代码(我还向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. 如果查看有关过滤的文档页面的顶部,则会看到OpenCV使用的所有边框类型。 By default, filter2D uses BORDER_REFLECT_101 . 默认情况下, filter2D使用BORDER_REFLECT_101 This is probably not what we want, so let's change it to BORDER_REPLICATE . 这可能不是我们想要的,所以让我们将其更改为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. 如果查看filter2D的功能描述的底部,您会发现它实际上是在计算互相关而不是卷积。 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]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM