简体   繁体   中英

convolution of float image with 2D function in C

Hello I have to perform 2D convolution of my 32 bit raw image with the following kernel

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

I am not sure how to perform it as I am new to coading. My image size is 1024*768. should I keep the kernel of the same size and perform convolution or I should keep a small kernel ? Will both of them make a difference? If I keep a small kernel , how do I convolute it with the whole image ?

Please help

please check if the code for generating the kernel is right

Thank you both of you for answering. Please can you check below this code of generating the kernel and then the convolution . I am not sure if I am doing right

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]);


            }
       }
   }
}

return out; }

Did you know how to do a 1-D signal convolution? your filters are always finite length. You cannot do infinite convolution using a digital computer. 2-D filters are always finite length also. For example, one of the simplest 2-D filter Laplacian is only 3X3 size. The longer the filter, the more complex your processing.

Well it would take forever to use a very big kernel (which would be the theoretical exact result) so usually you take 3x3 or 5x5 unless you really need something precise. More is unlikely to make a difference if you use regular floating points numbers with their limited precision anyway.

The convolution can be made with two simple for loops going through every point. For the edges an easy way is to extend the image (if you use 3x3 for example you add one pixel on every side) and start your loop from the old edges.

edit after the code was posted:

Using ifs in the loop code will prevent your compiler from using faster instructions (unless your compiler is very smart) to calculate more points at the same time. This line: out[i][j] += in[ii][jj] * (kernel[mm][nn]); can probably be transformed by the compiler to be calculated 4 values at the same time with SIMD instructions. It is because of this usually more efficient to add padding zeros to the edges and don't center the kernel on these points.

There are many ways to compute a Gaussian filter (this is a fundamental one in image processing). It depends on your requirements for performance and the range of kernel sizes you want to support.

OpenCV and Intel IPP do support this filter, and you will easily find open source on the Web. You can also have a look at the Deriche (Recursively implementating the Gaussian and its derivatives) and van Vliet (Recursive implementation of the Gaussian filter) special algorithms: they manage to compute the filter with a fixed number of operations per pixels, regardless the size.

You implementation seems correct. Anyway I recommend you to use the separability property of the filter: a 2D Gaussian is obtained by a 1D horizontal Gaussian followed by a 1D vertical ( e^-(X²+Y²)=e^-X².e^-Y² ). This way, instead of krow x kcol operations per pixel, you'll only need krow + kcol of them, a significant saving.

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.

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