阅读 5

计算颜色的差异

问题

我们想计算任意两种颜色的差异,也就是给定两个颜色的数字表示,计算出一个差异度,这个差异度最好能和人的主观感受一致。

解决方案

一般来说,我们很容易得到颜色的RGB表示,RGB是一个三维的颜色空间,每种RGB颜色可以看作RGB三维空间中的一个点,不难想到我们可以计算两个颜色在RRG空间中的距离作为颜色的差异度,最简单的,我们可以计算欧式距离。

import math
import numpy as np
import matplotlib.pyplot as plt
复制代码
def show_colors(rgb):
    color_tensor = np.zeros((200, 1000, 3), dtype=np.uint8)
    color_tensor[:,:] = np.array(rgb)
    plt.axis('off')
    plt.imshow(color_tensor)
    plt.show()
复制代码
def rgb_euclid_distance(rgb1, rgb2):
    r1, g1, b1 = rgb1
    r2, g2, b2 = rgb2
    dr, dg, db = r1-r2, g1-g2, b1-b2
    distance = math.sqrt(dr*dr + dg*dg + db*db)
    return distance
复制代码

比如,我们计算粉红 rgb(255,192,203) 和红色 rgb(255,0,0) 的距离,及粉红和绿色 rgb(0,255,0)的距离

show_colors((255,192,203))
show_colors((255,0,0))
show_colors((0,255,0))
print(rgb_euclid_distance((255,192,203), (255,0,0)))
print(rgb_euclid_distance((255,192,203), (0,255,0)))
复制代码

color
结果分别为279.4154612758571,331.96837198745305。与我们的主观感受一致,粉红和红色的差异小于红色和绿色的差异。

又比如,我们计算红色 rgb(255,0,0)与某种橙色 rgb(255,200,0)及某种紫色 rgb(255,0,200) 和之间的距离

show_colors((255,0,0))
show_colors((255,100,0))
show_colors((255,0,100))
print(rgb_euclid_distance((255,0,0), (255,200,0)))
print(rgb_euclid_distance((255,0,0), (255,0,200)))
复制代码

color

计算结果为 200.0,200.0

显然两组差异完全一致,但从人的主观感受来说,可能会觉得红色与紫色颜色相对更近一些。

可见,RGB空间中的距离和人对颜色差异的主观感受不太一致。为了解决这个问题,人们又发明了很多色彩空间和色彩距离的计算方法,而目前一般认为和人感觉比较接近的是CIE L*a*b* 色彩空间,关于色彩空间和色彩距离,是一个历史悠久的话题,可以参考wiki。作为一个食谱教程,我们直接使用相关库skimage来计算,有兴趣进一步了解可以直接去读skimage 的源码。

总体思路是把RGB先转换到CIE L*a*b* 空间,再使用相关距离度量,如CIEDE2000。

import skimage.color
def ciede2000_distance(rgb1, rgb2):
    lab1 = skimage.color.rgb2lab(np.array(rgb1).reshape((1,1,3))) # 注意skimage直接处理3维图片
    lab2 = skimage.color.rgb2lab(np.array(rgb2).reshape((1,1,3)))
    distance = skimage.color.deltaE_ciede2000(lab1, lab2).item()
    return distance
复制代码

我们使用这个算法再次计算红色 rgb(255,0,0)与某种橙色 rgb(255,200,0)及某种紫色 rgb(255,0,200) 和之间的距离

print(ciede2000_distance((255,0,0), (255,200,0)))
print(ciede2000_distance((255,0,0), (255,0,200)))
复制代码

1.6029676553991018e-05

1.0265169721951483e-05

两组差异是不一样的,其中红色与紫色的差异稍小。

讨论

关于颜色的转换,距离计算等,除了skimage库外,还有一个专门处理颜色的库 Colour