如何在Java中呈现具有视觉意义的2D FFT?

时间:2013-12-13 13:26:14

标签: java algorithm fft

我创建了一个过滤器,用于渲染图像的2D FFT(快速傅里叶变换)。在实际应用中,图像来自实时​​数据馈送。问题是只有极低的频率才能记录,所以我看到的是一个平坦的灰色图像,左上角有一个点(最低频率)。任何人都可以建议一种修复此代码的方法,以便它显示的不仅仅是左上角有几个点的平面图像吗?

我相信这是代码中的问题区域。这使2D FFT结果平方以消除虚部,然后对其进行缩放。

            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 > 255d) {
                rgb |=  255 << 16;    
            } else if (tmpc >= 0d){
                rgb |= ((tmpc << 16) & (255 << 16));
            }

完整来源

/*
 * 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 < imageW) {
            fftW = fftW << 1;
        }

        while(fftH < imageH) {
            fftH = fftH << 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<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<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<fftH;y++) {
            for(x=0;x<fftW;x++) {

                rgb = fftImage.getRGB(x,y);
                double r = new Double(rgb & 255);
                double g = new Double((rgb >> 8) & 255);
                double b = new Double((rgb >> 16) & 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 & Max

        double max = 0;
        double min = 0;

        for(y=0;y<fftH;y++) {
            for(x=0;x<fftW;x++) {
                ctmp.setTo(result_r[x][y]);
                ctmp.mult(result_r[x][y]);
                if (ctmp.real > max) {
                    max = ctmp.real;
                } else if (ctmp.real < min) {
                    min = ctmp.real;
                }

                ctmp.setTo(result_g[x][y]);
                ctmp.mult(result_g[x][y]);

                if (ctmp.real > max) {
                    max = ctmp.real;
                } else if (ctmp.real < min) {
                    min = ctmp.real;
                }

                ctmp.setTo(result_b[x][y]);
                ctmp.mult(result_b[x][y]);

                if (ctmp.real > max) {
                    max = ctmp.real;
                } else if (ctmp.real < min) {
                    min = ctmp.real;
                }
            }
        }

        System.out.println(String.format("Size: %f,%f",min,max));

        // compute absolute max
        max = Math.abs(min) > max ? Math.abs(min) : max;

        // Map result onto fftImage

        for(y=0;y<fftH;y++) {
            for(x=0;x<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 > 255d) {
                    rgb |=  255 << 16;    
                } else if (tmpc >= 0d){
                    rgb |= ((tmpc << 16) & (255 << 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 > 255d) {
                    rgb |=  255 << 8;    
                } else if (tmpc >= 0d){
                    rgb |= ((tmpc << 8) & (255 << 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 > 255d) {
                    rgb |=  255;    
                } else if (tmpc >= 0d){
                    rgb |= (tmpc & 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;
    }


}

注意:这是我第一次使用这个特殊的FFT,我还没有验证FFT算法是否正确,所以我假设FFT算法是正确的。

1 个答案:

答案 0 :(得分:1)

请注意,这些行不会消除虚部

ctmp.setTo(result_r[x][y]); // Copy Result to ctmp
ctmp.mult(result_r[x][y]); // Square the result to eliminate imaginary part

(a + i * b)(a + i * b)= a ^ 2 - b ^ 2 + i *(a + b)

我建议您需要复数的幅度(模数)

Amp = Sqrt(ctmp.real^2 + ctmp.imaginary^2)

(可能你在复杂的课程中有特殊功能)