生成唯一颜色的算法

33
我正在寻找一种算法,可以生成一系列颜色,使这些颜色尽可能广泛地分布(以便它们不会容易混淆)。
我有一系列对象,其ID从1开始递增。我想用不同的、美观的颜色来表示每个对象,这样它们与相邻的对象不会被轻易混淆。虽然颜色不一定是随机的,但我希望输入相同的ID时得到相同的颜色。
7个回答

32

我已经检查过所有的方法,试过很多种。最终,使用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

23

你可以将id乘以黄金比例(phi)得到一个介于0和1之间的数字n。你生成的所有数字都趋向于均匀分布。

PHI = (1 + sqrt(5))/2
n = id * PHI - floor(id * PHI) 

那么问题就在于将该数字转换为颜色,例如:

hue = floor(n * 256)

10
http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ - Ohad Schneider

13

我写了一篇关于同样主题的文章:

如何编程生成随机颜色

基本上,您可以使用HSV颜色空间,设置固定的饱和度和明度,并修改色相。当您知道所需颜色的数量时,只需通过Hue的范围 [0,1[ 分割即可。如果您不知道所需颜色的数量,仍然可以使用黄金比例从此空间选择颜色。


1
@philmccull 我修改了它,只通过改变色调生成30种独特且视觉上不同的颜色。http://jsfiddle.net/hCtc3/42 - Berty
1
不错的技巧。 - Timmmm

11

图形设计师知道,如果在信息显示中将使用很多颜色,则这些颜色应该在颜色空间中相对接近。相对于大的跳跃而言,饱和度或色调的小变化通常更好–当涉及许多颜色时,人眼实际上发现当颜色距离不是非常大时更容易吸收信息。

此外,不要忘记您的一些用户可能是色盲。由于有许多不同类型的色盲,很难知道要避免什么颜色组合。也许其他人可以回答这个问题?


9
可能元素的数量有一个合理的下限吗?一种快速简单的解决方案是使用项目的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;
       }
    }
}

看我的答案,有一种方法可以避免预测 EXPECTED_MAX 并仍然获得均匀分布。 - Patrick McElhaney

0

我发现与hsl不同,hsluv颜色空间对于随机选择颜色非常有用,因为在我的观点中,那里的颜色更加均匀分布。请参考https://www.hsluv.org/

以下是一个示例:下面的脚本选择了400种不同的颜色,其中0 <= 色调 <= 360,80 <= 饱和度 <= 100(在该范围内均匀选择),亮度基于正态分布选择,平均值为66,标准差为10:

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()

结果是

enter image description here

这可以与martinus的答案https://dev59.com/yHM_5IYBdhLWcg3w6X1e#5104386或此线程中的其他答案相结合。相比之下,以下示例在hsl颜色空间中具有0 <= hue <= 1,0.4 <= lightness <= 0.6和0.9 <= saturation <= 1:

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()

enter image description here

请注意,这里的亮度不同(蓝色和红色方块似乎比黄色或绿色方块更暗)。以下文章解释了原因:https://programmingdesignsystems.com/color/perceptually-uniform-color-spaces/

0

我有一个简单的解决方案,它独特、稳定但可能不太美观:

color_code = "#" + md5(unique_key_like_email).substring(0, 3)

MD5 方便地生成基于16进制的字符 0-9+a-f,非常适合用于颜色索引。


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