I wrote the two methods below to automatically select N distinct colors. It works by defining a piecewise linear function on the RGB cube. The benefit of this is you can also get a progressive scale if that's what you want, but when N gets large the colors can start to look similar. I can also imagine evenly subdividing the RGB cube into a lattice and then drawing points. Does anyone know any other methods? I'm ruling out defining a list and then just cycling through it. I should also say I don't generally care if they clash or don't look nice, they just have to be visually distinct.

public static List<Color> pick(int num) {
    List<Color> colors = new ArrayList<Color>();
    if (num < 2)
        return colors;
    float dx = 1.0f / (float) (num - 1);
    for (int i = 0; i < num; i++) {
        colors.add(get(i * dx));
    }
    return colors;
}

public static Color get(float x) {
    float r = 0.0f;
    float g = 0.0f;
    float b = 1.0f;
    if (x >= 0.0f && x < 0.2f) {
        x = x / 0.2f;
        r = 0.0f;
        g = x;
        b = 1.0f;
    } else if (x >= 0.2f && x < 0.4f) {
        x = (x - 0.2f) / 0.2f;
        r = 0.0f;
        g = 1.0f;
        b = 1.0f - x;
    } else if (x >= 0.4f && x < 0.6f) {
        x = (x - 0.4f) / 0.2f;
        r = x;
        g = 1.0f;
        b = 0.0f;
    } else if (x >= 0.6f && x < 0.8f) {
        x = (x - 0.6f) / 0.2f;
        r = 1.0f;
        g = 1.0f - x;
        b = 0.0f;
    } else if (x >= 0.8f && x <= 1.0f) {
        x = (x - 0.8f) / 0.2f;
        r = 1.0f;
        g = 0.0f;
        b = x;
    }
    return new Color(r, g, b);
}

当前回答

我有个主意。想象一个HSV气缸

定义亮度和饱和度的上限和下限。这在空间内定义了一个正方形的横截面环。

现在,在这个空间中随机散布N个点。

然后对它们应用迭代排斥算法,要么迭代次数固定,要么直到这些点稳定下来。

现在你应该有N个点,代表N种颜色,它们在你感兴趣的颜色空间中尽可能不同。

Hugo

其他回答

对于Python用户来说,seaborn非常简洁:

>>> import seaborn as sns
>>> sns.color_palette(n_colors=4)

它返回RGB元组列表:

[(0.12156862745098039, 0.4666666666666667, 0.7058823529411765),
(1.0, 0.4980392156862745, 0.054901960784313725),
(0.17254901960784313, 0.6274509803921569, 0.17254901960784313),
(0.8392156862745098, 0.15294117647058825, 0.1568627450980392)]

如果N足够大,你会得到一些相似的颜色。世界上只有这么多。

为什么不把它们均匀地分布在光谱中,像这样:

IEnumerable<Color> CreateUniqueColors(int nColors)
{
    int subdivision = (int)Math.Floor(Math.Pow(nColors, 1/3d));
    for(int r = 0; r < 255; r += subdivision)
        for(int g = 0; g < 255; g += subdivision)
            for(int b = 0; b < 255; b += subdivision)
                yield return Color.FromArgb(r, g, b);
}

如果您想混合序列,以便相似的颜色不在彼此旁边,您可能会打乱结果列表。

是我想得不够周全吗?

这个OpenCV函数使用HSV颜色模型在0<=H<=360º周围生成n个均匀分布的颜色,最大S=1.0, V=1.0。函数在bgr_mat中输出BGR颜色:

void distributed_colors (int n, cv::Mat_<cv::Vec3f> & bgr_mat) {
  cv::Mat_<cv::Vec3f> hsv_mat(n,CV_32F,cv::Vec3f(0.0,1.0,1.0));
  double step = 360.0/n;
  double h= 0.0;
  cv::Vec3f value;
  for (int i=0;i<n;i++,h+=step) {
    value = hsv_mat.at<cv::Vec3f>(i);
    hsv_mat.at<cv::Vec3f>(i)[0] = h;
  }
  cv::cvtColor(hsv_mat, bgr_mat, CV_HSV2BGR);
  bgr_mat *= 255;
}

HSL颜色模型可能非常适合“排序”颜色,但如果您正在寻找视觉上独特的颜色,您肯定需要Lab颜色模型。

CIELAB被设计成相对于人类色觉而言在感知上是一致的,这意味着这些数值中相同数量的数值变化对应着大约相同数量的视觉感知变化。

一旦你知道了这一点,从广泛的颜色范围中找到N种颜色的最优子集仍然是一个(NP)困难问题,有点类似于旅行推销员问题,所有使用k-mean算法或其他方法的解决方案都不会有真正的帮助。

也就是说,如果N不是太大,如果你从一个有限的颜色集开始,你会很容易找到一个非常好的不同颜色的子集,根据一个简单的随机函数的Lab距离。

我编写了这样一个工具供我自己使用(你可以在这里找到:https://mokole.com/palette.html),下面是我在N=7时得到的:

它都是javascript,所以请随意查看页面的源代码,并根据自己的需要进行调整。

您可以使用HSL颜色模型来创建颜色。

如果你想要的只是不同的色调(可能),以及亮度或饱和度的轻微变化,你可以像这样分配色调:

// assumes hue [0, 360), saturation [0, 100), lightness [0, 100)

for(i = 0; i < 360; i += 360 / num_colors) {
    HSLColor c;
    c.hue = i;
    c.saturation = 90 + randf() * 10;
    c.lightness = 50 + randf() * 10;

    addColor(c);
}