Imagine we how some basic colors:
RED = Color ((196, 2, 51), "RED")
ORANGE = Color ((255, 165, 0), "ORANGE")
YELLOW = Color ((255, 205, 0), "YELLOW")
GREEN = Color ((0, 128, 0), "GREEN")
BLUE = Color ((0, 0, 255), "BLUE")
VIOLET = Color ((127, 0, 255), "VIOLET")
BLACK = Color ((0, 0, 0), "BLACK")
WHITE = Color ((255, 255, 255), "WHITE")
I want to have a function, which gets a 3-tuple as a parameter (like (206, 17, 38)), and it should return the color which it is. For instance, (206, 17, 38) is red, and (2, 2, 0) is black, and (0, 255, 0) is green. Which is most accurate way to choose one of 8 colors?
I'm by no means a color expert, but I've been desperately looking for a RGB/HEX/HSV to simple color names converter in python. After doing some research I believe I made a formidable solution. According to IfLoop in this post:
Therefore, Jochen Ritzel's code won't always return the proper color, as Graf pointed out. This is because both RGB and HSV are linear color spaces. We need to use a linear perceptual color space like YUV.
So what I did was I took Jochen Ritzel's code and replaced the rgb to hsv code with the rgb to yuv code based on this post.
Now we seem to end up with the right colors almost every time:
More examples:
So far it appears that my version seems to be working almost perfectly, but please note: It is likely that if an rgb color is too bright or too dark, you will probably get returned 'WHITE' or 'BLACK.' To resolve this you will need to add lighter and darker colors to your colors dictionary. Also adding more colors like 'BROWN' and 'GRAY' (and so on) to the colors dictionary will also return better results.
Use rgb_to_hsv to convert. Then match the color with the closet hue
For your example it would be RED because the hue matches exactly
Here's an example of how to find the closest match
I hope this is the way it's supposed to work: It converts the colors to hsv, then takes the (squared) euclidean distance to all available colors and returns the closest match.
Mostly a fixed version of gnibblers code.
All the funky list comprehension would look much better with a simple
Color
class that supports sorting and distance (but you can do that for practice ;-).Treat colors as vectors and count distance between the given and each of them and choose the one, which is the least. The simplest distance can be:
|a1 - a2| + |b1 - b2| + |c1 - c2|
.Read this too: http://answers.yahoo.com/question/index?qid=20071202234050AAaDGLf, there is a better distance function described.
The colors module of my Goulib library does this fairly well, and much more. It defines a Color class that can be inited from several color spaces, and grouped in a Palette dictionary. Several palettes are predefined, notably one that is indexed by the html/matplotlib names. Each Color automagically recieves a name from the index of the nearest color in this palette, measured in Lab space (deltaE)
see demo here http://nbviewer.jupyter.org/github/Goulu/Goulib/blob/master/notebooks/colors.ipynb
Short answer: use the Euclidean distance in a device independent color space (source: Color difference article in Wikipedia). Since RGB is device-dependent, you should first map your colors to one of the device-independent color spaces.
I suggest to convert RGB to Lab*. To quote Wikipedia again:
Here's a recipe to do the conversion. Once you have the
L
,a
,b
values, calculate the Euclidean distance between your color and all the reference colors and choose the closest one.Actually, the python-colormath Python module on Google Code (under GPL v3) is capable of converting between many different color spaces and calculates color differences as well.