Note that there are some explanatory texts on larger screens.

plurals
  1. POHow can you render a visually meaningful 2D FFT in Java?
    primarykey
    data
    text
    <p>I have created a filter which is meant to render a 2D FFT (Fast Fourier Transform) of an image. In the actual application the images are coming from a live data feed. The problem is only the extremely low frequencies are registering so all I see is a flat gray image with a dot in the top left (lowest frequency). Can anyone suggest a way of repairing this code so it displays more than a flat image with a few dots in the top left corner?</p> <p>I believe this is the problem area in the code. This squares the 2D FFT Result to eliminate the imaginary part and then scales it.</p> <pre><code> ctmp.setTo(result_r[x][y]); // Copy Result to ctmp ctmp.mult(result_r[x][y]); // Square the result to eliminate imaginary part cval = 127 + (127 * ctmp.real/ max); tmpc = (int) Math.floor(cval); //System.out.println(String.format("tmpc=%d %f",tmpc,ctmp.real)); if (tmpc &gt; 255d) { rgb |= 255 &lt;&lt; 16; } else if (tmpc &gt;= 0d){ rgb |= ((tmpc &lt;&lt; 16) &amp; (255 &lt;&lt; 16)); } </code></pre> <p>Full source</p> <pre><code>/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package physics.filters; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.WritableRaster; import physics.Filter; // http://www.cs.virginia.edu/~wm2a/applets/Transformation/Complex.java import physics.helpers.Complex; // http://www.cs.virginia.edu/~wm2a/applets/Transformation/Fourier2D.java import physics.helpers.Fourier2D; /** * * @author rritoch */ public class FFTFilter implements Filter { BufferedImage last = null; boolean is_init = false; int imageW; int imageH; int fftW; int fftH; BufferedImage fftImage; Fourier2D fourier2d; Complex[][] complex2d_r; // red buffer Complex[][] complex2d_g; // green buffer Complex[][] complex2d_b; // blue buffer public static BufferedImage cloneImage(BufferedImage bi) { ColorModel cm = bi.getColorModel(); boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); WritableRaster raster = bi.copyData(null); return new BufferedImage(cm, raster, isAlphaPremultiplied, null); } /** * Init/Re-init Cache * */ void computeParams(BufferedImage in) { imageW = in.getWidth(); imageH = in.getHeight(); fftW = 1; fftH = 1; while(fftW &lt; imageW) { fftW = fftW &lt;&lt; 1; } while(fftH &lt; imageH) { fftH = fftH &lt;&lt; 1; } fftImage = new BufferedImage(fftW, fftH, in.getType()); fourier2d = new Fourier2D(fftW,fftH); complex2d_r = new Complex[fftW][]; complex2d_g = new Complex[fftW][]; complex2d_b = new Complex[fftW][]; for(int idx=0;idx&lt;fftW;idx++) { complex2d_r[idx] = new Complex[fftH]; complex2d_g[idx] = new Complex[fftH]; complex2d_b[idx] = new Complex[fftH]; for(int idy=0;idy&lt;fftH;idy++) { complex2d_r[idx][idy] = new Complex(); complex2d_g[idx][idy] = new Complex(); complex2d_b[idx][idy] = new Complex(); } } System.out.println(String.format("Init FFTFilter (%d,%d)!",fftW,fftH)); } void fft(BufferedImage img) { Graphics2D gr; Complex[][] result_r; Complex[][] result_g; Complex[][] result_b; int x,y; Complex ctmp = new Complex(); double cval; int rgb,tmpc; gr = fftImage.createGraphics(); gr.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); gr.drawImage(img, 0, 0, fftW, fftH, 0, 0, img.getWidth(), img.getHeight(), null); gr.dispose(); // Copy values from img to complex2d for(y=0;y&lt;fftH;y++) { for(x=0;x&lt;fftW;x++) { rgb = fftImage.getRGB(x,y); double r = new Double(rgb &amp; 255); double g = new Double((rgb &gt;&gt; 8) &amp; 255); double b = new Double((rgb &gt;&gt; 16) &amp; 255); complex2d_r[x][y].imag = 0; complex2d_r[x][y].real = r - 127d; complex2d_g[x][y].imag = 0; complex2d_g[x][y].real = g - 127d; complex2d_b[x][y].imag = 0; complex2d_b[x][y].real = b - 127d; } } // Calculate FFT result_r = fourier2d.fft(complex2d_r); result_g = fourier2d.fft(complex2d_g); result_b = fourier2d.fft(complex2d_b); // Scan result for Min &amp; Max double max = 0; double min = 0; for(y=0;y&lt;fftH;y++) { for(x=0;x&lt;fftW;x++) { ctmp.setTo(result_r[x][y]); ctmp.mult(result_r[x][y]); if (ctmp.real &gt; max) { max = ctmp.real; } else if (ctmp.real &lt; min) { min = ctmp.real; } ctmp.setTo(result_g[x][y]); ctmp.mult(result_g[x][y]); if (ctmp.real &gt; max) { max = ctmp.real; } else if (ctmp.real &lt; min) { min = ctmp.real; } ctmp.setTo(result_b[x][y]); ctmp.mult(result_b[x][y]); if (ctmp.real &gt; max) { max = ctmp.real; } else if (ctmp.real &lt; min) { min = ctmp.real; } } } System.out.println(String.format("Size: %f,%f",min,max)); // compute absolute max max = Math.abs(min) &gt; max ? Math.abs(min) : max; // Map result onto fftImage for(y=0;y&lt;fftH;y++) { for(x=0;x&lt;fftW;x++) { rgb = 0; ctmp.setTo(result_r[x][y]); ctmp.mult(result_r[x][y]); cval = 127 + (127 * ctmp.real/ max); tmpc = (int) Math.floor(cval); //System.out.println(String.format("tmpc=%d %f",tmpc,ctmp.real)); if (tmpc &gt; 255d) { rgb |= 255 &lt;&lt; 16; } else if (tmpc &gt;= 0d){ rgb |= ((tmpc &lt;&lt; 16) &amp; (255 &lt;&lt; 16)); } ctmp.setTo(result_g[x][y]); ctmp.mult(result_g[x][y]); cval = 127 + (127 * ctmp.real/ max); tmpc = (int) Math.floor(cval); if (tmpc &gt; 255d) { rgb |= 255 &lt;&lt; 8; } else if (tmpc &gt;= 0d){ rgb |= ((tmpc &lt;&lt; 8) &amp; (255 &lt;&lt; 8)); } ctmp.setTo(result_b[x][y]); ctmp.mult(result_b[x][y]); cval = 127 + (127 * ctmp.real/ max); tmpc = (int) Math.floor(cval); if (tmpc &gt; 255d) { rgb |= 255; } else if (tmpc &gt;= 0d){ rgb |= (tmpc &amp; 255); } fftImage.setRGB(x, y, rgb); } } // Copy fft Image to image gr = img.createGraphics(); gr.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); gr.drawImage(fftImage, 0, 0, img.getWidth(), img.getHeight(), 0, 0, fftImage.getWidth(), fftImage.getHeight(), null); gr.dispose(); } @Override public BufferedImage filter(BufferedImage in) { if (last == null || last.getWidth() != in.getWidth() || last.getHeight() != in.getHeight()) { computeParams(in); } BufferedImage ret = cloneImage(in); fft(ret); last = in; return ret; } } </code></pre> <p>Note: This is my first time using this particular FFT and I haven't verified if the FFT algorithm is correct so I am going off of the assumption that the FFT algorithm is correct.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload