Skip to content
ToolsNow
Guides All tools

How colour palette extraction works

Why two tools give different palettes from the same image, what dominant and balanced actually mean, and why extracted colours are never a brand’s real ones.

Published

Run the same photograph through three palette extractors and you will get three different palettes. None of them is broken. They are answering slightly different questions, using different definitions of “similar colour”, on different samples of the same pixels.

Once you know which question you asked, the disagreement stops being mysterious and starts being useful.

The problem, stated honestly

A two-megapixel photograph contains up to two million colour values, and typically several hundred thousand distinct ones. You want six.

There is no correct answer to which six. There are only different reasonable procedures, and the choice between them is a design decision that most tools make silently on your behalf.

Method one: counting

The obvious approach is to count how often each colour appears and take the most common.

Applied naively to a photograph this fails completely. Nearly every pixel has a unique 24-bit value, so the “most common” colour appears four times and the top six are meaningless. The fix is to round before counting: reduce each channel from 256 levels to 32 (dropping the low three bits), which groups visually indistinguishable colours into the same bucket. Now the counts mean something.

What this gives you is genuinely “what is most of this image made of”. On a portrait against a wall, the honest answer is mostly wall. That is not a failure — it is the correct answer to the question of area.

The weakness is that it spends slots on near-duplicates. A sky that shifts gradually from one blue to another can fill four of your six slots with four blues that look the same.

Method two: dividing the colour space

Median cut, from Paul Heckbert’s 1982 paper, takes a different approach. Put every pixel in one box. Repeatedly find the box with the largest spread, split it along its widest axis at the median, and stop when you have as many boxes as you want colours. Each box’s average becomes a palette entry.

Because the split is at the median, each box ends up holding a similar number of pixels. Because the split is along the widest axis, boxes covering a wide range of colour get subdivided in preference to tight ones — which is exactly what stops four near-identical blues from occupying four slots.

There is a limit worth knowing, because it is routinely overstated. Median cut halves the pixel population at each split, so a minority colour needs roughly 1/2ⁿ of the image to survive n splits. A colour occupying 1.5% of the frame will not appear in a four-colour palette no matter which method you pick; give it eight slots and median cut finds it while a popularity count still does not.

A useful property: median cut is deterministic. The same image always gives the same palette. K-means clustering, the other common approach, needs a random starting point, so “regenerate” gives a different answer each time — which sounds like a feature until you are trying to reproduce yesterday’s result.

Method three: filtering first

Neither method above knows what an accent colour is. Both will happily return six greys from a photograph that is mostly grey, even though the one vivid thing in the frame is what you actually wanted.

Filtering to pixels above a saturation threshold before clustering fixes this. It needs two guards: exclude very dark and very light pixels too, because hue becomes numerically unstable near black and white and a saturation sort will otherwise surface essentially random values. And it needs a fallback, because a genuinely monochrome image has no vivid pixels and an empty palette is a worse answer than a muted one.

Why “similar” is the hard part

Every method has to decide when two colours are close enough to group. The obvious measure is straight-line distance in RGB, and it disagrees with human vision badly.

RGB is not perceptually uniform. A distance of 30 units in the green region is a barely perceptible shift; the same distance among dark blues is obvious. So clustering in RGB over-splits regions the eye barely distinguishes and merges ones it separates easily.

CIELAB, defined by the CIE, was built to fix this: it is designed so that equal distances correspond to roughly equal perceived differences. Its L axis is lightness, and a and b carry the colour. Comparing in Lab produces noticeably better groupings, at the cost of a matrix multiply and a cube root per conversion.

Even Lab is only approximately uniform — it is known to be least accurate in the blue region, which is why later formulas (CIE94, CIEDE2000) exist. For palette work the simpler CIE76 distance is almost always sufficient; the ranking rarely changes.

Then there is a subtler trap: gamma. sRGB channel values are gamma-encoded, so averaging them directly is not averaging light. The midpoint of black and white in sRGB arithmetic is #808080, which is far darker than half the light. Any operation that blends colours — averaging a cluster, generating tints — should convert to linear light first, or the results come out consistently too dark.

Sampling, and why percentages are estimates

Reading every pixel of a 24-megapixel photograph to build a six-colour palette is wasted work: a sample of forty thousand pixels gives an indistinguishable result in a fraction of the time. Almost every tool samples, and few say so.

The practical consequence is that reported frequencies are close estimates, not exact counts. For choosing colours this is irrelevant. For a claim like “this image is 31.2% blue” it matters, and that figure deserves a decimal place fewer than it is usually given.

Transparency

Fully transparent pixels still have colour channel values, and in most PNGs exported by most editors those values are pure black. Include them and every palette from every logo drifts toward black.

Excluding them is why extracting from a logo on a transparent background gives you the logo’s colours rather than a black entry — and it is a good quick test of whether a tool has thought about the problem.

Why these are not the brand’s colours

This is the claim worth being careful about, because it is made constantly and it is not true.

Between a brand’s specified colour and the pixels you are sampling sit several lossy steps:

  • JPEG compression shifts colour, and does so most in exactly the regions brands care about — chroma subsampling stores colour at half resolution.
  • Screenshots capture whatever the display and the operating system did, including any colour management.
  • Photographs add lighting, white balance and the camera’s own rendering.
  • Colour profiles mean identical bytes are meant to be displayed differently; ignore the embedded profile and you get the wrong colour from a perfectly good file.
  • Rendering and antialiasing blend edge pixels with the background.

An extracted palette is an accurate reading of this file. If an official brand reference exists, that is the authority; the extraction is a good way to get close, and a bad way to be certain.

Contrast is a separate question

A palette that looks good says nothing about whether text will be readable on it. That is a measurable property: the WCAG contrast ratio, computed from the relative luminance of both colours, running from 1:1 to 21:1. AA requires 4.5:1 for normal text and 3:1 for large; AAA requires 7:1 and 4.5:1.

Two things are worth flagging. The ratio depends only on luminance, so two colours can be wildly different hues and still fail — a red and a green of similar lightness are nearly unreadable together and are also the pair most likely to be indistinguishable to a colour-blind reader. And a contrast result should always be stated in words as well as shown as a swatch, because a verdict communicated only by a red or green indicator is inaccessible to exactly the people it is meant to help.

Sources and further reading

Last reviewed 31 July 2026.