2010-08-25 61 views
6

假设我们一些基本的颜色如何:哪一种是最准确的方法来区分8种颜色之一?

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

2,2,0在技术上并不黑,就像240240240不技术上灰色。 – Chris 2010-08-25 10:59:06

+4

这是一个近似值。这显然是这个脚本的目标。 – 2010-08-25 11:00:39

回答

11

简答题的例子搭配衣柜色调

对于示例它的颜色是红色:在独立于设备的色彩空间中使用欧几里德距离(来源:维基百科中的Color difference文章)。由于RGB是依赖于设备的,因此应先将您的颜色映射到与设备无关的颜色空间之一。

我建议将RGB转换为Lab*。再次引用维基百科:

不像RGB和CMYK色彩模式, Lab颜色被设计成接近 人的视觉。

Here's a recipe要做转换。获得L,a,b值后,计算您的颜色和所有参考颜色之间的欧几里得距离,然后选择最接近的颜色。


实际上,在谷歌代码python-colormath Python模块(下GPL V3)能够许多不同的颜色空间和之间进行转换的计算颜色差异,以及

+1

非常好! python-colormath是我需要的!究竟! – Graf 2010-08-25 13:33:58

+0

python-colormath引用http://www.brucelindbloom.com/ - 如果您想了解转换背后的数学原理,这是一个很好的源代码。 – Bolo 2010-08-25 13:36:43

3

将颜色作为向量处理,并计算给定的每个元素之间的距离并选择最小的元素。最简单的距离可以是:|a1 - a2| + |b1 - b2| + |c1 - c2|

请仔细阅读:http://answers.yahoo.com/question/index?qid=20071202234050AAaDGLf,有一个更好的距离函数描述。

+2

RGB是依赖于设备的,因此它不是一个很好的色彩空间来测量色差(请参阅:http://en.wikipedia.org/wiki/Color_difference) – Bolo 2010-08-25 11:08:26

3

使用rgb_to_hsv进行转换。然后,因为色调完全一致

>>> 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') 
+0

这对我不起作用,请用颜色自己尝试(2,2,0),这显然是黑色的,你的代码说它是橙色的。 – Graf 2010-08-25 12:51:53

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类,支持排序和距离好得多(但你可以做到这一点的做法;-)。

+0

也许这有效,感谢您的评论,但我已经找到了更好的解决方案。 – Graf 2010-08-25 13:32:38

+0

没有,这不起作用,我试过颜色(2,2,0),它说它是绿色的。 我认为,转换为hsv不是最好的主意。通常建议您只应在两种Lab颜色上使用欧几里德距离,而不是RGB颜色或hsv颜色。 – Graf 2010-08-25 13:40:31

+0

@格拉夫:感谢您的信息。我想我们应该把这些东西留给那些真正知道他们在做什么并使用python-colormath模块的人;-) – 2010-08-25 14:36:17

3

我绝不是一个颜色专家,但我一直在拼命寻找一个RGB/HEX/HSV到python中的简单颜色名称转换器。在做了一些研究后,我相信我提出了一个强大的解决方案。根据IfLoop在this post

如果最终使用笛卡尔距离来比较颜色,正常的输入转换成线性,感知颜色空间,如实验室或YUV。 RGB和HSV都不是线性的,所以笛卡尔距离实际上与相似的两种颜色没有多大关系。 - IfLoop 11年7月27日在21:15

因此,乔兴Ritzel的代码不会总是返回正确的颜色,正如格拉夫指出的。这是因为RGB和HSV都是线性色彩空间。我们需要使用像YUV这样的线性感知色彩空间。

所以我做的是我拿走了Jochen Ritzel的代码,并用rgb替换了rgb到基于this post的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颜色太亮或太暗,可能会返回'白色'或'黑色'。为了解决这个问题,你需要为你的颜色词典添加更轻更深的颜色。同时向颜色词典中添加更多颜色,如“BROWN”和“GREY”(等等)也会返回更好的结果。

+1

这主要是OP要求的内容如果他/她想要一个实际的源代码。大多数人忘记了色彩空间之间的差异。 RGB用于设备,HSV是非线性的。应该在YUV中与欧几里德进行比较(实验室也可以工作,但主要是与人类视觉进行比较)。 – 2015-07-30 20:22:58

+0

感谢您提供答案。当我尝试时(45,106,168),它打印出绿色。但事实上,这种颜色接近BLUE。 – Indrajeet 2016-01-18 14:05:49

0

我的Goulib库的颜色模块做得很好,还有更多。 它定义了一个Color类,它可以从几个颜色空间进行插入,并在Palette字典中进行分组。几个调色板是预定义的,特别是由html/matplotlib名称索引的调色板。每种颜色的自动的临危一个名字从这个调色板中最接近的颜色的指标,在​​实验室测量空间(DeltaE值)

看到演示这里http://nbviewer.jupyter.org/github/Goulu/Goulib/blob/master/notebooks/colors.ipynb

相关问题