Skip to content
AI360Xpert
Beta

Gaussian Filter Smooths With a Bell Curve

A Gaussian filter blends each pixel with its neighbours, weighting close neighbours most by a bell curve, so noise fades while shapes stay fair.

A Gaussian kernel piles weight on the center and tapers outward, so close neighbours shape the output most.
A Gaussian kernel piles weight on the center and tapers outward, so close neighbours shape the output most.

Why Does This Exist?

A box blur treats a distant neighbour the same as an adjacent one, which is why it looks harsh and erases corners. Real optical blur falls off with distance, brightest at the center and fading outward. The Gaussian kernel copies that falloff with the bell curve G(x,y)=12πσ2e−(x2+y2)/(2σ2)G(x, y) = \frac{1}{2\pi\sigma^2} e^{-(x^2+y^2)/(2\sigma^2)}, where σ\sigma (sigma) sets the width of the trust.

It is the default pre-filter in the smoothing family and the opening step of the Canny detector, which differentiates noise without it. When edges themselves must survive the smoothing, step up to the bilateral filter; when salt-and-pepper spikes dominate, prefer the median filter.

Think of It Like This

Asking neighbours for advice

You weight advice by distance: your own judgment most, next-door neighbours somewhat, strangers across town barely. Sigma is how far your trust reaches. A tiny sigma trusts only yourself, so nothing changes; a huge sigma trusts the whole town equally, and every opinion blurs into mush. Good smoothing, like good advice, listens widely but trusts locally.

Where it stops: neighbours cannot fix a lie everyone repeats, and a Gaussian cannot fix structured interference or dead pixels, because it only averages whatever values it is given.

How It Actually Works

Sample the bell curve over a window, typically 3×33 \times 3 or 5×55 \times 5, and normalize so the weights sum to 1. The classic 3×33 \times 3 kernel with σ≈0.85\sigma \approx 0.85 is:

116[121242121]\frac{1}{16}\begin{bmatrix} 1 & 2 & 1 \\ 2 & 4 & 2 \\ 1 & 2 & 1 \end{bmatrix}

The center carries 4/164/16 of the vote, edge-adjacent cells 2/162/16 each, and corners only 1/161/16 each. Because the 2D bell curve factors into horizontal times vertical, filtering runs as two 1D passes: O(k)O(k) work per pixel instead of O(k2)O(k^2), which is what separability buys.

Worked example

Drop one bright impulse of value 100100 into darkness:

[00001000000]\begin{bmatrix} 0 & 0 & 0 \\ 0 & 100 & 0 \\ 0 & 0 & 0 \end{bmatrix}

The outputs follow directly from the weights. Center: 100⋅4/16=25100 \cdot 4/16 = 25. Each edge-adjacent pixel: 100⋅2/16=12.5100 \cdot 2/16 = 12.5. Each diagonal pixel: 100⋅1/16=6.25100 \cdot 1/16 = 6.25. Conservation check: 25+4⋅12.5+4⋅6.25=25+50+25=10025 + 4 \cdot 12.5 + 4 \cdot 6.25 = 25 + 50 + 25 = 100, so no brightness leaks away. A box mean would put 100/9≈11.1100/9 \approx 11.1 everywhere in the window, keeping less of the spike at the center and spreading more to the corners, which is exactly the harshness the bell curve avoids.

Code

Pure Python, no imports: apply the 3×33 \times 3 kernel to the impulse fixture and confirm the hand computation, including conservation.

kernel = [    [1, 2, 1],    [2, 4, 2],    [1, 2, 1],]impulse = [    [0, 0, 0],    [0, 100, 0],    [0, 0, 0],]
out = [    [sum(kernel[1 - di][1 - dj] * impulse[i + di][j + dj]         for di in (-1, 0, 1) for dj in (-1, 0, 1) if 0 <= i + di < 3 and 0 <= j + dj < 3) / 16     for j in range(3)]    for i in range(3)]print(out[1][1], out[0][1], out[0][0])# -> 25.0 12.5 6.25print(sum(map(sum, out)))# -> 100.0

Center 25.025.0, edge 12.512.5, corner 6.256.25, total 100.0100.0: brightness is preserved, just redistributed with the center trusted most.

Watch Out For

Sigma too large erases small objects

Every sigma increment widens the bell and mixes in more distant pixels. The symptom is small targets shrinking below detection size after the blur. Size the window to the noise, not the objects: use the smallest sigma that kills the grain, and never out-blur the smallest target.

Blurring across edges then wondering where they went

A Gaussian mixes pixels from both sides of every boundary, so strong edges come out rounded and thin lines fade. The symptom is a Canny detector returning broken contours on an over-smoothed image. Fix: keep sigma small before detection, or switch to the edge-preserving bilateral filter when the boundary itself is the signal.

The Quick Version

  • Gaussian weights fall off as a bell curve controlled by sigma, with close neighbours trusted most.
  • The 3×33 \times 3 kernel sums to 1616, with 44 at the center, 22 on edges, and 11 in corners.
  • The impulse fixture gives center 2525, edges 12.512.5, diagonals 6.256.25, conserving 100100 total.
  • The kernel separates into two 1D passes, cutting per-pixel work from O(k2)O(k^2) to O(k)O(k).
  • It is the standard hush before Sobel, Laplacian, and Canny, but it rounds edges and erases small targets when sigma runs too large.