用C中的2D函数对浮动图像进行卷积

时间:2014-07-15 09:02:05

标签: c image-processing convolution

您好我必须使用以下内核对我的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]);


            }
       }
   }
}

退出; }

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

使用非常大的内核(这将是理论上的确切结果)需要永远,所以通常你需要3x3或5x5,除非你真的需要精确的东西。如果您使用有限精度的常规浮点数,则不太可能产生影响。

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

代码发布后

编辑:

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

答案 2 :(得分:0)

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

OpenCV和Intel IPP支持此过滤器,您可以轻松地在Web上找到开源。您还可以查看Deriche(递归实现高斯及其衍生物)和van Vliet(高斯滤波器的递归实现)特殊算法:它们设法计算每个像素具有固定操作数的滤波器,无论大小如何

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