我正在寻找一种简单的算法来生成大量随机的、美观的颜色。所以没有疯狂的霓虹色,让人联想到粪便的颜色等。

我找到了解决这个问题的方法,但它们依赖于 RGB 之外的替代调色板。我宁愿只使用直接 RGB 而不是来回映射。这些其他解决方案也最多只能生成 32 种左右令人愉悦的随机颜色。

任何想法都会很棒。


您可以将随机颜色的 RGB 值与恒定颜色的 RGB 值进行平均:

(Java 中的示例)

public Color generateRandomColor(Color mix) {
  Random random = new Random();
  int red = random.nextInt(256);
  int green = random.nextInt(256);
  int blue = random.nextInt(256);

  // mix the color
  if (mix != null) {
      red = (red + mix.getRed()) / 2;
      green = (green + mix.getGreen()) / 2;
      blue = (blue + mix.getBlue()) / 2;
  }

  Color color = new Color(red, green, blue);
  return color;
}

将随机颜色与白色 (255、255、255) 混合,通过增加亮度同时保持原始颜色的色调来创建中性粉彩。这些随机生成的粉彩通常搭配得很好,尤其是大量使用时。

以下是使用上述方法生成的一些柔和的颜色:

第一的

您还可以将随机颜色与恒定的柔和色混合,从而产生一组有色的中性色。例如,使用浅蓝色会产生如下颜色:

第二

更进一步,您可以将启发式方法添加到您的生成器中,以考虑互补色或阴影级别,但这完全取决于您希望通过随机颜色获得的印象。

一些额外的资源:


我会使用色轮并给定一个随机位置,你可以添加黄金角度(137.5 度)

http://en.wikipedia.org/wiki/Golden_angle

为了每次都获得不重叠的不同颜色。

调整色轮的亮度,您还可以获得不同的亮/暗颜色组合。

我发现这篇博文很好地解释了问题和使用黄金比例的解决方案。

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

更新:我刚刚发现了另一种方法:

它称为 RYB(red, yellow, blue) 方法,在本文中有描述:

http://threekings.tk/mirror/ryb_TR.pdf

作为“Paint Inspired Color Compositing”。

该算法生成颜色,并选择每种新颜色以最大化其与先前选择的颜色的欧几里德距离。

在这里你可以找到一个很好的 javascript 实现:

http://afriggeri.github.com/RYB/

更新 2:

Sciences Po Medialb 刚刚发布了一个名为“I want Hue”的工具,可以为数据科学家生成调色板。使用不同的颜色空间并通过使用 k 均值聚类或力向量(排斥图)生成调色板这些方法的结果非常好,它们在其网页中展示了理论和实现。

http://tools.medialab.sciences-po.fr/iwanthue/index.php


在javascript中:

function pastelColors(){
  var r = (Math.round(Math.random()* 127) + 127).toString(16);
  var g = (Math.round(Math.random()* 127) + 127).toString(16);
  var b = (Math.round(Math.random()* 127) + 127).toString(16);
  return '#' + r + g + b;
}

在这里看到了这个想法:http://blog.functionalfun.net/2008/07/random-pastel-colour-generator.html


转换为另一个调色板是一种更好的方法。他们这样做是有原因的:其他调色板是“可感知的”——也就是说,它们将相似的颜色放在一起,调整一个变量以可预测的方式改变颜色。对于 RGB 来说,这一切都不是真的,RGB 颜色之间没有明显的关系,可以“很好地搭配”。


我已经成功地使用TriadMixingCIE94来避免相似的颜色。下图使用红色、黄色和白色的输入颜色。这里

// http://devmag.org.za/2012/07/29/how-to-choose-colours-procedurally-algorithms/#:~:text=120%20and%20240.-,7.%20Triad%20Mixing,-This%20algorithm%20takes

public static Color RandomMix(Color color1, Color color2, Color color3, 
   float greyControl)
{
   int randomIndex = random.NextByte() % 3;
   float mixRatio1 =
      (randomIndex == 0) ? random.NextFloat() * greyControl : random.NextFloat();
   float mixRatio2 = 
      (randomIndex == 1) ? random.NextFloat() * greyControl : random.NextFloat();
   float mixRatio3 = 
      (randomIndex == 2) ? random.NextFloat() * greyControl : random.NextFloat();
   float sum = mixRatio1 + mixRatio2 + mixRatio3;

   mixRatio1 /= sum;
   mixRatio2 /= sum;
   mixRatio3 /= sum;

   return Color.FromArgb(
      255,
      (byte)(mixRatio1 * color1.R + mixRatio2 * color2.R + mixRatio3 * color3.R),
      (byte)(mixRatio1 * color1.G + mixRatio2 * color2.G + mixRatio3 * color3.G),
      (byte)(mixRatio1 * color1.B + mixRatio2 * color2.B + mixRatio3 * color3.B));
}

TriadMixing + CIE94


一个不容忽视的答案是现实生活中的照片和绘画样本,因为它简单且具有优势。在现代艺术图片、塞尚、梵高、莫奈、照片的缩略图上随机抽取尽可能多的随机像素颜色......优点是您可以按主题获取颜色,并且它们是有机颜色。只需将 20 - 30 张图片放在一个文件夹中,然后每次随机抽取一张随机图片。

转换为 HSV 值是基于心理的调色板的一种广泛使用的代码算法。hsv 更容易随机化。


在 PHP 中:

function pastelColors() {
    $r = dechex(round(((float) rand() / (float) getrandmax()) * 127) + 127);
    $g = dechex(round(((float) rand() / (float) getrandmax()) * 127) + 127);
    $b = dechex(round(((float) rand() / (float) getrandmax()) * 127) + 127);

    return "#" . $r . $g . $b;
}

来源:https ://stackoverflow.com/a/12266311/2875783


使用独特的颜色

用javascript写的。

它生成视觉上不同颜色的调色板

distinct-colors 是高度可配置的:

  • 选择调色板中有多少种颜色
  • 将色调限制在特定范围内
  • 将色度(饱和度)限制在特定范围内
  • 将亮度限制在特定范围内
  • 配置调色板的一般质量

这是用 C# 编写的快速但肮脏的颜色生成器(使用本文中描述的“RYB 方法” 这是对JavaScript的重写

使用:

List<Color> ColorPalette = ColorGenerator.Generate(30).ToList();

前两种颜色往往是白色和黑色。我经常像这样跳过它们(使用 Linq):

List<Color> ColorsPalette = ColorGenerator
            .Generate(30)
            .Skip(2) // skip white and black
            .ToList(); 

执行:

public static class ColorGenerator
{

    // RYB color space
    private static class RYB
    {
        private static readonly double[] White = { 1, 1, 1 };
        private static readonly double[] Red = { 1, 0, 0 };
        private static readonly double[] Yellow = { 1, 1, 0 };
        private static readonly double[] Blue = { 0.163, 0.373, 0.6 };
        private static readonly double[] Violet = { 0.5, 0, 0.5 };
        private static readonly double[] Green = { 0, 0.66, 0.2 };
        private static readonly double[] Orange = { 1, 0.5, 0 };
        private static readonly double[] Black = { 0.2, 0.094, 0.0 };

        public static double[] ToRgb(double r, double y, double b)
        {
            var rgb = new double[3];
            for (int i = 0; i < 3; i++)
            {
                rgb[i] = White[i]  * (1.0 - r) * (1.0 - b) * (1.0 - y) +
                         Red[i]    * r         * (1.0 - b) * (1.0 - y) +
                         Blue[i]   * (1.0 - r) * b         * (1.0 - y) +
                         Violet[i] * r         * b         * (1.0 - y) +
                         Yellow[i] * (1.0 - r) * (1.0 - b) *        y +
                         Orange[i] * r         * (1.0 - b) *        y +
                         Green[i]  * (1.0 - r) * b         *        y +
                         Black[i]  * r         * b         *        y;
            }

            return rgb;
        }
    }

    private class Points : IEnumerable<double[]>
    {
        private readonly int pointsCount;
        private double[] picked;
        private int pickedCount;

        private readonly List<double[]> points = new List<double[]>();

        public Points(int count)
        {
            pointsCount = count;
        }

        private void Generate()
        {
            points.Clear();
            var numBase = (int)Math.Ceiling(Math.Pow(pointsCount, 1.0 / 3.0));
            var ceil = (int)Math.Pow(numBase, 3.0);
            for (int i = 0; i < ceil; i++)
            {
                points.Add(new[]
                {
                    Math.Floor(i/(double)(numBase*numBase))/ (numBase - 1.0),
                    Math.Floor((i/(double)numBase) % numBase)/ (numBase - 1.0),
                    Math.Floor((double)(i % numBase))/ (numBase - 1.0),
                });
            }
        }

        private double Distance(double[] p1)
        {
            double distance = 0;
            for (int i = 0; i < 3; i++)
            {
                distance += Math.Pow(p1[i] - picked[i], 2.0);
            }

            return distance;
        }

        private double[] Pick()
        {
            if (picked == null)
            {
                picked = points[0];
                points.RemoveAt(0);
                pickedCount = 1;
                return picked;
            }

            var d1 = Distance(points[0]);
            int i1 = 0, i2 = 0;
            foreach (var point in points)
            {
                var d2 = Distance(point);
                if (d1 < d2)
                {
                    i1 = i2;
                    d1 = d2;
                }

                i2 += 1;
            }

            var pick = points[i1];
            points.RemoveAt(i1);

            for (int i = 0; i < 3; i++)
            {
                picked[i] = (pickedCount * picked[i] + pick[i]) / (pickedCount + 1.0);
            }

            pickedCount += 1;
            return pick;
        }

        public IEnumerator<double[]> GetEnumerator()
        {
            Generate();
            for (int i = 0; i < pointsCount; i++)
            {
                yield return Pick();
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public static IEnumerable<Color> Generate(int numOfColors)
    {
        var points = new Points(numOfColors);

        foreach (var point in points)
        {
            var rgb = RYB.ToRgb(point[0], point[1], point[2]);
            yield return Color.FromArgb(
                (int)Math.Floor(255 * rgb[0]),
                (int)Math.Floor(255 * rgb[1]),
                (int)Math.Floor(255 * rgb[2]));
        }
    }
}

微信小程序

微信扫一扫体验

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部