Is it a bug or just me?

plugin
fft
java

#1

Okay… this time only pictures… This is my input (2048x2048):

This is the FFT of it in my Java-Plugin (1041x2520):

This is the FFT as it comes out in ImageJ (simply as user using the FFT-Plugin, 2048x2048)

and this is the code leading to the wrong FFT: (floatImg is the input which was copied from a View)

ImgFactory<ComplexFloatType> fftImgFactory = null;
fftImgFactory = floatImg.factory().imgFactory(new ComplexFloatType());
Img<ComplexFloatType> fft = FFT.realToComplex(floatImg, fftImgFactory);
// … ImagePlus imp = ImageJFunctions.wrap(fft,“SomeTitle”);
uiService.show(floatImg);
ImageJFunctions.show(fft);

I also tried opService.run(…) , but must have done something wrong. I can’t put it in words how much I would appreciate someone helping me out now!


#2

Please see my post in your other DFT-thread:
https://forum.image.sc/t/regular-discrete-fourier-transform-dft/20387/2?u=herbie

Regards

Herbie


#3

Hi,
well, I don’t much about the Fiji/ImageJ2 functions, but I think the main difference is that ImageJ shows the origin at the center of the image, your FFT at the top shows it at the edge. Is this what you refer to as “wrong FFT”? You can switch between the two views with Process>FFT>Swap Quadrants.
Also note that the display of the FFT (at least the Process>FFT of ImageJ1) is the power spectrum with logarithmic grayscale, which shows many weak features that would otherwise remain invisible.
Anyhow, in both FFTs one can nicely see the rings caused by all the roughly circular features with ~ 70 pixels diameter of the inner dark region in your original images.


#4

Dear Michael,

one of the FT-related implementations of ImageJ-2 shows only one half of the Fourier-spectral plane.

Of course and independently, your remark concerning the qudrants is a valid one.

I fear howvever that the OP refers to the very ImageJ-2 implementation (see the obove link).

Best

Herbie


#5

Hi @KansasCityShuffle

Both look correct they are just in different coordinate systems and formats.

The first looks like it was generated by the imglib2 implementation and/or ops. This implementation has the origin at 0,0 and does not keep the redundant pixels.

If you are coding in imglib2 you should use the imglib2 version of FFT, if you are working in imagej1 then it probably makes sense to use the IJ1 version.

In the Fiji script editor, under ‘Templates->Filters->’ there is an example called “Lowpass.groovy” that shows how to interact with the ‘imglib2’ FFT format.

#@ OpService ops
#@ UIService ui
#@ ImgPlus img
#@ Integer radius
#@OUTPUT ImgPlus filtered

import net.imglib2.img.display.imagej.ImageJFunctions
import net.imglib2.util.Util
import net.imglib2.FinalDimensions

// perform fft of the input
inputFFT=ops.filter().fft(img)

// display fft (by default it will be a generalized log power spectrum)
// note that frequency 0,0 is at the origin and that the dimension in x dimensions is half that in y
// this stack overflow question explains the reason the first transformed dimensions is half that of the second
// http://stackoverflow.com/questions/17322449/fftw-size-of-output-array-for-2d-fourier-transform-of-3d-data
ImageJFunctions.show(inputFFT).setTitle("fft power spectrum")

// get a cursor so we can loop through the FFT
fftCursor=inputFFT.cursor()
// declare an array to hold the current position of the cursor
pos = new long[ inputFFT.numDimensions() ];

// define origin as 0,0
def origin=[0,0] as long[]

// define a 2nd 'origin' at bottom left of image.  This is a bit of a hack.  We want to draw a circle around the origin, since the origin
// is at 0,0 - the circle will 'reflect' to the bottom
def origin2=[0,inputFFT.dimension(1)] as long[]

// loop through all pixels
while (fftCursor.hasNext()) {
	
	fftCursor.fwd()
	fftCursor.localize( pos );

	// calculate distance from 0,0 and bottom left corner (so we can form the reflected semi-circle)
	dist = Util.distance( origin, pos )
	dist2 = Util.distance( origin2, pos )

	// if distance is above radius (cutoff frequency) set value of FFT to zero 
	if ( (dist>radius) & (dist2>radius)) {
		fftCursor.get().setZero()
	}

}

// show FFT after bandpass, shoudl have "semicircle" around 0,0
ImageJFunctions.show(inputFFT).setTitle("fft after bandpass")

// create Img memory for inverse FFT and compute inverse 
inverse=ops.create().img([img.dimension(0), img.dimension(1)] as long[])

// perform inverse and show
ops.filter().ifft(inverse, inputFFT)
ui.show("template inverse", inverse)