Histograms and Equalisation
The histogram tells you what an image is made of. Equalisation rewrites it to use the whole range.
Overview
Counting, not looking
An image histogram is a count: for each of the 256 possible brightness values, how many pixels hold it. Nothing else. It discards position entirely — an image and the same image shuffled into random order have identical histograms.
That sounds like a weakness and is mostly a strength. Exposure, contrast and the presence of distinct regions are all properties of the *distribution* of values, not of where they sit, so the histogram is exactly the right summary for judging them. Photographers read one on the back of a camera for this reason.
Watch the two histograms under the visualisation above. The input image is deliberately low in contrast, so its histogram is a narrow spike: almost every pixel sits between roughly 100 and 160, and the ranges below and above are empty. Two hundred of the 256 available values are being wasted.
Histograms and Equalisation
Worth knowing
Histograms and Equalisation
What an image is made of, and how to make it use the range it has.
What a shape means
A spike in the middle is low contrast. The image is grey and flat, and detail exists but the differences are too small to see.
A wide, flat spread is high contrast, using the full range.
Two separated humps — a bimodal histogram — means the image has two distinct populations of pixel, usually an object and a background. This is the shape that makes [thresholding](thresholding.html) work, and the valley between the humps is where the threshold belongs.
A pile against the right edge is clipping: pixels that were brighter than 255 have all been recorded as 255. That detail is gone and no amount of processing brings it back, which is why photographers expose to avoid it.
How equalisation works
Histogram equalisation asks a specific question: what mapping from old values to new ones would make the histogram as flat as possible?
The answer is the cumulative distribution function. For each value *v*, compute the fraction of pixels whose value is at most *v*. That fraction is between 0 and 1; multiply by 255 and you have the new value for *v*.
cdf[v] = (number of pixels <= v) / (total pixels)
new[v] = round(cdf[v] * 255)Why this works is worth a moment. If a value is very common, the CDF climbs steeply across it, so values on either side get mapped far apart — crowded regions are spread out. If a range of values is rare or absent, the CDF is nearly flat there, so that whole range collapses to almost a single output value. The transformation gives range to where the pixels actually are, and takes it away from where they are not.
Toggle the control above and watch both the image and the output histogram. The narrow spike is pulled apart across the full width, and detail that was present but invisible — the difference between the triangle and the background — becomes plainly visible.
What it costs
Equalisation is not free, and the costs follow directly from the mechanism.
It amplifies noise. In a region that is genuinely flat, the small random variations between neighbouring pixels are still variations, and stretching the range stretches them too. A clear sky becomes a mottled one.
It is global. One lookup table is computed from the whole image and applied everywhere. An image that is correctly exposed on the left and dark on the right gets a compromise that suits neither.
The result is not natural. Faces in particular look wrong after equalisation, because skin tones occupy a narrow band and equalisation deliberately spreads narrow bands apart.
CLAHE
The standard fix for the second and third problems is CLAHE, Contrast Limited Adaptive Histogram Equalisation. It divides the image into tiles, equalises each tile against its own histogram, and interpolates between tiles so the boundaries do not show. The dark region gets its own aggressive stretch; the well-exposed region is left more or less alone.
The "contrast limited" half addresses the noise. Before computing the CDF, any histogram bin taller than a set limit is clipped and the excess redistributed across the other bins. This caps how steeply the CDF can climb, which caps how far apart nearly-identical values can be pushed — and since noise amplification *is* pushing nearly-identical values apart, capping it directly limits the damage.
Equalisation is the CDF, worked
Histogram equalisation has one moving part: it remaps each brightness through the image's own cumulative distribution, scaled to the full range. On a 16-pixel image whose values cluster low, new[v] = round(cdf[v] × 7) over an 8-level range:
| old value | cumulative fraction | new value |
|---|---|---|
| 2 | 4/16 | 2 |
| 3 | 10/16 | 4 |
| 5 | 13/16 | 6 |
| 6 | 15/16 | 7 |
| 7 | 16/16 | 7 |
The crowded values (3 appears six times) get pulled far apart, because the CDF climbs steeply across them; the rare high values collapse together, because the CDF is nearly flat there. The transformation gives range to where the pixels actually are and takes it from where they are not, which is what flattens the histogram and makes buried contrast visible. The costs follow from the same mechanism: in a genuinely flat region the small random differences between pixels are stretched too, so noise is amplified — a clear sky becomes mottled — and because one lookup table is computed from the whole image, a frame that is well-exposed on one side and dark on the other gets a compromise suiting neither. CLAHE fixes both by equalising per-tile with a contrast cap that limits how steeply the CDF may climb.
Where it goes wrong
Equalising an already well-exposed image. There is nothing to gain and noise to lose. Look at the histogram first; if it already spans the range, leave it alone.
Equalising each RGB channel separately. The three channels get three different mappings, so the colours shift. Convert to a space with a separate brightness channel, equalise that one channel, and convert back.
Comparing histograms across images to judge similarity. Two completely different photographs can share a histogram. It describes the palette, not the picture.
The histogram, and the CDF that flattens it
A histogram throws away every bit of spatial information and keeps only how often each brightness occurs. That sounds like a loss, and it is -- but it is exactly what you need to fix exposure, and equalisation turns out to be nothing more than applying the image's own cumulative distribution as a lookup table.
Check yourself
0 of …Answer without scrolling back up.
What does a histogram tell you nothing about?
Which function does histogram equalisation use as its lookup table?
Why does CLAHE clip the histogram before computing the CDF?
Histograms and Equalisation
An image histogram is a count: for each of the 256 possible brightness values, how many pixels hold it. Nothing else. It discards position entirely — an image and the same image shuffled into random order have identical histograms.