How Can I Perform a 3D Fourier Transform on 2D Images Over Time in Python?

Click For Summary

Discussion Overview

The discussion revolves around performing a 3D Fourier Transform on a series of 2D images over time using Python. Participants explore the necessary steps to transition from 1D to 2D Fourier Transforms and then to 3D, addressing challenges encountered in the process.

Discussion Character

  • Exploratory, Technical explanation, Debate/contested, Mathematical reasoning

Main Points Raised

  • One participant describes their initial approach to performing a 3D Fourier Transform using a list of point sources and expresses uncertainty about transitioning from 1D to 2D images.
  • Another participant suggests using numpy arrays instead of Python lists for better performance and provides specific code snippets for creating 1D and 2D arrays.
  • A third participant comments on the unnecessary calculations in the Fourier Transform code, indicating that the magnitude can be computed directly from the absolute value of the Fourier coefficients.
  • A later post details an attempt to read an image and separate its color channels into a 3D array for Fourier Transform, but encounters an error related to plotting the resulting data.
  • Another participant recommends plotting the color channels separately and suggests a more efficient method for rearranging the image data using numpy functions.
  • There is a mention of using the real FFT functions (rfft2 or rfftn) for real-valued inputs to avoid redundancy in the Fourier Transform results.

Areas of Agreement / Disagreement

Participants express various approaches to the problem, and while some suggestions are made, there is no clear consensus on the best method to achieve the desired 3D Fourier Transform.

Contextual Notes

Participants note potential issues with the dimensions of the data being plotted and the implications of using different FFT functions based on the nature of the input data.

EnSlavingBlair
Messages
34
Reaction score
2
Hi,

My aim is to get a series of images in 2D space that run over different timestamps and put them through a 3D Fourier Transform. So my 3D FT has 2 spatial axes and one temporal axis. However I have never done anything like this before, and I have a very basic knowledge of Python.

So far, I can do the FFT for a list (or 1D array) of point sources as follows:

##
# Import libs
import matplotlib.pyplot as plt
import numpy as np

# create point sources
tmp = range(100)
source = [0 for x in tmp]
source.insert(50,1)
source.insert(5,1)
source.insert(60,0.5)

# make t useable later
t = np.array(source)

# equations for later
f = np.fft.fft(t)
g = np.sqrt(np.abs(f)**2)

# set up plot
fig = plt.figure()

# add sources to plot
ax1 = fig.add_subplot(211)
plt.plot(source)
ax1.set_title('Source')
ax1.xaxis.set_visible(False)

# add FT of sources to plot
ax2 = fig.add_subplot(212)
plt.plot(f)
ax2.set_title('Fourier Transform')
ax2.xaxis.set_visible(False)

# show plot
plt.show()
##

Now I would like to turn my 1D image into a 2D image, and I just can't work out how to do this. I've tried by doing something like this for my point sources:

##
# Array of 3 source lists
# Create list of lists - seems dodgy
tmp_array = range(3)
array_list = []

# create source lists to go in array
tmp = range(10)
source1 = [0 for x in tmp]
source1.insert(5,1)
source2 = [0 for x in tmp]
source2.insert(4,1)
source3 = [0 for x in tmp]
source3.insert(2,1)

# put lists in array
array_list.insert(1,source1)
array_list.insert(2,source2)
array_list.insert(3,source3)
##

Though calling it "source" instead of "array_list" would fit better with previous code.
However it is not working and I cannot figure out why.

I was also wandering if I need to bother with getting the 2D FT working before trying the 3D, or if I can just jump forward? Not that I have any idea how to do that yet.

Thank you for your help
 
Technology news on Phys.org
I would suggest creating arrays as numpy arrays first, not as Python lists:

For the 1d array:

t = np.zeros(103)
t[5] = 1
t[51] = 1
t[60] = 0.5

(if that was your intention)

For the 2d array:

array_list = np.zeros((3, 11))
array_list[0,5] = 1
# etc...

For a 2d fft of with real-valued input, use rfft2 or rfftn.

Note that for large FFT sizes, try to avoid a size with large prime factors, or pad out to the next largest power of 2 if that is unavoidable (using the optional size parameter). Fftpack seems to handle small prime factors like 3 or 5 OK, though.
 
One more comment:

f = np.fft.fft(t)
g = np.sqrt(np.abs(f)**2)
The sqrt and square here are unnecessary: np.abs(f) is already sqrt(f.real**2 + f.imag**2).
 
Thank you :)

I've gone for a slightly different approach now than above, and hitting different problems.

# A lot of this is taken from http://matplotlib.org/users/image_tutorial.html
# as well as http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.html

##
img=mpimg.imread('stinkbug.png')
img_red = img[:,:,0]
img_green = img[:,:,1]
img_blue = img[:,:,2]
# I assume this is taking the data in each of the red, green and blue columns?

array_list = []
array_list.append(img_red)
array_list.append(img_green)
array_list.append(img_blue)

t = np.array(array_list)
f = np.fft.fftn(t)
fshift = np.fft.fftshift(f)
magnitude_spectrum = np.log(np.abs(fshift))

fig = plt.figure()

ax1 = fig.add_subplot(211)
imgplot=plt.imshow(img)
ax1.set_title('FT this Bug')
imgplot.set_cmap('gray')
plt.colorbar()

ax2 = fig.add_subplot(212)
plt.imshow(magnitude_spectrum)
plt.colorbar()

plt.show()
##

I get the following error

###
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "image_test2", line 51, in <module>
plt.imshow(magnitude_spectrum)
File "/usr/lib/pymodules/python2.7/matplotlib/pyplot.py", line 2892, in imshow
imlim=imlim, resample=resample, url=url, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/axes.py", line 7300, in imshow
im.set_data(X)
File "/usr/lib/pymodules/python2.7/matplotlib/image.py", line 429, in set_data
raise TypeError("Invalid dimensions for image data")
TypeError: Invalid dimensions for image data
##

Which I believe is because I'm trying to plot 3 images in 1 2D image, where I should be making a very thin rectangular cube. Because the images are basically the same, I expect that all the information will be in the first part and only left-over stuff in the others as I am sampling a limited sized image. I just don't know how to do that!
 
Try plotting the red, green, and blue sections separately.

A few other comments on the code

nSlavingBlair said:
Thank you :)
img=mpimg.imread('stinkbug.png')
img_red = img[:,:,0]
img_green = img[:,:,1]
img_blue = img[:,:,2]
# I assume this is taking the data in each of the red, green and blue columns?

array_list = []
array_list.append(img_red)
array_list.append(img_green)
array_list.append(img_blue)

t = np.array(array_list)

This could more easily be achieved using rollaxis(img, 2, 0):

img_rgba = img.rollaxis(img, 2, 0)
img_rgb = img_rgba[:3]

f = np.fft.fftn(t)
fshift = np.fft.fftshift(f)
magnitude_spectrum = np.log(np.abs(fshift))

Again, for real-valued input, the fft will have a second set of redundant conjugate negative-frequency values (the shift just moves them to to the beginning of the array, IIRC). I suggest using rfftn.
 

Similar threads

  • · Replies 1 ·
Replies
1
Views
3K
  • · Replies 2 ·
Replies
2
Views
2K
Replies
13
Views
2K
Replies
5
Views
8K