MikeT
MikeT

Reputation: 51

How to implement a low pass filter over an image in the frequency domain with the Discrete Fourier Transform?

I'm trying to implement a 2d fourier transform on an image. I have it so my DFT and inverse DFT work on an image. But when I apply the filter, by multiplying the complex numbers, and inverse the result I just get image noise.

Here is my 2d DFT

public void dft(double[][] inreal, double[][] inimag) {
int n = inreal.length;

double[][] tempreal = new double[n][n];
double[][] tempimag = new double[n][n];
realArray = new double[n][n];
imagArray = new double[n][n];

  for(int row = 0; row < n; row++) {  
    for (int col = 0; col < n; col++) {  
        double sumreal = 0;
        double sumimag = 0;
        for (int t = 0; t < n; t++) {  
            double angle = 2 * Math.PI * t * col / n;
            sumreal +=  inreal[row][t] * Math.cos(angle) + inimag[row][t] * Math.sin(angle);
            sumimag += -inreal[row][t] * Math.sin(angle) + inimag[row][t] * Math.cos(angle);
            
        }
        //System.out.println("r" + row + " " + "c" + col + " " + sumreal + " " + sumimag);
        tempreal[row][col] = sumreal;
        tempimag[row][col] = sumimag;
    }
}
    
    //now do it over the columns
 for (int col = 0; col < n; col++) {
    for (int row = 0; row < n; row++) {  // For each output element
        double sumreal = 0;
        double sumimag = 0;
        for (int t = 0; t < n; t++) {  // For each input element
            double angle = 2 * Math.PI * t * row / n;
            sumreal +=  tempreal[t][col] * Math.cos(angle) + tempimag[t][col] * Math.sin(angle);
            sumimag += -tempreal[t][col] * Math.sin(angle) + tempimag[t][col] * Math.cos(angle);
        }
        realArray[row][col] = sumreal;
        imagArray[row][col] = sumimag;
        //System.out.println(realArray[row][col] + " " + imagArray[row][col] + "i");
    }
 }
 
 

}

And here is my inverse DFT

public void inverseDFT(double[][] inRealArray, double[][] inImagArray) {
 int n = realArray.length;
    outRealArray = new double[n][n];
    outImagArray = new double[n][n];
    outputarray = new int[n][n];
    
    double[][] tempreal = new double[n][n];
    double[][] tempimag = new double[n][n];
 
    for (int col = 0; col < n; col++) {
        for (int row = 0; row < n; row++) {   // For each output element
           double sumreal = 0;
           double sumimag = 0;
           for (int t = 0; t < n; t++) {  // For each input element
               double angle = 2 * Math.PI * t * row / n;
               sumreal +=  inRealArray[t][col] * Math.cos(angle) - inImagArray[t][col] * Math.sin(angle);
               sumimag +=  inRealArray[t][col] * Math.sin(angle) + inImagArray[t][col] * Math.cos(angle);
        
           }
           //System.out.println("r" + row + " " + "c" + col + " " + sumreal + " " + sumimag);
           tempreal[row][col] = sumreal;
           tempimag[row][col] = sumimag;
       }
   }

    //now do it over the columns
    for(int row = 0; row < n; row++) {  
        for (int col = 0; col < n; col++) {  // For each output element
           double sumreal = 0;
           double sumimag = 0;
           for (int t = 0; t < n; t++) {  // For each input element
               double angle = 2 * Math.PI * t * col / n;
               sumreal +=  tempreal[row][t] * Math.cos(angle) - tempimag[row][t] * Math.sin(angle);
               sumimag +=  tempreal[row][t] * Math.sin(angle) + tempimag[row][t] * Math.cos(angle);
           }
           outRealArray[row][col] = sumreal / (n * n);
           outImagArray[row][col] = sumimag / (n * n);
           outputarray[row][col] = (int)Math.abs(outRealArray[row][col]);
           //System.out.println(outRealArray[row][col] + " " + outImagArray[row][col] + "i");
       }
  }
    
}

The image goes through and comes back the same. I shifted the image to the center and got the spectral image to test if it works.

enter image description here

This is the magnitude of the complex number and shifted to the center

This is the magnitude of the complex number and shifted to the center

enter image description here

The Low Pass Filter

enter image description here

The Filter put through the DFT.

Here's my code to multiply the two.

    public void applyLowPassFilter(String filename, double[][] realArray, double[][] imagArray) throws IOException {
    ReadPGMFile readPGM = new ReadPGMFile(filename);
    double[][] filterArrayR = readPGM.loadArray();
    double[][] filterArrayI = new double[filterArrayR.length][filterArrayR.length];
    
    FourierTransform ft = new FourierTransform();
    ft.dft(filterArrayR, filterArrayI);
    filterReal = ft.getRealArray();
    filterImag = ft.getImagArray();
    
    int n = realArray.length;
    resultRealArray = new double[n][n];
    resultImagArray = new double[n][n];
    
    for(int i = 0; i < n; i++){
        int colValue = 0;
        int rowValue = 0;
        for(int j = 0; j < n; j++) {
         if(j < n / 2 ){
             colValue = (n / 2) - j;
         } else {
             colValue = (n - 1) - (j - ((n - 1) / 2));
         }
         if (i < n / 2) {
             rowValue = (n / 2) - i;
         } else {
             rowValue = (n - 1) - (i - ((n - 1) / 2));
         }
            
            
            resultRealArray[i][j] = realArray[rowValue][colValue] * filterReal[i][j] - imagArray[rowValue][colValue] * filterImag[i][j];
            resultImagArray[i][j] = realArray[rowValue][colValue] * filterImag[i][j] + imagArray[rowValue][colValue] * filterReal[i][j];
        }
    }
}

enter image description here

This is the result that I am getting. Sorry for the long post. If anyone has any insights I would appreciate them. I've been struggling with this for a few weeks now.

Upvotes: 0

Views: 1310

Answers (1)

gpasch
gpasch

Reputation: 2682

Here's the code I use to test it:

      int[] pix=bim.getRGB(0, 0, wc, hc, null, 0, wc);
      double[][] ri=new double[hc][hc], ii=new double[hc][hc], ro=new double[hc][hc], io=new double[hc][hc];
      for(i=0; i<hc; i++)
      for(j=0; j<hc; j++) {
        int rr=(pix[i+j*wc]&0x00ff0000)>>16, rg=(pix[i+j*wc]&0x0000ff00)>>8, rb=pix[i+j*wc]&0x000000ff;
        ri[i][j]=0.2126*rr+0.7152*rg+0.0722*rb;
      }
      double[][] ff=new double[hc][hc];
      ff[hc/2][hc/2]=ff[hc/2][hc/2+1]=ff[hc/2][hc/2-1]=ff[hc/2+1][hc/2]=ff[hc/2-1][hc/2]=1;
      // ff[hc/2][hc/2]=ff[hc/2][hc/2+1]=ff[hc/2][hc/2-1]=ff[hc/2+1][hc/2]=ff[hc/2-1][hc/2]=ff[hc/2-1][hc/2-1]=ff[hc/2-1][hc/2+1]=ff[hc/2+1][hc/2-1]=ff[hc/2+1][hc/2+1]=0.125;
      filterDFT(ff, ri, ro, io);
      int[] pix2=new int[hc*hc];
      for(i=0; i<hc; i++)
      for(j=0; j<hc; j++) pix2[i+j*hc]=0xff000000|(int)Math.abs(ro[i][j]);
      BufferedImage b2=new BufferedImage(hc, hc, BufferedImage.TYPE_INT_RGB);
      b2.setRGB(0, 0, hc, hc, pix2, 0, hc);

Now b2 is your image; and it shows well - you have to reshuffle the quadrants.

Therefore I suggest you take a second look at what your filter reading downloads.

Upvotes: 1

Related Questions