想象一下我们如何使用一些基本颜色:
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")
我想要一个函数,它将一个3元组作为参数(如(206,17,38)),它应该返回它的颜色。例如,(206,17,38)是红色,(2,2,0)是黑色,(0,255,0)是绿色。 选择8种颜色中哪一种最准确?
答案 0 :(得分:12)
简答:在设备无关的颜色空间中使用欧几里德距离(来源:维基百科中的Color difference文章)。由于RGB与设备有关,因此您应首先将颜色映射到与设备无关的颜色空间之一。
我建议将RGB转换为Lab*。再次引用维基百科:
与RGB和CMYK颜色模型不同, 实验室颜色旨在近似 人类的愿景。
Here's a recipe进行转化。获得L
,a
,b
值后,计算颜色与所有参考颜色之间的欧几里德距离,并选择最接近的颜色。
实际上,Google Code上的python-colormath Python模块(在GPL v3下)能够在许多不同的颜色空间之间进行转换,也可以计算颜色差异。
答案 1 :(得分:4)
我绝不是色彩专家,但我一直在拼命寻找RGB / HEX / HSV到python中的简单颜色名称转换器。经过一番研究后,我相信我做了一个强大的解决方案。根据{{3}}中的IfLoop:
如果最终使用笛卡尔距离来比较颜色,通常应将输入转换为线性感知色彩空间,例如Lab或Yuv。 RGB和HSV都不是线性的,因此笛卡尔距离与类似的两种颜色实际上没有多大关系。 - IfLoop 2011年7月27日21:15
因此,正如格拉夫所指出的那样,Jochen Ritzel的代码并不总能恢复正确的颜色。这是因为RGB和HSV都是线性颜色空间。我们需要使用像YUV这样的线性感知色彩空间。
所以我做的是我使用Jochen Ritzel的代码并将rgb代码替换为基于this post的rgb到yuv代码的hsv代码。
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( (a-b)**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.')
现在我们几乎每次都会得到正确的颜色:
>>> color_to_match = (2, 2, 0) #Graf's test
>>> print min_color_diff( color_to_match, colors)
>>>
(6.408043991348166e-05, 'BLACK')
更多例子:
>>> 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')
到目前为止,似乎我的版本似乎工作得非常完美,但请注意:如果rgb颜色太亮或太暗,很可能会返回'WHITE '或'黑色'。要解决此问题,您需要为颜色词典添加更浅和更深的颜色。同时在颜色字典中添加更多颜色,如“BROWN”和“GRAY”(等等),也会返回更好的效果。
答案 2 :(得分:3)
将颜色视为向量并计算给定颜色和每个颜色之间的距离,并选择最小的颜色。最简单的距离可以是:|a1 - a2| + |b1 - b2| + |c1 - c2|
。
同样阅读:http://answers.yahoo.com/question/index?qid=20071202234050AAaDGLf,描述的距离函数更好。
答案 3 :(得分:3)
使用rgb_to_hsv进行转换。然后将颜色与壁橱色调匹配
对于您的示例,它将是RED,因为色调完全匹配
>>> from colorsys import rgb_to_hsv
>>> rgb_to_hsv(192,2,51)
(0.83333333333333337, 0, 192)
>>> rgb_to_hsv(206, 17, 38)
(0.83333333333333337, 0, 206)
>>>
以下是如何找到最接近匹配的示例
>>> from colorsys import rgb_to_hsv
>>>
>>> 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"),))
>>>
>>> color_to_match = (206,17,38)
>>>
>>> print min((abs(rgb_to_hsv(*k)[0]-rgb_to_hsv(*color_to_match)[0]),v) for k,v in colors.items())
(0.0, 'RED')
答案 4 :(得分:1)
我希望这是它应该工作的方式:它将颜色转换为hsv,然后将(平方)欧几里德距离转换为所有可用颜色并返回最接近的匹配。
主要是gnibblers代码的固定版本。
from colorsys import rgb_to_hsv
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 to_hsv( color ):
""" converts color tuples to floats and then to hsv """
return rgb_to_hsv(*[x/255.0 for x in color]) #rgb_to_hsv wants floats!
def color_dist( c1, c2):
""" returns the squared euklidian distance between two color vectors in hsv space """
return sum( (a-b)**2 for a,b in zip(to_hsv(c1),to_hsv(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)
color_to_match = (127, 255, 255)
print min_color_diff( color_to_match, colors)
使用支持排序和距离的简单Color
类,所有时髦列表理解看起来会更好(但是你可以在练习中做到这一点; - )。
答案 5 :(得分:0)
我的Goulib库的颜色模块做得相当好,还有更多。 它定义了一个Color类,可以从多个颜色空间中进行定义,并在Palette字典中进行分组。预定义了几个调色板,特别是由html / matplotlib名称索引的调色板。每个颜色自动从此调色板中最近颜色的索引中获取名称,以实验室空间(deltaE)为单位
在此处查看演示http://nbviewer.jupyter.org/github/Goulu/Goulib/blob/master/notebooks/colors.ipynb