2D Fourier transform

Every image is a sum of 2D sinusoids of different frequencies and orientations. See how much of each one an image contains, click a frequency to see its sinusoid, and filter the image by removing frequencies directly in the spectrum.

Image f(x,y)f(x, y) 256×256256 \times 256 px
Magnitude log⁡(1+∣F(u,v)∣)\log(1 + |F(u, v)|) DC in the center; tinted: removed by the filter
Filtered F−1{F⋅H}\mathcal{F}^{-1}\{F \cdot H\}
Phase ∠F(u,v)\angle F(u, v) black −π-\pi, white +π+\pi

The 2D discrete Fourier transform

The Fourier transform describes an image f(x,y)f(x, y) of N×NN \times N pixels by how much of each 2D sinusoid it contains:

F(u,v)=∑x=0N−1∑y=0N−1f(x,y) e−i2π(ux+vy)/N,f(x,y)=1N2∑u,vF(u,v) ei2π(ux+vy)/NF(u, v) = \sum_{x = 0}^{N - 1} \sum_{y = 0}^{N - 1} f(x, y) \, e^{-i 2\pi (ux + vy) / N}, \qquad f(x, y) = \frac{1}{N^2} \sum_{u, v} F(u, v) \, e^{i 2\pi (ux + vy) / N}

With eiθ=cos⁡θ+isin⁡θe^{i\theta} = \cos\theta + i \sin\theta, each term is a wave across the image: uu cycles along xx and vv cycles along yy. Its period is N/u2+v2N / \sqrt{u^2 + v^2} pixels, its stripes run perpendicular to the direction (u,v)(u, v), and the second formula says that the image is exactly the sum of all these waves. For a real image, F(−u,−v)F(-u, -v) is the complex conjugate of F(u,v)F(u, v), so the two coefficients together form one real cosine

Acos⁡ ⁣(2π(ux+vy)/N+φ),A=2∣F(u,v)∣N2,φ=∠F(u,v).A \cos\!\big(2\pi (ux + vy) / N + \varphi\big), \qquad A = \frac{2 |F(u, v)|}{N^2}, \quad \varphi = \angle F(u, v).

The magnitude ∣F∣|F| says how strong the wave is, the phase φ\varphi where its crests lie. The transform is computed with the fast Fourier transform, which splits it into smaller transforms and needs about N2log⁡2N2N^2 \log_2 N^2 operations instead of N4N^4.

Reading the spectrum

The spectrum is shown with (0,0)(0, 0) in the center. That is the DC term, the sum of all pixels; low frequencies lie close to it, fine detail far out, up to the Nyquist frequency ±N/2\pm N/2 at the border. The magnitudes cover many orders of magnitude, so they are shown on a logarithmic scale. Natural images have most of their energy at low frequencies. A straight edge contains all frequencies perpendicular to it and shows up as a line through the center, rotated by 90° against the edge. The transform treats the image as periodic, so the jumps between opposite borders act as edges too: they cause the bright horizontal and vertical lines through the center.

The phase looks like noise, but it carries much of the structure: where the edges are. Without the right phases, the waves would not add up to the image.

Filtering in the frequency domain

Multiplying the spectrum by a transfer function H(u,v)H(u, v) and transforming back scales every wave separately. A low-pass filter keeps the frequencies within a radius D0D_0 and blurs the image; a high-pass filter 1−Hlow1 - H_\text{low} removes the low frequencies and keeps edges and texture; a band-pass filter keeps a ring between D0D_0 and D1D_1. A filter with H(0,0)=0H(0, 0) = 0 removes the mean brightness, so the result is shown around the original mean.

The ideal filter cuts off abruptly at D0D_0. Just like cutting off a Fourier series, this causes ringing next to edges. The Gaussian profile e−D2/2D02e^{-D^2 / 2 D_0^2} falls off smoothly and does not ring.

Periodic noise, such as interference stripes from a scanner or sensor, is a single sinusoid: two bright peaks at ±(u,v)\pm (u, v) in the spectrum. Setting H=0H = 0 at just these two spots, a notch filter, removes the stripes and leaves the rest of the image almost unchanged, which no spatial blur can do.

The convolution theorem

Convolution in the image domain is multiplication in the frequency domain:

F{f∗h}=F{f}⋅F{h}=F⋅H\mathcal{F}\{f \ast h\} = \mathcal{F}\{f\} \cdot \mathcal{F}\{h\} = F \cdot H

Every convolution filter therefore has a transfer function HH, the Fourier transform of its kernel, and filtering via the spectrum gives the same result as sliding the kernel, if the image is extended periodically at the border. A Gaussian kernel with σ\sigma pixels has a Gaussian transfer function with σu=N/(2πσ)\sigma_{u} = N / (2\pi\sigma): the wider the blur, the narrower the band of frequencies it keeps. A box kernel has a transfer function with ripples that become negative: it lets some high frequencies through and even inverts some of them, which makes it a poor low-pass filter. For large kernels, the detour over the spectrum is also faster, since its cost does not depend on the kernel size.

Try this