I am by no means a specialist in color, but I was desperately looking for RGB / HEX / HSV for a simple color name converter in python. After some research, I believe I made a huge decision. According to IfLoop in this post :
If you finish using the Cartesian distance to compare colors, you should usually translate the inputs into a linear, perceptual color space, such as Lab or Yuv. Neither RGB nor HSV are linear, and therefore Cartesian distance is not very similar to similar two colors. - IfLoop Jul 27 '11 at 21:15
Consequently, the Jochen Ritzel code does not always return the correct color, as the Count pointed out. This is because RGB and HSV are linear color spaces. We need to use a linear perceptual color space such as YUV.
So what I did, I took the Jochen Ritzel code and replaced rgb with hsv code with rgb code with yuv based on this post .
colors = dict(( ((196, 2, 51), "RED"), ((255, 165, 0), "ORANGE"), ((255, 205, 0), "YELLOW"), ((0, 128, 0), "GREEN"), ((0, 0, 255), "BLUE"), ((127, 0, 255), "VIOLET"), ((0, 0, 0), "BLACK"), ((255, 255, 255), "WHITE"),)) def rgb_to_ycc(r, g, b): #http://bit.ly/1blFUsF y = .299*r + .587*g + .114*b cb = 128 -.168736*r -.331364*g + .5*b cr = 128 +.5*r - .418688*g - .081312*b return y, cb, cr def to_ycc( color ): """ converts color tuples to floats and then to yuv """ return rgb_to_ycc(*[x/255.0 for x in color]) def color_dist( c1, c2): """ returns the squared euklidian distance between two color vectors in yuv space """ return sum( (ab)**2 for a,b in zip(to_ycc(c1),to_ycc(c2)) ) def min_color_diff( color_to_match, colors): """ returns the `(distance, color_name)` with the minimal distance to `colors`""" return min( # overal best is the best match to any color: (color_dist(color_to_match, test), colors[test]) # (distance to `test` color, color name) for test in colors) if __name__ == "__main__": r = input('r: ') g = input('g: ') b = input('b: ') color_to_match = (r, g, b) print min_color_diff( color_to_match, colors) input('Press enter to exit.')
Now we seem to get the right colors almost every time:
>>> color_to_match = (2, 2, 0)
Other examples:
>>> color_to_match = (131, 26, 26) >>> print min_color_diff( color_to_match, colors) >>> (0.027661314571288835, 'RED') >>> color_to_match = (69, 203, 136) >>> print min_color_diff( color_to_match, colors) >>> (0.11505647737959283, 'GREEN')
It still seems that my version works almost perfectly, but note:. It is likely that if the rgb color is too bright or too dark, you will probably get it back. WHITE 'or' BLACK. 'To solve this problem, you need to add lighter and darker colors to the color dictionary. Also adding more colors such as βBROWNβ and βGRAYβ (etc.) to the color dictionary will also bring better results.