计算字典中最接近输入颜色的颜色

3

我有一个颜色字典(如下),以及一个颜色代码 #4a7dac,对应的名称是'steelblue'。我想找到字典中与此颜色最接近的颜色代码名称。因此,算法会选择#0000ff并返回'blue'

colors= {
    "red":"#FF0000",
    "yellow":"#FFFF00",
    "green":"#008000",
    "blue":"#0000FF",
    "black":"#000000",
    "white":"#FFFFFF",
    "gray":"#808080",
}

我考虑过计算颜色之间的某种“距离”,但不知道如何编写它。


我怀疑这不是你想要的,但如果你有名称,你可以进行字符串搜索。例如,在“steelblue”中搜索“blue”。它在你的示例结果中完美地工作! - Ant
2个回答

4
我们可以创建一个函数,该函数接受两个十六进制字符串,并返回各个颜色组件之间差异的总和。如果您不理解以下代码如何工作,请留言说明。
def diff(h1, h2):
    def hexs_to_ints(s):
        return [int(s[i:i+2], 16) for i in range(1,7,2)]
    return sum(abs(i - j) for i, j in zip(*map(hexs_to_ints, (h1, h2))))

我们可以进行测试:

>>> diff('#ff00ff', '#0000ff')
255
>>> diff('#0000ff', '#00000a')
245

所以,我们现在可以创建一个使用这个函数完成任务的函数:
def get_col_name(hex, colors):
    return min([(n,diff(hex,c)) for n,c in colors.items()], key=lambda t: t[1])[0]

很不幸,这对你的颜色无效,因为它选择了灰色,它的RGB值是[128, 128, 128],所以与钢蓝色[74, 125, 172])相比非常接近,比起蓝色[0, 0, 255]),它们之间的差异更小。这意味着与灰色相比,与蓝色相比更难区分。我会尝试想出更好的方法,但也许有人能提供一些见解并留下评论?


1
也许在HSV或类似的颜色空间中工作会更好? - Dan Mašek
@DanMašek 我也有这个想法,但是gray的色调是没有意义的(可以是任何颜色),所以它仍然会搞乱事情。 - Joe Iddon
你是否考虑先进行饱和度检测以检测灰度阴影?或者参考 https://en.wikipedia.org/wiki/Color_difference。 - Dan Mašek
我尝试了5种不同的度量方式,灰色总是最接近的。我猜如果OP真的想要得到蓝色作为结果,他们就必须定义自己的定制指标来满足他们的愿望。 - Dan Mašek
@DanMašek 是的,HSV 只是让我们更接近结果 :D。 - NoorJafri
使用 colorsys.rgb_to_hls(*rgb)math.sqrt(sum(abs(i - j)**2 for i, j in zip(*map(hexs_to_ints, (h1, h2)))) 的组合效果不好吗? - taront

3
如何将它们转换为RGB并找到主导颜色呢?
例如:
RED FF0000         rgb(255,0,0)
BLUE 0000FF        rgb(0,0,255)
steelblue 4A7DAC   rgb(74,125,172)

您可以使用RGB而不是HEX来实现此目标。
您可以查看以下算法:https://dev59.com/tmox5IYBdhLWcg3wtmg1#9018100 编辑: RGB和HEX计算无法处理灰色,因为每种颜色只有最接近灰色的距离。为此,可以使用颜色的HSV值,我已经加入了HSV的实现 :D
学到了很多:D
我在这里玩得很开心:
    import math
    colors= {
    "red":"#FF0000",
    "yellow":"#FFFF00",
    "green":"#008000",
    "blue":"#0000FF",
    "black":"#000000",
    "white":"#FFFFFF",
    "grey": "#808080"
}

# function for HSV TAKEN FROM HERE: https://gist.github.com/mathebox/e0805f72e7db3269ec22
def rgb_to_hsv(r, g, b):
    r = float(r)
    g = float(g)
    b = float(b)
    high = max(r, g, b)
    low = min(r, g, b)
    h, s, v = high, high, high

    d = high - low
    s = 0 if high == 0 else d/high

    if high == low:
        h = 0.0
    else:
        h = {
            r: (g - b) / d + (6 if g < b else 0),
            g: (b - r) / d + 2,
            b: (r - g) / d + 4,
        }[high]
        h /= 6

return h, s, v

# COLOR YOU WANT TO TEST TESTED
check = "#808000".lstrip('#')
checkRGB = tuple(int(check[i:i+2], 16) for i in (0, 2 ,4))
checkHSV = rgb_to_hsv(checkRGB[0], checkRGB[1], checkRGB[2])


colorsRGB = {}
colorsHSV = {}

for c, v in colors.items():
    h = v.lstrip('#')
    colorsRGB[c] = tuple(int(h[i:i+2], 16) for i in (0, 2 ,4))

for c, v in colorsRGB.items():
    colorsHSV[c] = tuple(rgb_to_hsv(v[0], v[1], v[2]))

def colourdistanceRGB(color1, color2):
    r = float(color2[0] - color1[0])
    g = float(color2[1] - color1[1])
    b = float(color2[2] - color1[2])
    return math.sqrt( ((abs(r))**2) + ((abs(g))**2) + ((abs(b))**2) )

def colourdistanceHSV(color1, color2):
    dh = min(abs(color2[0]-color1[0]), 360-abs(color2[0]-color1[0])) / 180.0
    ds = abs(color2[1]-color1[1])
    dv = abs(color2[2]-color1[2]) / 255.0
    return math.sqrt(dh*dh+ds*ds+dv*dv)

resultRGB = {}
resultHSV = {}

for k, v in colorsRGB.items():
    resultRGB[k]=colourdistanceRGB(v, checkRGB)

for k,v in colorsHSV.items():
    resultHSV[k]=colourdistanceHSV(v, checkHSV)


#THIS WILL NOT WORK FOR GREY
print("RESULT WITH RGB FORMULA")
print(resultRGB)
print(min(resultRGB, key=resultRGB.get))


#THIS WILL WORK FOR EVEN GREY
print(resultHSV)
print(min(resultHSV, key=resultHSV.get))

#OUTPUT FOR RGB
#check = "#808000"  output=GREY
#check = "#4A7DAC"  output=GREY :D

#OUTPUT FOR RGB
#check = "#808000"  output=GREEN
#check = "#4A7DAC"  output=BLUE:D

如果您不理解代码的任何部分,请告诉我。 :) - NoorJafri
1
这不是回答问题的方式!?!你只是从字典中删除了“gray”! - Joe Iddon
是的,RGB颜色计算会在灰色方面出现问题。他必须使用HSV颜色计算以及完全不同的公式,我会尝试在这里放置它:D干杯。 - NoorJafri
@JoeIddon 现在它也适用于灰色了。祝你有个愉快的一天 :D - NoorJafri
谢谢,但它对大多数对象返回“黄色”。没有起作用 :/ - shahidammer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接