【发布时间】:2010-11-13 04:28:54
【问题描述】:
我正在寻找一种能够生成一系列颜色的算法,以便颜色尽可能广泛地分布(这样它们就不会轻易混淆)。
我有一系列 ID 从 1 开始计数的对象。我想用一种不同的、美观的颜色来表示它们中的每一个,这种颜色不会轻易与相邻的颜色混淆。颜色不一定是随机的。我希望每次输入相同的 ID 时都得到相同的颜色。
【问题讨论】:
标签: algorithm colors language-agnostic
我正在寻找一种能够生成一系列颜色的算法,以便颜色尽可能广泛地分布(这样它们就不会轻易混淆)。
我有一系列 ID 从 1 开始计数的对象。我想用一种不同的、美观的颜色来表示它们中的每一个,这种颜色不会轻易与相邻的颜色混淆。颜色不一定是随机的。我希望每次输入相同的 ID 时都得到相同的颜色。
【问题讨论】:
标签: algorithm colors language-agnostic
我已经检查了所有方法,解决了不止几种方法。最后是 CIEde2000 的蛮力,真的,你最好的选择只是一个静态列表。无论您做什么,您都无法获得超过 30 种具有良好清晰度的颜色。考虑到色盲和混淆线,你真的在做一些阻碍的事情。使用查找表并使用一些其他特征修改数据点,而不仅仅是颜色。
#000000
#00FF00
#0000FF
#FF0000
#01FFFE
#FFA6FE
#FFDB66
#006401
#010067
#95003A
#007DB5
#FF00F6
#FFEEE8
#774D00
#90FB92
#0076FF
#D5FF00
#FF937E
#6A826C
#FF029D
#FE8900
#7A4782
#7E2DD2
#85A900
#FF0056
#A42400
#00AE7E
#683D3B
#BDC6FF
#263400
#BDD393
#00B917
#9E008E
#001544
#C28C9F
#FF74A3
#01D0FF
#004754
#E56FFE
#788231
#0E4CA1
#91D0CB
#BE9970
#968AE8
#BB8800
#43002C
#DEFF74
#00FFC6
#FFE502
#620E00
#008F9C
#98FF52
#7544B1
#B500FF
#00FF78
#FF6E41
#005F39
#6B6882
#5FAD4E
#A75740
#A5FFD2
#FFB167
#009BFF
#E85EBE
【讨论】:
您可以将 id 乘以 golden ratio (phi) 得到一个数字 0
PHI = (1 + sqrt(5))/2
n = id * PHI - floor(id * PHI)
然后就是将该数字转换为颜色的问题,例如
hue = floor(n * 256)
我写过一篇关于同一主题的文章:
How to Generate Random Colors Programmatically
基本上你可以使用 HSV 颜色空间,设置一个固定的 Saturation 和 Value,并修改 Hue。当您知道您需要的颜色数量时,只需将色调的范围[0,1[ 以此分割即可。如果您不知道所需颜色的数量,您仍然可以使用黄金比例从这个空间中选择颜色。
【讨论】:
平面设计师知道,如果要在信息显示中使用大量相互靠近的颜色,则这些颜色在色彩空间中应该相对接近。饱和度或色调的小幅变化通常比大的跳跃要好 - 当涉及多种颜色时,人眼实际上发现在颜色距离不是很大时更容易吸收信息。
另外,不要忘记您的一些用户可能是色盲。由于色盲种类繁多,很难知道要避免哪些组合。也许其他人可以解决这个问题?
【讨论】:
可能元素的数量是否有合理的下限?一种快速简单的解决方案是使用项目的 ID 存储一组颜色值。这假设您的颜色数量相对较少,但是您确定不会超过一定数量的项目。
如果您想生成颜色而不是使用列表,让它们具有一致且体面的外观的一个技巧是使用 HSB 生成它们。预定义亮度和饱和度,然后根据 ID 的某些函数确定色调值(这可以是多种事情,具体取决于您计划拥有多少个 ID,但将 ID 乘以某个数量(并在超过时进行修改) 255!) 是一个很好的粗略方法。通过这种方法,颜色将在饱和度和亮度方面全部“对齐”,但它们每个都有不同的颜色。
我工作有点无聊,所以我想出了一个快速的解决方案:
class HsbColor
{
public int Hue { get; set; }
public int Saturation { get; set; }
public int Brightness { get; set; }
public Color ToRGB
{
// left as exercise to the reader...
}
}
public class Item
{
public int Id { get; set; }
private static const byte EXPECTED_MAX = 15;
private static int HUE_FACTOR = 255 / EXPECTED_MAX;
public HsbColor Color
{
get {
var color = new HsbColor() { Saturation = 175, Brightness = 175 };
color.Hue = (Id * HUE_FACTOR) % 255;
return color;
}
}
}
【讨论】:
我发现 hsluv 颜色空间对于随机选择颜色非常有用,而不是 hsl,因为在我看来,颜色分布更均匀。见https://www.hsluv.org/
示例:以下脚本选择 400 种不同的颜色,其中 0
import matplotlib.pyplot as plt
import numpy as np
from hsluv import hsluv_to_rgb
nrows, ncols = 20, 20
h = np.random.uniform(low=0, high=360, size=(nrows, ncols))
l = np.random.normal(loc=66, scale=10, size=(nrows, ncols))
s = np.random.uniform(low=80, high=100, size=(nrows, ncols))
image = np.dstack((h,s,l))
image = np.apply_along_axis(hsluv_to_rgb, 2, image)
plt.figure(figsize=(15,15))
plt.matshow(image, fignum=1)
plt.xticks([])
plt.yticks([])
plt.show()
结果是
这可以与 martinus 的答案 https://stackoverflow.com/a/5104386/1165155 或此线程中的其他答案结合使用。相比之下,以下示例在 hsl 颜色空间中,0
import matplotlib.pyplot as plt
import numpy as np
from colormap.colors import hls2rgb
nrows, ncols = 20, 20
h = np.random.uniform(low=0, high=1, size=(nrows, ncols))
l = np.random.uniform(low=0.4, high=0.6, size=(nrows, ncols))
s = np.random.uniform(low=0.9, high=1, size=(nrows, ncols))
image2 = np.apply_along_axis(lambda color: hls2rgb(*color), 2, image)
plt.figure(figsize=(15,15))
plt.matshow(image2, fignum=1)
plt.xticks([])
plt.yticks([])
plt.show()
请注意,这里的亮度不一样(蓝色和红色方块似乎比黄色或绿色方块更暗)。以下文章解释了原因:https://programmingdesignsystems.com/color/perceptually-uniform-color-spaces/
【讨论】:
我有一个简单的解决方案,独特、稳定但可能很难看:
color_code = "#" + md5(unique_key_like_email).substring(0, 3)
MD5 可以方便地生成 0-9+a-f 基 16 个字符,非常适合用于颜色索引。
【讨论】: