生成随机颜色的问题 - asp.net和c#

6
我需要在我的asp.net应用程序中生成随机颜色的十六进制值,以绘制图表。
 Random random = new Random();
 color = String.Format("#{0:X6}", random.Next(0x1000000)); 

上面的代码生成随机颜色代码。但是我的问题是,有时它会生成与先前颜色几乎相似的颜色。因为我要用它来制作图表,所以我需要生成完全不同的颜色。有什么好的想法...
4个回答

5

尝试

Color.FromArgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));

--编辑--

根据mjv的评论更新:

public class RandomColor
{
    Random _random;
    public RandomColor()
    {
        _random = new Random();
    }

    public Color GetNext()
    {
        return Color.FromArgb(_random.Next(0, 255), _random.Next(0, 255), _random.Next(0, 255));
    }
}

使用方法:

colorRandom.GetNext();

为什么这种方法可以确保不会连续生成两个相似的颜色? - mjv
Random() 函数根据种子生成随机数,只要您在 Random 对象中重复使用它。例如,在您的 RandomColor 类的构造函数中。 - KMån
@KMan:你说得没错。然而,从统计学的角度来看,你所建议的代码片段第二次被调用时,有可能会生成与上一次类似的颜色。实际上,这种情况发生的概率与在 OP 的代码片段中同时绘制所有 3 个成分值的概率相同。 - mjv
@mjv:你还能用什么方法生成(*使用Random*)?请看我的编辑。 - KMån
@KMan。重复使用随机数生成器只能确保[由于某种奇怪的原因]新产生的生成器不会有相同的种子,从而产生相同的序列。为了防止两种类似的颜色连续产生,需要执行以下操作之一:a)测试相似性并重新绘制或b)对各个组件使用特定的数学运算。然而,后一种选择可能会减少可能访问的颜色列表。 - mjv
@mjv:我同意你提出的两个选项;但是这些“决策”或“准确度水平”实际上取决于项目的范围;如果它是一个精确的要求或者只是为了实现实际要求而添加的附加功能。例如,如果我正在开发图形软件,我不会使用Random.GetNext();但是如果我正在开发银行支票处理应用程序,我可能会使用它。 - KMån

5

我可能误解了问题...
如果问题是为了避免随时间产生类似的颜色序列,可以参考KMan的回答。他首先建议通过使用同一个生成器产生所有随机值(而不是每次产生一个新的生成器),就可以避免产生与之前使用的生成器具有相同种子的风险。

如果问题是避免连续绘制两种“相似”的颜色,则应采用以下方法。避免连续绘制两种相似的颜色意味着

  • 使用某些数学逻辑(但存在一定风险,即所使用的函数可能无法覆盖所有可能颜色的光谱,就像一个好的随机数生成器一样)
  • 绘制真正的随机颜色,但在它们被认为太相似时拒绝它们(并尝试重新选择)。

第二种方法是下面代码片段中所示的内容。
这里使用的是长格式样式,并且颜色接受标准有些任意,但这应该提供了一个很好的想法。
此外,通过重复使用单个随机数生成器(RNG),如果以某种方式每次创建RNG并且偶然使用了相同的种子,则避免了重复序列的风险...

  const int minTotalDiff = 200;    // parameter used in new color acceptance criteria
  const int okSingleDiff = 100;    // id.

  int prevR, prevG, prevB;  // R, G and B components of the previously issued color.
  Random RandGen = null;

  public string GetNewColor()
  {
      int newR, newG, newB;

      if (RandGen == null)
      {
          RandGen = new Random();
          prevR = prevG = prevB = 0;
      }

      bool found = false;
      while (!found)
      {
          newR = RandGen.Next(255);
          newG = RandGen.Next(255);
          newB = RandGen.Next(255);

          int diffR = Math.Abs(prevR - newR);
          int diffG = Math.Abs(prevG - newG);
          int diffB = Math.Abs(prevB - newB);

          // we only take the new color if...
          //   Collectively the color components are changed by a certain
          //   minimum
          //   or if at least one individual colors is changed by "a lot".
          if (diffR + diffG + diffB >= minTotalDiff
              || diffR >= okSingleDiff
              || diffR >= okSingleDiff
              || diffR >= okSingleDiff
          )
            found = true;
        }

       prevR = newR;
       prevG = newG;
       prevB = newB;

      return String.Format("#{0:X2}{0:X2}{0:X2}", prevR, prevG, prevB);
  }

3
我看不到你的代码足够多,但如果我猜测你的代码结构正确的话,这应该会有所帮助……它应该可以澄清为什么数字相同或接近相同,因为我曾经遇到过类似的问题,以下是我如何解决以及我认为这是解决方法的原因。
我有一些生成随机数的代码,看起来像这样(大大简化了):
for (some loop logic)
{
  Random r = new Random();
  int myRandomNumber = Random.Next()
}

当执行时,它实际上为循环的一部分(比如8次迭代)创建了完全相同的数字,然后切换到一个新数字,重复9次迭代,等等。我通过将其更改为以下内容来解决它:
Random r = new Random();
for (some loop logic)
{
  int myRandomNumber = Random.Next()
}

我相信其他人会表达得更好,但是通过在循环外声明 Random,Random 类的实例能够跟踪上一个生成的随机数,并确保下一个随机数实际上是随机的。如果将它放在循环内(就像第一个示例中一样),则每次迭代都会创建一个新的 Random 对象,因此它只使用任何逻辑(我假设是基于时间的)来生成一个随机数,而不知道不同的实例刚刚生成了相同的数字。
天啊,我希望这有意义... 现在已经很晚了,我的解释可能不清楚,但我认为你的问题可能是你在循环逻辑中创建了 Random 类的一个新实例,而你需要在循环外声明它。
编辑-添加:
本文介绍了为什么要这样做:

http://geekswithblogs.net/kakaiya/archive/2005/11/27/61273.aspx


1
Random r=new Random();
var newCol=(r.Next(0,256)<<16)+(r.Next(0,256)<<8)+(r.Next(0,256));

如果你想要更亮的颜色,请考虑提高Next的最小参数。

1
这种方法为什么能确保不产生连续两个相似的颜色? - mjv
@Mjv:如果您在同一时间窗口内为每个使用创建一个新的对象,那么您最终会得到几个具有相似种子和相同结果的“Random”对象。 - KMån

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