3

Suppose, we have a bitmap image represented as a 2D integer array, int [,] image2D; whose FFT is Complex[,] fftImage2D;

Suppose, we have an kernel represented as a 2D integer array, int [,] kernel2D; whose FFT is Complex[,] fftKernel2D;

We know that, the convolution (in spatial domain) of image2D and kernel2D would be,

int Rows = image2D.GetLength(0);
int Cols = image2D.GetLength(1);

for(int i=0 ; i<Rows ; i++)
{
    for(int j=0 ; j<Cols ; j++)
    {
        //sweep the kernel2D across image2D
        //...........................
    }
}

The following links are all about convolution in spatial domain:

http://www.codeproject.com/Articles/2008/Image-Processing-for-Dummies-with-C-and-GDI-Part http://www.gutgames.com/post/Matrix-Convolution-Filters-in-C.aspx https://softwarebydefault.com/2013/05/01/image-convolution-filters/

Convolution in frequency domain would be, multiplication between fftImage2D and fftKernel2D.

How can I do this multiplication?

How can I multiply two Complex [,] type 2D arrays of different dimensions?

user366312
  • 16,949
  • 65
  • 235
  • 452

2 Answers2

5

To perform linear convolution by using multiplication in the frequency domain you must first make sure the two complex 2D arrays have the same dimensions. This can be achieved by padding the two spatial domain arrays (image2D and kernel2D) to the same size. Note that you already have to pad your spatial domain arrays to a minimum of one less than the sum of the two arrays dimensions (along each dimension) to perform linear convolution rather than circular convolution.

So the process looks like:

  • Compute padded number of rows: image2D.GetLength(0)+kernel2D.GetLength(0)-1
  • Compute padded number of columns: image2D.GetLength(1)+kernel2D.GetLength(1)-1
  • Pad image2D to this new size, repeating border elements
  • Pad kernel2D to this new size, filling in zeros
  • Compute FFT of the padded image2D and kernel2D
  • Perform multiplication of padded fftImage2D and fftKernel2D which are now of the same size
  • Compute inverse FFT
  • Optionally truncate result to original image2D size (this is only required if you are interested in a obtaining an image filtered by kernel2D without the edge effects that comes with a full convolution).

For a sample implementation, future readers may have a look at this other question from @anonymous together with the changes I indicated in my answer.

Community
  • 1
  • 1
SleuthEye
  • 14,379
  • 2
  • 32
  • 61
  • What if I take the larger of the two (image2D vs kernel2D) as pad size? Should I keep the kernel at the center of the padded image or at any one of the four corners? And, how can I truncate image2D? – user366312 Jun 13 '16 at 03:26
  • 1
    If you take only the larger of the two as pad size you will wind up with some artifacts from the circular convolution. Only as the size gets to at least the value stated above would the artifacts become zero. Kernel location in frequency domain should be in the 4 corners (assuming zero frequency is at the center, which is common), unless you also fftshift/ifftshift the image (ie. you need to keep both image with the same zero frequency location). – SleuthEye Jun 13 '16 at 12:17
  • 1
    Kernel location in spatial domain could be anywhere provided you account for the corresponding shift when you truncate resulting image. If you put it in 4 corners in spatial domain, you should get a zero shift so truncating the resulting image would simply be taking the first `GetLength(0)` & `GetLength(1)` pixels. – SleuthEye Jun 13 '16 at 12:17
-1

You have to use the multiplication of two complex numbers.

Here is a little java code that do the work for two 1D arrays, with such encoding: [R1, C1, R2, C2, ..., Rn, Cn]:

public void Multiply(double[] object1, double[] object2, double[] result)
{
double img_r, img_i, mask_r, mask_i ;

for (int pos=0 ; pos < result.length ; pos+=2)
    {
    img_r = object1[pos] ;
    img_i = object1[pos+1] ;

    mask_r = object2[pos] ;
    mask_i = object2[pos+1] ;

    result[pos]   = img_r*mask_r - img_i*mask_i;
    result[pos+1] = img_r*mask_i + img_i*mask_r ;
    }
}
FiReTiTi
  • 5,597
  • 12
  • 30
  • 58