如何随机生成完全饱和的颜色?

问题描述:

我通常使用下面的代码来生成随机颜色:如何随机生成完全饱和的颜色?

Random rand = new Random(); 

Color random = Color.FromArgb((int)(rand.NextDouble() * 255), 
           (int)(rand.NextDouble() * 255), 
           (int)(rand.NextDouble() * 255)); 

但大多看起来像一个灰色的变化。我怎样才能限制输出只有完全饱和的颜色?

谢谢。

+2

表达式'(int)(rand.NextDouble()* 255)'永远不会生成值“255”。 'NextDouble'生成一个数字,使得0

+0

很高兴知道,吉姆 – abenci

理论

完全饱和(13759 HSL和类似的配色方案),实际上意味着,你必须在一个完整的RGB值,一个0,一个在任何其他值。

其原因是饱和度是基于最高和最低颜色成分之间的差异,并且当它们处于极端时是最高的。实际的定义更加复杂(并涉及亮度),但足够说一个0和另一个1的分量将给出最大饱和度。

算法1

这导致这样做的一个比较简单的方法。

  1. 生成随机数0和1之间
  2. 随机
  3. 分配这个号码到一个FO的R,G和B的元素。
  4. 将零随机分配给其余元素之一。
  5. 设定的最后一个元素为1

这会给你一个最大饱和度的颜色相对简单。

对于实现它可能是最容易产生一个随机数1到6为6可能的选择你分配0,1和随机元素,然后使用某种类型的开关。

这是最简单的算法,但由于选择/分支不一定是最简单的实现。

算法2

的建议由吉姆·米契尔基于类似的理论,但只是实现了一个稍微不同的第二种方法。

  1. 产生用于每个R,G和B分量
  2. 的随机值查找最大分量。
  3. 找到最小组件。
  4. 将最大分量设置为1.
  5. 将最小分量设置为0。

这与将一个值设置为1,一个设置为0和一个设置为随机值的效果相同。它的优点是它不需要你使用凌乱的switch语句,但是你最终可能会产生一些混乱的循环。同样取决于你的组件的精度(例如,如果你直接用字节),那么如果你的中间值实际上等于你的顶部或底部(或所有三个都是相同的),那么这可能也会被重置,这取决于你如何编码你的算法。这将主要影响随机性的倾斜,但这不太可能引人注意。吉姆

int[] rgb = new int[3]; 
    rgb[0] = rnd.Next(256); // red 
    rgb[1] = rnd.Next(256); // green 
    rgb[2] = rnd.Next(256); // blue 

    // Console.WriteLine("{0},{1},{2}", rgb[0], rgb[1], rgb[2]); 

    // find max and min indexes. 
    int max, min; 

    if (rgb[0] > rgb[1]) 
    { 
     max = (rgb[0] > rgb[2]) ? 0 : 2 
     min = (rgb[1] < rgb[2]) ? 1 : 2; 
    } 
    else 
    { 
     max = (rgb[1] > rgb[2]) ? 1 : 2; 
     int notmax = 1 + max % 2; 
     min = (rgb[0] < rgb[notmax]) ? 0 : notmax; 
    } 
    rgb[max] = 255; 
    rgb[min] = 0; 

    // Console.WriteLine("{0},{1},{2}", rgb[0], rgb[1], rgb[2]); 
+0

有趣的另一种方法是产生三个随机数(对于R,G和B)。然后,推动最高到1和最低到0 –

+0

是的,这也可以工作,几乎肯定会是整洁的代码,没有杂乱的开关 – Chris

+0

@JimMischel:我已经在你的建议中加入了我的答案。假设你不介意... – Chris

我想你想在HSL值中产生你的颜色,设置饱和度固定在它的最大值,只有随机化色调和亮度。你可以找到HSL颜色here的课程。

+0

它可能是你想要固定在0.5(即中点)亮度,因为它往往是白色,并低于黑色,所以你可能会结束与以前相同的颜色聚束问题即越接近0和1,亮度越小,即使在最大饱和度下,你也会看到不同的H差异。 – Chris

的方法,两人还礼貌为了记录

代码实现,这里是一个小的适应吉姆·米契尔建议(下面是Java代码,适应.NET是微不足道的):

private static Random r = new Random(); 

public static final String randomColor() { 
    int[] arr = new int[3]; 
    arr[0] = 0x80; 
    arr[1] = 0xFF; 
    arr[2] = r.nextInt(0x10) * 8 + 0x80; 
    // Fisher–Yates shuffle 
    for (int i1 = arr.length - 1; i1 >= 0; i1--) { 
     int i2 = r.nextInt(i1 + 1); 
     int tmp = arr[i2]; 
     arr[i2] = arr[i1]; 
     arr[i1] = tmp; 
    } 
    return String.format("%02x%02x%02x", arr[0], arr[1], arr[2]); 
} 

我们集3个值中随机:

  • ö ne到0x80
  • 另一个0xFF
  • 剩余的一个到0X80到0xFF之间的一个随机值。

随机值与的0x10的步骤产生得到一组不同颜色的减少(即6×8 = 48),则可以写为arr[2] = r.nextInt(0x80) + 0x80;更多的选择。

我也将最小值设置为0x80以获得饱和度较低的颜色,这在我看来更好看一些(这是一个不好的味道......)。你可以减少这个最小值来增加饱和度。