Skip to content
AI360XpertBeta

Frequency Domain Image Processing

Instead of viewing an image as a grid of pixels, frequency domain processing treats it as a sum of 2D sine and cosine waves, allowing us to easily filter out noise or isolate specific patterns.

Striped pixels become two spectral dots, a notch mask deletes them, and the inverse transform returns a clean flat image
Striped pixels become two spectral dots, a notch mask deletes them, and the inverse transform returns a clean flat image

Why Does This Exist?

When you look at an image in the spatial domain (its raw pixels), certain problems are notoriously difficult to solve. A photograph corrupted by a repeating striped pattern resists pixel-by-pixel repair, because the interference touches every pixel and any local edit damages the scene underneath.

The frequency domain provides an entirely different perspective. By breaking the image into its wave frequencies, global patterns become isolated points: a repeating stripe covering the whole image turns into a single bright pair of dots. Erase that pair, convert back, and the interference vanishes. The transform itself is covered in Fourier transform for images; this page is the three-step filter round trip, the spatial counterpart of which lives in spatial filtering.

Think of It Like This

A musical chord versus sheet music

Imagine hearing a complex chord played on a piano (the spatial domain image). Removing one out-of-tune string by listening to the combined sound is nearly impossible because all notes arrive mixed together.

Transcribe that chord into sheet music (the frequency domain) and each note stands visible on its own line. Erase the bad note, replay the score, and the chord rings clean. Where it stops: sheet music still tells you when each note plays, while the basic spectrum forgets where things sit, so location needs phase or wavelets rather than magnitude alone.

How It Actually Works

Processing in this domain always follows three steps: transform the image with the 2D FFT, multiply the spectrum by a filter mask, and apply the inverse FFT to return to pixels. The mask decides the effect. A low-pass mask keeps the center and drops the rim, which blurs the image and calms noise. A high-pass mask keeps the rim and drops the center, which exposes edges while flattening smooth backgrounds. A notch mask zeroes one chosen pair of dots, which deletes one repeating pattern and nothing else.

Worked example

Take the striped 2×22 \times 2 image [02550255]\begin{bmatrix} 0 & 255 \\ 0 & 255 \end{bmatrix} with mean 510/4=127.5510 / 4 = 127.5. Its spectrum holds DC =510= 510 plus the horizontal pair term −510-510. A notch mask zeroes the pair term and keeps DC untouched. The inverse transform of the surviving [[510,0],[0,0]][[510, 0], [0, 0]] divides by 4 at every pixel, returning a perfectly flat [127.5127.5127.5127.5]\begin{bmatrix} 127.5 & 127.5 \\ 127.5 & 127.5 \end{bmatrix}. Stripes gone, average brightness preserved, each number traceable: 510/4=127.5510 / 4 = 127.5 everywhere.

Code

The point of this snippet is the full round trip in standard-library-only code: forward DFT, notch mask, inverse DFT, ending on the flat 127.5 the prose derived by hand.

def dft2(img):    out = [[0] * 2 for _ in range(2)]    for u in range(2):        for v in range(2):            s = 0            for x in range(2):                for y in range(2):                    s += img[x][y] * ((-1) ** (u * x + v * y))            out[u][v] = s    return out
def idft2(spec):    out = [[0.0] * 2 for _ in range(2)]    for x in range(2):        for y in range(2):            s = 0            for u in range(2):                for v in range(2):                    s += spec[u][v] * ((-1) ** (u * x + v * y))            out[x][y] = s / 4    return out
spec = dft2([[0, 255], [0, 255]])print(spec)# -> [[510, -510], [0, 0]]spec[0][1] = 0  # notch mask deletes the stripe pair, keeps DCprint(idft2(spec))# -> [[127.5, 127.5], [127.5, 127.5]]

The mask line is the whole filter: one assignment removes the stripes, and the inverse confirms every pixel lands on the original mean of 127.5.

Watch Out For

Ringing artifacts from hard mask edges

A hard circular mask of ones and zeros (an ideal filter) has a sharp cutoff that paints ripple waves around edges in the rebuilt image. The symptom is ghost ripples near strong contours after an otherwise successful denoise. Use a smooth rolloff such as a Gaussian or Butterworth mask instead.

Filtering without padding the borders

The DFT treats the image as one tile in an infinite repeating grid, so opposite borders leak into each other during filtering. The symptom is wrap-around ghosts where the left edge bleeds into the right. Pad the image before transforming and crop after the inverse.

The Quick Version

  • The frequency domain treats an image as a sum of 2D waves rather than a grid of pixels.
  • Filtering means transform, multiply by a mask, and inverse-transform back.
  • The worked notch proves it: deleting −510-510 from [[510,−510],[0,0]][[510, -510], [0, 0]] returns flat 127.5 everywhere.
  • Low-pass blurs, high-pass exposes edges, notch deletes one repeating pattern.
  • Smooth mask edges and padded borders keep the rebuild free of ringing and ghosts.