23

I have a color (RGB) being read from a sensor. I also have a list of "known" colors, each paired with a string name.

What would the best way (ie behave like a human choosing colors) to pull the name of the nearest color out of this list?

I've tried a shortest cartesian distance with RGB, but that makes grey closer to green than to black or white.

CharlesB
  • 86,532
  • 28
  • 194
  • 218
Eric
  • 95,302
  • 53
  • 242
  • 374
  • 1
    I believe this may help (very similar problem): http://stackoverflow.com/questions/1678457/best-algorithm-for-matching-colours/1678498#1678498 – Rooke Nov 12 '09 at 07:35

3 Answers3

26

Rather than using RGB, try using an HSL (Hue, Saturation, Lightness) or HSV (Hue, Saturation and Value) color model. Then experiment with different elements of bias, e.g. hue being more important than luminance when you're calculating the distance.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @AlbertRenshaw: I'm not really sure what information your comment is meant to convey... – Jon Skeet Jul 21 '13 at 19:49
  • 6
    Also, if it helps anyone else... I found the best results in my app when giving HUE a 47.5% importance, SATURATION a 28.75% importance, and BRIGHTNESS a 23.75% importance. – Albert Renshaw Jul 21 '13 at 19:54
  • @AlbertRenshaw: In what language/platform though? My guess is Objective-C... but the question has absolutely no indication of the platform involved. – Jon Skeet Jul 21 '13 at 19:58
  • Ah! You're correct 0:) I'll delete the comment haha! (And yes, it was objective-c!) – Albert Renshaw Jul 21 '13 at 20:05
  • 3
    HSV and HSL will probably be better than RGB, but the best way would be to convert to the LAB color space, then calculate the "delta-e" using one of the existing standard color comparisons (CIE1976, CIE94, CIEDE2000). I recently found the [ColorMine](http://colormine.org/) library for .NET, which makes all that a breeze. – Dave Haynes May 06 '14 at 17:09
7

Jon Skeet is right. You need to use a system with Hue as a component instead of RGB if you are concerned about the color component of the match differing too much. HSL or HSV will both work fine for this purpose.

Then you need to fiddle with the distance formula to weight up hue until you are happy with the results. Note that you will find the problem is actually essentially insoluble unless you have a large number of colors to match against or your input colors are confined to a small range of possible values. This is because although it might seem you can pin any color you want to one of 8 (red, orange yellow, green, blue, violet, black and white) or one of 16, in reality you'll find your algorithm will always find what seem to be obviously incorrect matches because with 3 axis of movement (hue, saturation, value or red, green, blue), there are a lot more "basic" colors than you might think at first glance.

Southern Hospitality
  • 1,260
  • 1
  • 8
  • 12
  • 1
    The idea is, the sensor finds the "closest" color within a list of colors. The application of this problem is a robot which must detect splodges of 4 predetermined colors on a white background. – Eric Nov 12 '09 at 22:15
  • 2
    Depends on what "closest" means. Green was closest to grey by RGB RMS error in your original code. So was it wrong? Given that you say yes, you are clearly imposing some other kind of idea of closest based upon color perception. And I'm telling you will find you aren't really happy with the results until you have something like 64 well-chosen colors to match to. At least to the human eye. Your code presented should work for comparing to 4 predetermined splotches, assuming the splotches don't look too much like each other. – Southern Hospitality Nov 13 '09 at 03:44
4

I would think that if you treat colors as RGB coordinates in 3-space and compute distance from sampled to known values, you could determine the closest match. I probably would also try scaling R G B according to eye sensitivity (ie, Y = 0.3*R + 0.59*G + 0.11*B) you'd achieve the best result

Scott Evernden
  • 39,136
  • 15
  • 78
  • 84
  • 6
    The only issue with using RGB and finding the magnitude between two colors is that the magnitude might be the same for two colors equally distant, but in opposing directions from the color being compared. For example (for simplicity, this does not take scaling for eye sensitivity into account): If the RGB is 0xFF0000, and it is compared against 0x00FF00 and 0x0000FF, the magnitudes are the same, but is green closer to red than blue? – Jason Satterfield Feb 08 '13 at 01:31