Blur: Gaussian, Median and Bilateral

Three ways to remove noise. One smears edges, one ignores outliers, one refuses to cross a boundary.

Overview

The same job, three different assumptions

All three filters answer the same question. What should this pixel be, given its neighbours? — and they differ in what they assume about how the pixel got corrupted. That assumption is the whole story, and it's why one filter can be great on one kind of noise and useless on another.

The image in the visualisation carries salt-and-pepper noise: isolated pixels flipped to pure black or pure white. Switch between the three filters and the difference isn't subtle.

Blur: Gaussian, Median and Bilateral

This module needs JavaScript: the images are computed in the page rather than downloaded.

Worth knowing

Gaussian blur is a weighted average. An outlier is included in the average, so it is spread out rather than removed.
The median filter sorts the neighbourhood and takes the middle value. An outlier is never the middle value, so it disappears completely.
Bilateral filtering weights neighbours by both distance and similarity, so it averages within a region but not across a boundary.
The source image here has salt-and-pepper noise, which is the case that separates the three most clearly.

Blur: Gaussian, Median and Bilateral

Three smoothing filters, one noisy image. A clear demo of why the choice matters.

Gaussian: a weighted average

A Gaussian blur replaces each pixel with a weighted mean of its zone, where the weights fall off with distance per to a Gaussian curve. The centre counts most, the corners least.

It's the right filter when the noise is additive and roughly even — each pixel nudged up or down by a small random amount. Blending a few such pixels cancels the nudges, because they're as often plus as minus. Sensor noise in reasonable light behaves like this, and a Gaussian handles it well.

On salt-and-pepper it fails, and the reason is structural: a mean includes each value it's given. A single pixel at 255 sitting among neighbours at 40 drags the mean up. The filter doesn't drop the outlier — it *spreads* it over the zone, converting one bright dot into a larger, dimmer smudge. Grow the radius and the smudges grow rather than vanishing.

The other cost is edges. An edge is a place where neighbouring pixels are truly different, and blending across it mixes the two sides together. Any filter based on a plain mean must blur edges. It has no way to know that an edge is there.

Median: sorting instead of averaging

The median filter takes the zone, sorts the values, and outputs the middle one.

This one change fixes salt-and-pepper fully. To be selected as the median, a value has to sit in the middle of the sorted list — and an extreme value, by meaning, sorts to one end. It's never chosen. It isn't reduced or spread. It's simply not selected, and the output takes a value that some genuine neighbouring pixel really had.

Set the filter to Median with radius 2 above. The speckles don't fade. They are gone, and the shapes underneath keep their edges. That edge preservation is the second gain: at a boundary, most of the zone belongs to one side or the other, so the median comes from the majority side rather than from a blend of both.

The median is a non-linear filter. This Means it can't be expressed as a convolution kernel and can't be broken down into separate flat and vertical passes. It's correspondingly slower, since a sort is needed at each pixel.

Bilateral: averaging only within a region

The bilateral filter keeps the weighted mean but times each weight by a second factor based on how similar the neighbour's *value* is to the centre pixel's.

weight = spatial(distance) * range(|neighbour - centre|)

A neighbour that is nearby and similar gets a large weight. A neighbour that is nearby but very different — because it's on the other side of an edge — gets a weight close to zero and is in effect excluded.

The result smooths within a region and refuses to smooth across a boundary. It is what makes the slightly plastic look of smartphone portrait modes: skin is smoothed heavily while the outline of the face stays sharp.

The edge sigma control sets how different a neighbour has to be before it's skipped. Turn it low and the filter barely does any of it, because almost all counts as an edge. Turn it high and the range term stops telling apart, and you've an plain Gaussian blur back.

Choosing

NoiseUseBecause
Small random variationGaussianaveraging cancels symmetric errors
Isolated extreme pixelsMedianoutliers never sort to the middle
Any, with edges to protectBilateraldissimilar neighbours are excluded
Impulse noise before thresholdingMedianextremes survive every threshold otherwise

A hands-on note: these compose. Median first to drop impulses, then a gentle Gaussian to handle what remains, is a common and effective pipeline.

Mean against median, on one neighbourhood

The three filters differ in what they assume about the noise, and a single salt-and-pepper zone shows why the choice isn't cosmetic. Take a 3×3 window of pixels around value 40, with two corrupted to the extremes — a 255 (salt) and a 0 (pepper):

[40, 42, 255, 41, 39, 38, 43, 40, 0]

filteroutput
mean (Gaussian-like)59.8 — dragged up, the 255 spread over the region
median40 — the extremes sort to the ends and are never chosen

A mean *includes each value it's given*. The 255 doesn't get removed, it gets smeared into a dimmer smudge, and the 0 pulls the other way. The output, 59.8, resembles neither the true signal nor the noise. The median sorts the nine values and takes the middle one, and an extreme by meaning sorts to an end, so it's simply not selected — the output is a value some real neighbour really had. That is why median filtering drops salt-and-pepper fully while a Gaussian can't, and why it also preserves edges: at a boundary most of the window belongs to one side, so the majority side supplies the median. The cost is that it's non-linear, so it can't be separated into two 1D passes and needs a sort per pixel. The bilateral filter keeps the mean but zeroes the weight of neighbours too different in value, which is how it smooths within a region and refuses to smooth across an edge.

Where it goes wrong with Blur

Blurring before edge spotting without thinking. Some blur helps, since edge finders amplify noise. Too much drops the edges you were looking for. The Canny finder builds a Gaussian in for just this reason, with a param to control it.

Using a large median radius on fine detail. Thin lines narrower than half the window are a minority in each zone they appear in, so the median drops them along with the noise.

Reaching for bilateral by default. It's far more costly than the other two and has two params instead of one. If the edges don't need protecting, it's a slow Gaussian.

Questions people ask about Blur

Which blur should I use to remove salt-and-pepper noise? The median filter. It discards extreme outliers by sorting the neighbourhood, whereas a Gaussian smears each speck into its neighbours.

Why does a Gaussian blur soften edges? It averages across an edge, mixing dark and bright pixels together. It has no way to tell an edge from a gradual change.

How does a bilateral filter keep edges sharp? It weights neighbours by both distance and similarity of colour. Pixels across an edge look very different, so they get almost no weight and the edge survives.

How do I pick the kernel size or sigma? Sigma sets how much smoothing happens, and the kernel only needs to be about six sigma wide to hold the bell shape. Raise sigma until noise is gone, then stop, since every extra step loses detail.

Why is the bilateral filter so slow? Its weights depend on pixel values, so they must be recomputed at every position, and it cannot be split into two separable passes. Large diameters get costly quickly.

Should I blur before edge detection? Usually yes. Gradient kernels amplify noise, so a light Gaussian blur first gives cleaner edges, which is why Canny begins with one.

Three blurs, and the one that keeps edges

Gaussian, median and bilateral filtering on the same noisy image. Each drops a different kind of noise and damages a thing different. The numbers show just which.

example_01.pyNumPy
Output

The median filter sorts each neighbourhood and picks the middle value, which drops outliers entirely.

example_02.pyNumPy
Output

Bilateral filtering weights neighbours by both distance and similarity, so it smooths within a region but refuses to cross a boundary.

example_03.pyNumPy
Output

Running all three filters on both noise types shows the quantitative separation between them.

example_04.pyNumPy
Output

Check yourself

0 of 3

Answer without scrolling back up.

  1. Why does a Gaussian blur fail to remove salt-and-pepper noise?

  2. Why does the median filter remove an outlier completely?

  3. What happens to a bilateral filter as its range sigma grows very large?

Cheat sheet

Blur: Gaussian, Median and Bilateral

Apply Gaussian, median and bilateral blur to one noisy image side by side and see which filter removes noise while preserving edges.

COMPUTER VISION · vizlearn.in/computer_vision/blur_gaussian_median_bilateral.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.