【问题标题】:convolution of float image with 2D function in C浮点图像与C中的二维函数的卷积
【发布时间】:2014-09-05 09:36:38
【问题描述】:

您好,我必须使用以下内核对我的 32 位原始图像执行 2D 卷积

h(x,y)= a(b* exp^(-squareroot(x^2+y^2))

我不知道如何执行它,因为我是编码新手。我的图像尺寸是 1024*768。我应该保持相同大小的内核并执行卷积还是应该保持一个小内核?他们俩会有所作为吗?如果我保留一个小内核,我如何将它与整个图像进行卷积?

请帮忙

请检查生成内核的代码是否正确

感谢两位的回答。请您在下面查看生成内核和卷积的代码。我不确定我是否做得对

int krowhalf=krow/2,kcolhalf=kcol/2;

// sum is for normalization
float sum = 0.0;

// generate  kernel
for (int x = -krowhalf; x <= krowhalf; x++)
{
    for(int y = -kcolhalf; y <= kcolhalf; y++)
    {
        r = sqrtl(x*x + y*y);
        gKernel[x + krowhalf][y + kcolhalf] = a*(b*exp(-(r));
        sum += gKernel[x + krowhalf][y + kcolhalf];
    }
}

 //normalize the Kernel
for(int i = 0; i < krow; ++i)
    for(int j = 0; j < kcol; ++j)

gKernel[i][j] /= sum;

  float **convolve2D(float** in, float** out, int h, int v, float **kernel, int kCols,     int kRows)

  {
      int kCenterX = kCols / 2;

      int kCenterY = kRows / 2;

       int i,j,m,mm,n,nn,ii,jj;



     for(i=0; i < h; ++i) 
         // rows
      {
       for(j=0; j < v; ++j)   
   // columns
        {

   for(m=0; m < kRows; ++m)     // kernel rows

    {
       mm = kRows - 1 - m;      // row index of flipped kernel

        for(n=0; n < kCols; ++n) // kernel columns
        {
            nn = kCols - 1 - n;  // column index of flipped kernel

             //index of input signal, used for checking boundary
         ii = i + (m - kCenterY);
          jj = j + (n - kCenterX);

            // ignore input samples which are out of bound
            if( ii >= 0 && ii < h && jj >= 0 && jj < v )

                //out[i][j] += in[ii][jj] * (kernel[mm+nn*29]);
                out[i][j] += in[ii][jj] * (kernel[mm][nn]);


            }
       }
   }
}

返回; }

【问题讨论】:

  • 你为什么有exp(-r*r)?您写道,您在第一部分中取平方根而不是平方。除此之外,大多数情况下看起来都是正确的方法(没有检查所有内容)
  • 很抱歉,我只是在尝试使用基本的高斯卷积。如果没问题,你能检查一下卷积部分吗?我可以用这种方法使用一个小内核让我们说 3*3 吗?
  • 它应该可以工作,小心检查你的尺寸是奇数而不是偶数,否则你会产生一些段错误。我假设您的数组已正确完成,因为您没有显示声明。纯粹出于性能考虑,将一维数组用于内核会更有效,因为您无法确定编译器是否会对其进行优化
  • 好的,非常感谢。它对你很有帮助。我注意到你所有的建议。

标签: c image-processing convolution


【解决方案1】:

您知道如何进行一维信号卷积吗?你的过滤器总是有限的长度。您无法使用数字计算机进行无限卷积。二维滤波器也总是有限长度。例如,最简单的 2-D 滤波器拉普拉斯算子之一只有 3X3 大小。过滤器越长,您的处理就越复杂。

【讨论】:

  • 您好,感谢您的回复。是的,我知道一维卷积。我理解您的观点,即我不能使用与图像大小相同的大内核。假设我采用 3*3 内核。我如何让它与我的整个形象交织在一起。我的意思是我在哪里启动内核以及如何在我的所有图像上移动它?感谢您提前回复。
  • 我用我生成的代码编辑了我的问题。请检查它的好方法吗?
【解决方案2】:

好吧,使用一个非常大的内核(这将是理论上的精确结果)需要很长时间,所以通常你会使用 3x3 或 5x5,除非你真的需要一些精确的东西。无论如何,如果您使用精度有限的常规浮点数,则更多不太可能产生影响。

可以通过两个简单的 for 循环遍历每个点来进行卷积。对于边缘,一种简单的方法是扩展图像(例如,如果您使用 3x3,则在每一侧添加一个像素)并从旧边缘开始循环。

代码发布后编辑:

在循环代码中使用 ifs 将阻止您的编译器使用更快的指令(除非您的编译器非常聪明)同时计算更多点。这一行: out[i][j] += in[ii][jj] * (kernel[mm][nn]); 可能会被编译器转换为使用 SIMD 指令同时计算 4 个值。正因为如此,在边缘添加填充零通常更有效,并且不在这些点上将内核居中。

【讨论】:

  • 您好,感谢您的回复。我用我生成的代码编辑了我的问题。请检查它的好方法吗?
  • 我明白你为什么说要添加零填充,但我不明白如何做到这一点..还有我如何使用我的 2d 内核作为 1d 矢量?
  • kernel[i][j] 可以替换为kernel[i*krow+j]。根据您加载图像的方式,可以或多或少地轻松完成零填充。最好的选择是为边缘编写特定的代码(但这会使代码更复杂和更长)
【解决方案3】:

计算高斯滤波器的方法有很多种(这是图像处理中的基本方法)。这取决于您对性能的要求以及您想要支持的内核大小范围。

OpenCV 和英特尔 IPP 确实支持此过滤器,您可以在 Web 上轻松找到开源。您还可以查看 Deriche(递归实现高斯及其导数)和 van Vliet(高斯滤波器的递归实现)特殊算法:无论大小,它们都设法通过每个像素固定数量的操作来计算滤波器.

您的实现似乎是正确的。无论如何,我建议您使用过滤器的可分离性属性:2D 高斯是由 1D 水平高斯后跟 1D 垂直 (e^-(X²+Y²)=e^-X².e^-Y²) 获得的。这样一来,您将只需要 krow + kcol 个像素,而不是每个像素的 krow x kcol 操作,这是一个显着的节省。

【讨论】:

  • 高斯滤波器非常好,不幸的是它不适用于大多数滤波器。许多实现使用慢速替代方案(例如,如果我没记错的话,是 Matlab),但只要有可能,最好这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-01
  • 2013-10-16
  • 1970-01-01
相关资源
最近更新 更多