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.util.Complex2dArray; import fr.unistra.pelican.util.ComplexNumber; /** * 2D recursive inverse fast fourier transform... * * !!! Image dimensions must be power of 2 (dimx=2^k, dimy=2^k') * * Input is composed of two images representing real and respectively imaginary part of transform. * Third input parameter allow to choose type of result (real part, imaginary part, or magnitudes) * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#REAL * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#IMAG * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#MAGN * * Result is in double precision * @deprecated use FFT2 faster better stronger * @author ?, Benjamin Perret (depracater) */ public class InverseFFT extends Algorithm { /** * Real part of input image in frequency domain */ public Image inputImageReal; /** * Imaginary part of input image in frequency domain */ public Image inputImageImag; /** * Result of iFFT */ public Image outputImage; /** * Wanted part of the output * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#REAL * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#IMAG * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#MAGN */ public int outputType; /** * We want real part of inverse transform */ public static final int REAL = 0; /** * We want imaginary part of inverse transform */ public static final int IMAG = 1; /** * We want magnitude of inverse transform */ public static final int MAGN = 2; /** * Constructor * */ public InverseFFT() { super(); super.inputs = "inputImageReal,inputImageImag,outputType"; super.outputs = "outputImage"; } /* * (non-Javadoc) * * @see fr.unistra.pelican.Algorithm#launch() */ public void launch() throws AlgorithmException { int xDim = inputImageReal.getXDim(); int yDim = inputImageReal.getYDim(); double[][] pixelsR2 = new double[inputImageReal.getXDim()][inputImageReal .getYDim()]; double[][] pixelsI2 = new double[inputImageReal.getXDim()][inputImageReal .getYDim()]; for (int x = 0; x < inputImageReal.getXDim(); x++) { for (int y = 0; y < inputImageReal.getYDim(); y++) { pixelsR2[x][y] = inputImageReal.getPixelXYDouble(x, y); pixelsI2[x][y] = inputImageImag.getPixelXYDouble(x, y); } } pixelsR2 = shiftOrigin(pixelsR2); pixelsI2 = shiftOrigin(pixelsI2); double[] pixelsR = new double[inputImageReal.size()]; double[] pixelsI = new double[inputImageReal.size()]; for (int x = 0; x < inputImageReal.getXDim(); x++) { for (int y = 0; y < inputImageReal.getYDim(); y++) { pixelsR[y * inputImageReal.getXDim() + x] = pixelsR2[x][y]; pixelsI[y * inputImageReal.getXDim() + x] = pixelsI2[x][y]; } } Complex2dArray input = new Complex2dArray(pixelsR, pixelsI, xDim, yDim); Complex2dArray intermediate = new Complex2dArray(pixelsR, xDim, yDim); Complex2dArray output = new Complex2dArray(pixelsR, xDim, yDim); for (int i = 0; i < input.size; ++i) intermediate.putColumn(i, recIFFT(input.getColumn(i))); for (int i = 0; i < intermediate.size; ++i) output.putRow(i, recIFFT(intermediate.getRow(i))); // prepare output according to predefined type outputImage = new DoubleImage(inputImageReal, false); // constant factor double c = outputImage.xdim * outputImage.ydim; switch (outputType) { case REAL: double[][] reals = output.getReals(); for (int x = 0; x < xDim; x++) for (int y = 0; y < yDim; y++) outputImage.setPixelXYDouble(x, y, c*reals[x][y]); break; case IMAG: double[][] imags = output.getImags(); for (int x = 0; x < xDim; x++) for (int y = 0; y < yDim; y++) outputImage.setPixelXYDouble(x, y, c*imags[x][y]); break; default: double[][] mags = output.getMagnitudes(); for (int x = 0; x < xDim; x++) for (int y = 0; y < yDim; y++) outputImage.setPixelXYDouble(x, y, c*mags[x][y]); } } private double[][] shiftOrigin(double[][] input) { int width = input.length; int height = input[0].length; double[][] output = new double[width][height]; int x = width / 2; int y = height / 2; int i2, j2; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { i2 = i + x; j2 = j + y; if (i2 >= width) i2 = i2 % width; if (j2 >= height) j2 = j2 % height; output[i][j] = input[i2][j2]; } } return output; } private ComplexNumber[] recIFFT(ComplexNumber[] x) { ComplexNumber z1, z2, z3, z4, tmp, cTwo; int n = x.length; int m = n / 2; ComplexNumber[] result = new ComplexNumber[n]; ComplexNumber[] even = new ComplexNumber[m]; ComplexNumber[] odd = new ComplexNumber[m]; ComplexNumber[] sum = new ComplexNumber[m]; ComplexNumber[] diff = new ComplexNumber[m]; cTwo = new ComplexNumber(2, 0); if (n == 1) result[0] = x[0]; else { z1 = new ComplexNumber(0.0, 2 * (Math.PI) / n); tmp = ComplexNumber.cExp(z1); z1 = new ComplexNumber(1.0, 0.0); for (int i = 0; i < m; i++) { z3 = ComplexNumber.cSum(x[i], x[i + m]); sum[i] = ComplexNumber.cDiv(z3, cTwo); z3 = ComplexNumber.cDiff(x[i], x[i + m]); z4 = ComplexNumber.cMult(z3, z1); diff[i] = ComplexNumber.cDiv(z4, cTwo); z2 = ComplexNumber.cMult(z1, tmp); z1 = new ComplexNumber(z2); } even = recIFFT(sum); odd = recIFFT(diff); for (int i = 0; i < m; i++) { result[i * 2] = new ComplexNumber(even[i]); result[i * 2 + 1] = new ComplexNumber(odd[i]); } } return result; } /** * 2D recursive inverse fast fourier transform... * * Input is composed of two images representing real and respectively imaginary part of transform. * Third input parameter allow to choose type of result (real part, imaginary part, or magnitudes) * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#REAL * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#IMAG * @see fr.unistra.pelican.algorithms.frequential.InverseFFT#MAGN * * Result is in double precision * * @param inputImageReal Real part of image in frequency domain. * @param inputImageImag Imaginary part of image in frequency domain. * @param outputType Type of output. * @return Inverse transform */ public static DoubleImage exec(Image inputImageReal, Image inputImageImag, int outputType) { return (DoubleImage ) new InverseFFT().process(inputImageReal,inputImageImag,outputType); } }