# What is the relation between image resolution and Cutoff from 2D FFT functions in frequency space?

This might be dumb, but unfortunately I need some urgent help about Cutoff from 2D FFT functions in frequency space.

I am writing my bachelor thesis, near DDL and cannot get a lot of help offline in uni.

The current task is: Get the resolution of image. The instruction is to "transform" raw image to 2D FFT functions in frequency space, and then get the Cutoff from FFT function. And somehow, I will then get the resolution from the cutoff.

The following pictures are my current state of work:

I am now able to get 2D FFT from image and 2D FFT functions in spatial space in FIJI. I should be able to find out how to transform 2D FFT functions in spatial space to frequency space. Yet I have no idea what is the relation between image resolution and Cutoff from 2D FFT functions in frequency space.

May anyone explain it at least mathematically? Practical instructions are also very welcomed.

I am also searching related pages and articles online. If it would be lengthy, I am glad to read an existing article. Just send a link in reply.

#### Frequencies in an image

The image of an object consists of many frequencies. High frequencies correspond to quickly varying intensity and likewise low frequencies correspond to slowly varying features. So high frequencies capture the details of an image, while low frequencies capture the overall shape. Due to the diffraction limit, a microscope can only capture frequencies up to a certain point. Roughly speaking, the diffraction limit depends on the wavelength of the length of the strength of your strongest lens.

If you look at an image whose resolution is lower than your camera resolution, you will see that in Fourier space your image lives inside a certain circle. This circle is not sharply defined, but rather smoothed out. To find out what this radius is you could do two things. You could find the circle in Fourier space that contains most of your image. Or, you could transform your image to Fourier spae, cut out everything outside a particular circle, transform back and see if your image has degraded. If your image has not degraded (by much), you know that your circle contains all of your image's frequencies.

#### Explanation of image

Below, I did this procedure on an artificially created image. The width of the stripes is given by 1 1 2 2 4 4 8 8 etc. In Fourier space I cut out everything outside of the red circle, which corresponds to $$\lambda=8$$. In the final image you can see that the stripes of width 4 4, which have a wavelength of 8, can be resolved just fine. But stripes narrower than that are not resolvable.

#### Scale in Fourier space

Note that an important part of this procedure relies on knowing which parts in Fourier space correspond to which wavelengths. To figure this out you can make use of the following facts.

1. I define the window of the image in real space to be of width $$[0,x_{max})$$. This means the size of a pixel is given by $$dx=n/x_{max}$$, where $$n$$ is the number of pixels. Note that $$x_{max}$$ is excluded because of periodicity.
2. The Fast Fourier Transform (FFT) sends this image to $$[0,k_{max})$$. Likewise, we have $$dk=n/k_{max}$$. To relate Fourier space to real space we need a linking equation: \begin{align} \begin{cases} n\,dx\,dk=1&\text{k in cycles/length}\\ n\,dx\,dk=2\pi&\text{k in radians/length} \end{cases} \end{align} So $$k$$ is either defined as $$k=2\pi/\lambda$$ for radians/length or $$k=1/\lambda$$ for cycles per length. Numpy, for example, uses cycles per length. But in physics we often use the radians per length convention.
3. The FFT defines the (0,0) point of an image as the origin. If you want to display images with the origin in the center, you may need to "roll" the image a few times to place the top-left corner in the center.

As a final note, this is just one hackish way to get the resolution of the image. There are probably better ways.

I hope you enjoy your thesis!

import numpy as np
import matplotlib.pyplot as plt

n = 150

img = np.zeros((n, n))

# Making a multiple resolution image
cur_width = 1
pointer = 0
while pointer < n:
img[pointer:pointer+cur_width,pointer:] = 1
img[pointer:,pointer:pointer+cur_width] = 1
pointer += 2*cur_width
cur_width *= 2

img += np.random.rand(*img.shape)*.1

fig, axes = plt.subplots(ncols=3, dpi=200)
plt.rcParams.update({'font.size': 8})
axes[0].imshow(img)
axes[0].set_xlabel('x (pixels)')

# Calculating FFT and centering
fft = np.fft.fftshift(img)
fft = np.fft.fft2(fft)
fft = np.fft.fftshift(fft)

# cutting out hole in frequency space
cutoff_wavelength = 8
cutoff_k = 1/cutoff_wavelength
dx = 1.0
k = np.fft.fftfreq(n, d=dx)
k = np.fft.fftshift(k)
Kx, Ky = np.meshgrid(k, k)
fft_cutoff = fft*(Kx**2  + Ky**2 < cutoff_k**2)

# plotting result with right scale
dk = 1/(n*dx)
krange = n*dk
kmin = -krange/2
kmax = krange/2 - dk
axes[1].imshow(np.log(1 + np.abs(fft)), extent=[kmin, kmax, kmin, kmax])
circ = plt.Circle((0,0), cutoff_k, color='r', fill=False)
axes[1].set_xlabel('k (1/pixels)')

# transforming back to real space, making sure the zero frequency is in the (0, 0) corner
img_low_resolution = np.fft.fftshift(fft_cutoff)
img_low_resolution = np.fft.ifft2(img_low_resolution)
img_low_resolution = np.fft.fftshift(img_low_resolution)

img_low_resolution[n-8:n, :] = img[n-8:n,:]*np.max(img_low_resolution)
axes[2].imshow(np.real(img_low_resolution))
axes[2].set_xlabel('x (pixels)')

plt.tight_layout()
plt.show()

• Thank you very much! Commented Mar 8 at 16:17
• Thank you very much! Now I have understood more about what should be practically be done. But your answer also helped me a lot by connecting already known but fractured theories in my mind! I have just understood spatial frequency (more or less). Should be able to finish it soon. Commented Mar 8 at 16:23