RGB Similar Color Approximation Algorithm

Darius picture Darius · Aug 22, 2012 · Viewed 7.6k times · Source

Given that in RGB we can represent 256^3 combinations = 16,777,216 colors, and since the human eye can only distinguish roughly 10,000,000, there is obviously a surplus of 6,777,216 RGB combinations that chromatically are indistinguishable from counterpart colors.

Compression algorithms work on this basis when approximating out spacial difference in color ranges across a frame I believe. With that in mind, how can one reliably compute whether a given color is within a range of 'similarity' to another?

Of course, 'similarity' will be some kind of arbitrary/tunable parameter that can be tweaked, but this is an approximation anyway. So any pointers, pseudocode, intuitive code samples, resources out there to help me model such a function?

Many thanks for your help

Answer

Joni picture Joni · Aug 22, 2012

There are many ways of computing distances between colors, the simplest ones being defined on color components in any color space. These are common "distances" or metrics between RGB colors (r1,g1,b1) and (r2,g2,b2):

  • L1: abs(r1-r2) + abs(g1-g2) + abs(b1-b2)
  • L2: sqrt((r1-r2)² + (g1-g2)² + (b1-b2)²)
  • L: max(abs(r1-r2), abs(g1-g2), abs(b1-b2))

These however don't take into account the fact that human vision is less sensitive to color than to brightness. For optimal results you should convert from RGB to a color space that encodes brightness and color separately. Then use one of the above metrics in the new color space, possibly giving more weight to the brightness component and less to the color components.

Areas of color that are indistinguishable form each other are called MacAdam ellipses. The ellipses become nearly circular in the CIELUV and CIELAB color spaces, which is great for computation, but unfortunately going from RGB into these color spaces is not so simple.

JPEG converts colors into YCbCr, where Y is brightness and the two C's encode color, and then halves the resolution of the C components. You could do the same and then use a weighed version of one of the above metrics, for example:

diff = sqrt(1.4*sqr(y1-y2) + .8*sqr(cb1-cb2) + .8*sqr(cr1-cr2)) 

The article on color difference in wikipedia has more examples for different color spaces.