/** * */ package fr.unistra.pelican.algorithms.frequential; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.DoubleImage; import fr.unistra.pelican.Image; import fr.unistra.pelican.algorithms.arithmetic.Difference; import fr.unistra.pelican.algorithms.io.ImageLoader; import fr.unistra.pelican.algorithms.visualisation.MViewer; import fr.unistra.pelican.gui.MultiViews.MultiView; /** * FFTShift rearranges the outputs of fft, and fft2 by moving the zero-frequency component to the center of the array. * It is useful for visualizing a Fourier transform with the zero-frequency component in the middle of the spectrum. * <p> * Take care to set inverse option to true if you want to be sure that the inverse transform is correctly done * (should not be needed when dimensions are even as inverse transform reduces to the original one in this particular case). * * @author Benjamin Perret * */ public class FFTShift extends Algorithm { /** * Input Image */ public Image inputImage; /** * Do the inverse transform, inverse transform is the same as original one if image dimensions are even */ public boolean inverse=false; /** * Result */ public Image outputImage; private int xdim; private int ydim; private int bdim; /** * */ public FFTShift() { super.inputs="inputImage"; super.options="inverse"; super.outputs="outputImage"; } /* (non-Javadoc) * @see fr.unistra.pelican.Algorithm#launch() */ @Override public void launch() throws AlgorithmException { outputImage=inputImage.copyImage(false); xdim=inputImage.xdim; ydim=inputImage.ydim; bdim=inputImage.bdim; int mx=xdim/2; int rx=xdim-mx; int my=ydim/2; int ry=ydim-my; if(inverse) doIt(rx, mx, ry, my); else doIt(mx, rx, my, ry); } private void doIt(int mx, int rx, int my, int ry) { for (int b = 0; b < bdim; b++) { // down right corner move to up left corner for (int y = 0; y < ry; y++) for (int x = 0; x < rx; x++) outputImage.setPixelXYBDouble(x, y, b, inputImage .getPixelXYBDouble(x + mx, y + my, b)); // down left corner move to up right corner for (int y = 0; y < ry; y++) for (int x = rx; x < xdim; x++) outputImage.setPixelXYBDouble(x, y, b, inputImage .getPixelXYBDouble(x - rx, y + my, b)); // up right corner move to down left corner for (int y = ry; y < ydim; y++) for (int x = 0; x < rx; x++) outputImage.setPixelXYBDouble(x, y, b, inputImage .getPixelXYBDouble(x + mx, y -ry, b)); // up left corner move to down right corner for (int y = ry; y < ydim; y++) for (int x = rx; x < xdim; x++) outputImage.setPixelXYBDouble(x, y, b, inputImage .getPixelXYBDouble(x - rx, y -ry, b)); } } @SuppressWarnings("unchecked") public static <T extends Image> T exec(T inputImage) { return (T)(new FFTShift()).process(inputImage); } @SuppressWarnings("unchecked") public static <T extends Image> T exec(T inputImage, boolean inverse) { return (T)(new FFTShift()).process(inputImage, inverse); } public static void main(String[] args) { DoubleImage im = new DoubleImage(ImageLoader.exec("samples/lenna.png"),true); MultiView mv=MViewer.exec(im); //im=Crop2D.exec(im,0,0,254,254); DoubleImage [] op = FFT2.exec(im, null, false); mv.add(Magnitude.exec(FFT2.exec(op[0], op[1], true))); DoubleImage shift1=FFTShift.exec(op[0]); DoubleImage shift2=FFTShift.exec(shift1, true); Image diff=Difference.exec(op[0], shift2, false); mv.add(shift1); mv.add(shift2); mv.add(diff); mv.add(Magnitude.exec(FFT2.exec(shift2, op[1], true))); } }