想象一下我们如何使用一些基本颜色:
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")
Run Code Online (Sandbox Code Playgroud)
我想要一个函数,它获得一个3元组作为参数(如(206,17,38)),它应该返回它的颜色.例如,(206,17,38)是红色,(2,2,0)是黑色,(0,255,0)是绿色.哪种选择8种颜色最精确?
Bol*_*olo 12
简答:在设备无关的颜色空间中使用欧几里德距离(来源:维基百科中的色差文章).由于RGB与设备有关,因此您应首先将颜色映射到与设备无关的颜色空间之一.
我建议将RGB转换为L a b*.再次引用维基百科:
与RGB和CMYK颜色模型不同,Lab颜色设计用于近似人类视觉.
这是进行转换的方法.一旦你的L,a,b值,计算出你的色彩和所有参考颜色之间的欧氏距离,选择最接近的一个.
实际上,Google Code上的python-colormath Python模块(在GPL v3下)能够在许多不同的颜色空间之间进行转换并计算颜色差异.
我绝不是色彩专家,但我一直在拼命寻找RGB / HEX / HSV到python中的简单颜色名称转换器。经过一些研究,我相信我提出了一个强大的解决方案。根据IfLoop在这篇文章中:
如果最终使用笛卡尔距离比较颜色,则通常应将输入转换为线性的,可感知的颜色空间,例如Lab或Yuv。RGB和HSV都不是线性的,因此笛卡尔距离与相似的两种颜色实际上并没有太大关系。– IfLoop 11年7月27日在21:15
因此,正如Graf指出的那样,Jochen Ritzel的代码不会总是返回正确的颜色。这是因为RGB和HSV都是线性色彩空间。我们需要使用线性感知色彩空间,例如YUV。
因此,根据这篇文章,我所做的是我接受了Jochen Ritzel的代码,并用rgb转换为yuv代码替换了rgb到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.')
Run Code Online (Sandbox Code Playgroud)
现在,我们似乎几乎每次都能获得正确的颜色:
>>> color_to_match = (2, 2, 0) #Graf's test
>>> print min_color_diff( color_to_match, colors)
>>>
(6.408043991348166e-05, 'BLACK')
Run Code Online (Sandbox Code Playgroud)
更多示例:
>>> 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')
Run Code Online (Sandbox Code Playgroud)
到目前为止,我的版本似乎工作得几乎完美,但是请注意:如果rgb颜色太亮或太暗,则很可能会返回“白”或“黑”。要解决此问题,您需要在颜色字典中添加较浅和较深的颜色。在颜色字典中添加更多颜色,例如“棕色”和“灰色”(等等)也将返回更好的结果。
| 归档时间: |
|
| 查看次数: |
2656 次 |
| 最近记录: |