Color Quantization using Median Cut
Given a list of RGB pixels and a target number of colors K, reduce the color palette using the median cut algorithm.
Algorithm:
- Start with all pixels in one bucket
- While the number of buckets < K:
- Find the bucket with the most pixels
- Determine which color channel (R=0, G=1, B=2) has the greatest range (max minus min) in that bucket. If channels tie, pick the lowest-numbered one (R before G before B)
- Sort the bucket by that channel (a stable sort: pixels with equal values keep their current order)
- Split at the median index into two halves (the first half gets pixels)
- If several buckets tie for the most pixels, split the one created earliest (a lower half counts as created before its upper half)
- For each bucket, compute the representative color as the per-channel mean of all its pixels, rounded to the nearest integer using Python's built-in rounding (an exact half goes to the nearest even integer, so and )
- Sort output colors by R, then G, then B (ascending)
Return the list of K representative colors.
Example
pixels = [[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 0]] K = 2
[[0, 128, 128], [255, 128, 0]]
- Input:
pixelsholds 4 colors, each a triple of channel values in : red, green, blue and yellow.K= 2 means the palette must end with exactly two buckets, so one split. - Choosing the channel: in the single starting bucket every channel spans . All three tie, so R wins the tie.
- Splitting: ordered by R the bucket reads green , blue , red , yellow , with the two R = 0 pixels keeping their original order. With the cut falls after pixels: {green, blue} and {red, yellow}.
- Averaging: {green, blue} gives , which rounds to . {red, yellow} gives , which rounds to .
- Output: ordered by R, the result is
[[0, 128, 128], [255, 128, 0]]. - Notice the tie rule matters here: splitting on G instead would pair {red, blue} and {green, yellow}, giving and , a different palette.
Constraints
- pixels is a list of [R, G, B] lists
- K >= 1 and K <= len(pixels)
- Return K colors as [R, G, B] lists (integer values)
- Sort output by R, then G, then B