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 fast fourier transform... one channel images only..
*
* !!! Image dimensions must be power of 2 (dimx=2^k, dimy=2^k')
*
* Result is a array of 3 DoubleImage
* - real part of transform
* - imaginary part of transform
* - magnitudes ( sqrt ( real^2 + imaginary^2 ) )
*
* @deprecated use FFT2 faster better stronger
* @author ?, Benjamin Perret (depracater)
*/
public class FFT extends Algorithm {
/**
* Input image
*/
public Image inputImage;
/**
* Coefficient images result
* First element is the real part
* Second element is imaginary part
* Third element is magnitudes ( sqrt ( real^2 + imaginary^2 ) )
*/
public DoubleImage [] outputs = new DoubleImage[3];
/* no use ???
public static final int REAL = 0;
public static final int IMAG = 1;
public static final int MAGN = 2;
*/
/**
* Constructor
*
*/
public FFT() {
super();
super.inputs = "inputImage";
super.outputs = "outputs";
}
/*
* (non-Javadoc)
*
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() throws AlgorithmException {
int xDim = inputImage.getXDim();
int yDim = inputImage.getYDim();
double[] pixels = new double[inputImage.size()];
for (int x = 0; x < inputImage.size(); x++)
pixels[x] = (double) inputImage.getPixelDouble(x);
Complex2dArray input = new Complex2dArray(pixels, xDim, yDim);
Complex2dArray intermediate = new Complex2dArray(pixels, xDim, yDim);
Complex2dArray output = new Complex2dArray(pixels, xDim, yDim);
for (int i = 0; i < input.size; ++i)
intermediate.putColumn(i, recFFT(input.getColumn(i)));
for (int i = 0; i < intermediate.size; ++i)
output.putRow(i, recFFT(intermediate.getRow(i)));
outputs[0] = new DoubleImage(inputImage, false);
outputs[1] = new DoubleImage(inputImage, false);
outputs[2] = new DoubleImage(inputImage, false);
double[][] reals = output.getReals();// shiftOrigin(output.getReals());
for (int x = 0; x < xDim; x++)
for (int y = 0; y < yDim; y++)
outputs[0].setPixelXYDouble(x, y, reals[x][y]);
double[][] imags = output.getImags();// shiftOrigin(output.getImags());
for (int x = 0; x < xDim; x++)
for (int y = 0; y < yDim; y++)
outputs[1].setPixelXYDouble(x, y, imags[x][y]);
double[][] mags = output.getMagnitudes();
for (int x = 0; x < xDim; x++)
for (int y = 0; y < yDim; y++)
outputs[2].setPixelXYDouble(x, y, mags[x][y]);
}
private static DoubleImage shiftOrigin(DoubleImage img) {
int width = img.getXDim();
int height = img.getYDim();
double[][] input = new double[width][height];
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
input[i][j] = img.getPixelXYDouble(i, j);
double[][] output = new double[width][height];
DoubleImage out = new DoubleImage(img);
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];
}
}
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
out.setPixelXYDouble(i, j, output[i][j]);
return out;
}
private ComplexNumber[] recFFT(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];
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);
cTwo = new ComplexNumber(2.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 = recFFT(sum);
odd = recFFT(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 fast fourier transform... one channel images only..
*
* Result is a array of 3 DoubleImage
* - real part of transform
* - imaginary part of transform
* - magnitudes ( sqrt ( real^2 + imaginary^2 ) )
*
* @param inputImage Input image
* @return Result of transform
*/
public static DoubleImage[] exec(Image inputImage)
{
return (DoubleImage []) new FFT().process(inputImage);
}
}