diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000000000000000000000000000000000000..7219206354fac7caf56d961f01cef916d5d98752
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
+		<attributes>
+			<attribute name="module" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="var" path="ICY_JAR"/>
+	<classpathentry kind="var" path="ICY_PLUGINS/adufour/ezplug/EzPlug.jar"/>
+	<classpathentry kind="var" path="ICY_PLUGINS/adufour/blocks/Blocks.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3a1f4bfdeca01d47c23831d9632af6b40a27800a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/*.jar
+/bin/
diff --git a/.project b/.project
new file mode 100644
index 0000000000000000000000000000000000000000..f69e79c7e58de5ada51385dab7df0ed5c21c7903
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>fft</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/FFT.png b/FFT.png
new file mode 100644
index 0000000000000000000000000000000000000000..8f59f36b596c2521b5e3929b4ebab0aa69b49eeb
Binary files /dev/null and b/FFT.png differ
diff --git a/FFT_icon.png b/FFT_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..5c94a39495b91786100b93192a3dacc4e41894c3
Binary files /dev/null and b/FFT_icon.png differ
diff --git a/export.jardesc b/export.jardesc
new file mode 100644
index 0000000000000000000000000000000000000000..0430195f09498518aca429b4fdfe4a6023fe3bef
--- /dev/null
+++ b/export.jardesc
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?>
+<jardesc>
+    <jar path="fft/fftPlugin.jar"/>
+    <options buildIfNeeded="true" compress="true" descriptionLocation="/fft/export.jardesc" exportErrors="false" exportWarnings="true" includeDirectoryEntries="true" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+    <storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+    <selectedProjects/>
+    <manifest generateManifest="true" manifestLocation="/Jython/META-INF/MANIFEST.MF" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+        <sealing sealJar="false">
+            <packagesToSeal/>
+            <packagesToUnSeal/>
+        </sealing>
+    </manifest>
+    <selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false">
+        <javaElement handleIdentifier="=fft/src"/>
+        <file path="/fft/export.jardesc"/>
+        <file path="/fft/.classpath"/>
+        <file path="/fft/.project"/>
+    </selectedElements>
+</jardesc>
diff --git a/src/plugins/praveen/fft/AssignFunction2D.java b/src/plugins/praveen/fft/AssignFunction2D.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a49873857a04f04df0c438c2b11867d1eae7e36
--- /dev/null
+++ b/src/plugins/praveen/fft/AssignFunction2D.java
@@ -0,0 +1,8 @@
+package plugins.praveen.fft;
+
+import cern.colt.function.tdouble.DoubleDoubleFunction;
+
+public interface AssignFunction2D {
+	void assign(double[] in, double[] out, int _w, int _h,
+			DoubleDoubleFunction Function);
+}
diff --git a/src/plugins/praveen/fft/AssignFunction3D.java b/src/plugins/praveen/fft/AssignFunction3D.java
new file mode 100644
index 0000000000000000000000000000000000000000..b5ab05d70e2f977cbdf3bd130711282d10581b8c
--- /dev/null
+++ b/src/plugins/praveen/fft/AssignFunction3D.java
@@ -0,0 +1,8 @@
+package plugins.praveen.fft;
+
+import cern.colt.function.tdouble.DoubleDoubleFunction;
+
+public interface AssignFunction3D {
+	void assign(double[] in, double[][][] out, int _w, int _h, int _z, int c,
+			DoubleDoubleFunction function);
+}
diff --git a/src/plugins/praveen/fft/AssignFunctions.java b/src/plugins/praveen/fft/AssignFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd6a326eda7a7f2abd7cfcadc6a227e79f6f5fc3
--- /dev/null
+++ b/src/plugins/praveen/fft/AssignFunctions.java
@@ -0,0 +1,95 @@
+package plugins.praveen.fft;
+
+import cern.colt.function.tdouble.DoubleDoubleFunction;
+
+public class AssignFunctions {
+
+	//function that walks the 2D FFT from JTransforms and fills the sequence data array
+	//this is the version that does not swap the quadrants
+	public static class DirectAssign2D implements AssignFunction2D {
+		public void assign(double[] in, double[] out, int _w, int _h,
+				DoubleDoubleFunction function) {
+			for (int i = 0; i < in.length/2; i++)
+			{
+				double real = in[2*i];
+				double imag = in[2*i + 1];
+				
+				out[i] = function.apply(real, imag);
+			}	
+		}
+	}
+	
+	//function that walks the 3D FFT from JTransforms and fills the sequence data array
+	//this is the version that does not swap the quadrants
+	public static class DirectAssign3D implements AssignFunction3D {
+		public void assign(double[] in, double[][][] out, int _w, int _h, int _z, int c,
+				DoubleDoubleFunction function) {
+			for(int z = 0; z < _z; z++)
+			{			
+				for(int y = 0; y < _h; y++)
+				{
+					for(int x = 0; x < _w; x++)
+					{
+						double real = in[(x + (y * _w) + (z * _w * _h))*2 + 0];
+						double imag = in[(x + (y * _w) + (z * _w * _h))*2 + 1];					
+						out[z][c][x + _w*y] = function.apply(real, imag);
+					}
+				}
+			}
+		}	
+	}
+	
+	// function that walks the 2D FFT from JTransforms and fills the sequence data array
+	// this is the version that swaps the quadrants
+	public static class SwapAssign2D implements AssignFunction2D{
+		public void assign(double[] in, double[] out, int _w, int _h,
+				DoubleDoubleFunction function)
+		{
+			int wc = (int) Math.ceil(_w/2);
+			int hc = (int) Math.ceil(_h/2);
+			
+			for(int y = 0; y < _h; y++)
+			{
+				for(int x = 0; x < _w; x++)
+				{
+					double real = in[(x + y*_w)*2 + 0];
+					double imag = in[(x + y*_w)*2 + 1];
+
+					int sx = (x + wc)%_w; // swap quadrants !
+					int sy = (y + hc)%_h;
+					
+					out[sx + _w*sy] = function.apply(real, imag);
+				}
+			}
+		}
+	}
+	
+	//function that walks the 3D FFT from JTransforms and fills the sequence data array
+	//this is the version that swaps the quadrants
+	public static class SwapAssign3D implements AssignFunction3D {
+		public void assign(double[] in, double[][][] out, int _w, int _h, int _z, int c,
+				DoubleDoubleFunction function) {
+			int wc = (int) Math.ceil(_w/2);
+			int hc = (int) Math.ceil(_h/2);
+			int zc = (int) Math.ceil(_z/2);
+
+			for(int z = 0; z < _z; z++)
+			{			
+				for(int y = 0; y < _h; y++)
+				{
+					for(int x = 0; x < _w; x++)
+					{
+						double real = in[(x + y * _w + z * _w * _h)*2 + 0];
+						double imag = in[(x + y * _w + z * _w * _h)*2 + 1];
+						
+						int sx = (x + wc)%_w; // swap quadrants !
+						int sy = (y + hc)%_h;
+						int sz = (z + zc)%_z;
+						
+						out[sz][c][sx + _w*sy] = function.apply(real, imag);
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/src/plugins/praveen/fft/ComplexFunctions.java b/src/plugins/praveen/fft/ComplexFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e385e8d3c996a070f344e4fae3065182d635724
--- /dev/null
+++ b/src/plugins/praveen/fft/ComplexFunctions.java
@@ -0,0 +1,37 @@
+package plugins.praveen.fft;
+
+import cern.colt.function.tdouble.DoubleDoubleFunction;
+
+public class ComplexFunctions {
+	public static class Real implements DoubleDoubleFunction
+	{
+		public double apply(double real, double imag)
+		{
+			return real;
+		}
+	};
+	
+	public static class Imag implements DoubleDoubleFunction
+	{
+		public double apply(double real, double imag)
+		{
+			return imag;
+		}
+	};
+	
+	public static class Magnitude implements DoubleDoubleFunction
+	{
+		public double apply(double real, double imag)
+		{
+			return Math.sqrt(Math.pow(real, 2) + Math.pow(imag, 2));
+		}
+	};
+
+	public static class Angle implements DoubleDoubleFunction
+	{
+		public double apply(double real, double imag)
+		{
+			return Math.atan2(imag, real);
+		}
+	};
+}
diff --git a/src/plugins/praveen/fft/FFT.java b/src/plugins/praveen/fft/FFT.java
new file mode 100644
index 0000000000000000000000000000000000000000..68f5b1d61aeb455805dd27fc3ca5c9c41466471c
--- /dev/null
+++ b/src/plugins/praveen/fft/FFT.java
@@ -0,0 +1,220 @@
+package plugins.praveen.fft;
+
+import cern.colt.function.tdouble.DoubleDoubleFunction;
+import edu.emory.mathcs.jtransforms.fft.DoubleFFT_2D;
+import edu.emory.mathcs.jtransforms.fft.DoubleFFT_3D;
+import icy.image.IcyBufferedImage;
+import icy.sequence.Sequence;
+import icy.type.DataType;
+import icy.type.collection.array.Array1DUtil;
+import plugins.adufour.blocks.lang.Block;
+import plugins.adufour.blocks.util.VarList;
+import plugins.adufour.ezplug.EzPlug;
+import plugins.adufour.ezplug.EzVarBoolean;
+import plugins.adufour.ezplug.EzVarEnum;
+import plugins.adufour.ezplug.EzVarSequence;
+import plugins.adufour.vars.lang.VarSequence;
+
+public class FFT extends EzPlug implements Block {
+
+	public static enum FFTDims {
+		FFT_2D("2D (xy)"), FFT_3D("3D (xyz)");
+		private String stringValue;
+		FFTDims(String s) { stringValue = s; }
+		public String toString() { return stringValue; }
+	}
+	
+	public static enum FFTOutputType {
+		MAGNITUDE_PHASE("Magnitude/Phase Pair"), REAL_IMAG("Real/Imaginary Pair");
+		private String stringValue;
+		FFTOutputType(String s) { stringValue = s; }
+		public String toString() { return stringValue; }
+	}
+	
+	EzVarSequence input = new EzVarSequence("Input");
+	EzVarEnum<FFTDims> ndims =  new EzVarEnum<FFTDims>("Type", FFTDims.values(), 0);
+	EzVarEnum<FFTOutputType> outputType =  new EzVarEnum<FFTOutputType>("Output as", FFTOutputType.values(), 0);
+	EzVarBoolean	swap = new EzVarBoolean("Swap Quadrants?", false);
+	
+	VarSequence fSequenceVar = new VarSequence("FFT sequence", null);
+
+	@Override
+	protected void initialize() {
+		super.addEzComponent(input);
+		super.addEzComponent(ndims);
+		super.addEzComponent(outputType);
+		super.addEzComponent(swap);
+		super.setTimeDisplay(true);
+	}
+	
+	// declare ourself to Blocks
+	@Override
+	public void declareInput(VarList inputMap) {
+		inputMap.add(input.name, input.getVariable());
+		inputMap.add(ndims.name, ndims.getVariable());
+		inputMap.add(outputType.name, outputType.getVariable());
+		inputMap.add(swap.name, swap.getVariable());
+	}
+
+	// declare ourself to Blocks
+	@Override
+	public void declareOutput(VarList outputMap) {
+		outputMap.add(fSequenceVar.getName(), fSequenceVar);
+	}
+
+	@Override
+	protected void execute() {
+		Sequence sequence = input.getValue();
+		Sequence fSequence = null;
+
+		if(ndims.getValue()==FFTDims.FFT_2D)
+		{		
+			fSequence = FFT_2D(sequence, swap.getValue(), outputType.getValue());
+		}
+		else
+		{
+			if (sequence.getSizeZ() >= 2)
+			{
+				fSequence = FFT_3D(sequence, swap.getValue(), outputType.getValue());
+			}
+			else
+			{
+				System.err.println("Sequence depth is 1, so computing 2D FFT instead of 3D.");
+				fSequence = FFT_2D(sequence, swap.getValue(), outputType.getValue());
+			}
+		}
+		
+		if (!isHeadLess()) {
+			addSequence(fSequence);
+		}
+		
+		fSequenceVar.setValue(fSequence);
+	}
+
+	private Sequence FFT_3D(Sequence sequence, boolean swap, FFTOutputType outputType) {
+		int _w = sequence.getSizeX();
+		int _h = sequence.getSizeY();
+		int _z = sequence.getSizeZ();
+
+		final DoubleFFT_3D fft = new DoubleFFT_3D(_z, _h, _w);
+		Sequence fSequence = new Sequence();
+		fSequence.setName("Fourier Transform 3D");
+
+		// allocate the output sequence
+		for(int k = 0; k < _z; k++)
+		{	
+			IcyBufferedImage fImage = new IcyBufferedImage(_w, _h, 2, DataType.DOUBLE);
+			fSequence.setImage(0, k, fImage);			
+		}
+		
+		double[] fArray = new double[_w*_h*_z*2];
+		// copy the data in fArray, with proper structure
+		for(int k = 0; k < _z; k++)
+		{
+			Array1DUtil.arrayToDoubleArray(sequence.getDataXY(0, k, 0), 0, fArray, k*_w*_h, _w*_h, sequence.isSignedDataType());
+		}
+
+		fft.realForwardFull(fArray);
+		
+		// direct reference to 3D byte array data [Z][C][XY] for specified t
+		double[][][] resultData = fSequence.getDataXYCZAsDouble(0);
+
+		DoubleDoubleFunction channel0ApplyFunction = null;
+		DoubleDoubleFunction channel1ApplyFunction = null;
+		if(outputType == FFTOutputType.MAGNITUDE_PHASE)
+		{
+			channel0ApplyFunction = new ComplexFunctions.Magnitude();
+			channel1ApplyFunction = new ComplexFunctions.Angle();
+			fSequence.setChannelName(0, "Magnitude");
+			fSequence.setChannelName(1, "Phase");
+		}
+		else
+		{
+			channel0ApplyFunction = new ComplexFunctions.Real();
+			channel1ApplyFunction = new ComplexFunctions.Imag();
+			fSequence.setChannelName(0, "Real");
+			fSequence.setChannelName(1, "Imaginary");
+		}
+		
+		AssignFunction3D assignFunction = null;
+		if(!swap)  // No Quadrant swapping. Leave as it is.
+		{
+			assignFunction = new AssignFunctions.DirectAssign3D();
+		}
+		else
+		{
+			assignFunction = new AssignFunctions.SwapAssign3D(); // Swap Quadrants
+		}
+		
+		assignFunction.assign(fArray, resultData, _w, _h, _z, 0, channel0ApplyFunction);
+		assignFunction.assign(fArray, resultData, _w, _h, _z, 1, channel1ApplyFunction);
+
+		fSequence.dataChanged();
+		
+		return fSequence;
+	}
+
+	private Sequence FFT_2D(Sequence sequence, boolean swap, FFTOutputType outputType) 
+	{
+		Sequence fSequence = new Sequence();
+		fSequence.setName("Fourier Transform 2D");
+		int _w = sequence.getSizeX();
+		int _h = sequence.getSizeY();
+		int _z = sequence.getSizeZ();
+
+		final DoubleFFT_2D fft = new DoubleFFT_2D(_h, _w);
+		
+		DoubleDoubleFunction channel0Function = null;
+		DoubleDoubleFunction channel1Function = null;
+		if(outputType == FFTOutputType.MAGNITUDE_PHASE)
+		{
+			channel0Function = new ComplexFunctions.Magnitude();
+			channel1Function = new ComplexFunctions.Angle();
+			fSequence.setChannelName(0, "Magnitude");
+			fSequence.setChannelName(1, "Phase");
+		}
+		else // Real/Imaginary Pair
+		{
+			channel0Function = new ComplexFunctions.Real();
+			channel1Function = new ComplexFunctions.Imag();
+			fSequence.setChannelName(0, "Real");
+			fSequence.setChannelName(1, "Imaginary");
+		}
+		
+		AssignFunction2D assignFunction = null;
+		if(!swap) //No Quadrant swapping
+		{
+			assignFunction = new AssignFunctions.DirectAssign2D();
+		}
+		else //Swap quadrants
+		{
+			assignFunction = new AssignFunctions.SwapAssign2D();
+		}
+
+		for(int k = 0; k < _z; k++)
+		{
+			double[] fArray = new double[_w*_h*2];
+			Array1DUtil.arrayToDoubleArray(sequence.getDataXY(0, k, 0), 0, fArray, 0, _w*_h, sequence.isSignedDataType());
+			
+			// Computes 2D forward DFT of real data leaving the result in fArray
+			// Because the result is stored in fArray, fArray must be of size rows*2*columns,
+			// with only the first rows*columns elements filled with real data.
+			fft.realForwardFull(fArray);
+
+			IcyBufferedImage resultArray = new IcyBufferedImage(_w, _h, 2, DataType.DOUBLE);
+			double[][] resultData = resultArray.getDataXYCAsDouble();
+					
+			assignFunction.assign(fArray, resultData[0], _w, _h, channel0Function);
+			assignFunction.assign(fArray, resultData[1], _w, _h, channel1Function);
+
+			resultArray.dataChanged();
+			fSequence.setImage(0, k, resultArray);
+		}
+
+		return fSequence;
+	}
+
+	@Override
+	public void clean() {
+	}
+}
\ No newline at end of file