创建色轮的功能

这是我多次虚拟解决的问题,从来没有找到解决方案。这是困在我身上。问题是想出一种方法来生成 N 颜色,它们尽可能地区分,其中 N 是一个参数。

0
额外 编辑
意见: 1
最后我检查了 JFreeChart 有这个精确的算法,因为它是开源的,你可以检查它的功能。我知道我得到的颜色似乎不是随机沿着某个圆或球体间隔排列,而是更具体地选择。
额外 作者 Kathy Van Stone,

8 答案

我首先想到的是“如何在最大化距离的空间生成N个向量”。你可以看到RGB(或者你使用的任何其他尺度在色彩空间中构成基础)只是矢量。查看随机挑选点。希望这对你是一个好开始!一旦你有一组向量被最大化的一部分,你可以将它们保存在一个散列表或其他东西,以后,只需对它们进行随机旋转,以获得所有你想要的颜色彼此最大距离!

Edit: Thinking about this problem more, it would be better to map the colors in a linear manor, possibly (0,0,0) --> (255,255,255) lexicographically, and then distribute them evenly. I really don't know how well this will work, but it should since, lets say:

n = 10 我们知道我们有16777216种颜色(256 ^ 3)。我们可以使用扣算法算法515 来查找词典索引颜色。。您可能需要编辑该算法以避免溢出,并且可能会添加一些小的速度改进。

0
额外
我同意这听起来合乎逻辑。 RGB主要制作紫色和橙色混合物,相对稀少使得蓝绿色混合物......颜色比例从红外线到深蓝色是均匀的,所以必须选择沿其等距的点。需要基于彩虹的算法。
额外 作者 com.prehensible,
请考虑upvoting /遵循StackExchange色彩理论网站: area51.stackexchange.com/proposals/110687/color-theory</一>
额外 作者 Adi Shavit,
这是不正确的,因为RGB颜色空间在感知上并不统一
额外 作者 adrienlucca.wordpress.com,

我读过人眼无法区分小于4个值的地方。所以这是要记住的事情。以下算法不会对此进行补偿。

我不确定这正是您想要的,但这是随机生成非重复颜色值的一种方法:

(注意,前面提供的不一致的伪代码)

//colors entered as 0-255 [R, G, B]
colors = []; //holds final colors to be used
rand = new Random();

//assumes n is less than 16,777,216
randomGen(int n){
   while (len(colors) < n){
      //generate a random number between 0,255 for each color
      newRed = rand.next(256);
      newGreen = rand.next(256);
      newBlue = rand.next(256);
      temp = [newRed, newGreen, newBlue];
      //only adds new colors to the array
      if temp not in colors {
         colors.append(temp);
      }
   }
}

你可以通过一种方式来优化这个功能以获得更好的可视性,比较每个新颜色和数组中所有颜色之间的距离:

for item in color{
   itemSq = (item[0]^2 + item[1]^2 + item[2]^2])^(.5);
   tempSq = (temp[0]^2 + temp[1]^2 + temp[2]^2])^(.5);
   dist = itemSq - tempSq;
   dist = abs(dist);
}
//NUMBER can be your chosen distance apart.
if dist < NUMBER and temp not in colors {
   colors.append(temp);
}

但是这种方法会显着减慢你的算法。

另一种方法是在上面的例子中,放弃随机性并系统地遍历每个4个值并为数组添加颜色。

0
额外

这是不是也是一个命令你设置颜色的因素?

就像如果你使用Dillie-Os的想法一样,你需要尽可能地混合颜色。 0 64 128 256是从一个到下一个。但在轮子中的0 256 64 128会更“分开”

这有意义吗?

0
额外

一些相关资源:

ColorBrewer - Sets of colours designed to be maximally distinguishable for use on maps.

Escaping RGBland: Selecting Colors for Statistical Graphics - A technical report describing a set of algorithms for generating good (i.e. maximally distinguishable) colour sets in the hcl colour space.

0
额外
逃离RGBland是必须阅读参考选择知觉可区分的调色板。
额外 作者 Drake Guan,

以下是一些代码,用于在指定亮度的HSL色轮周围均匀分配RGB颜色。

class cColorPicker
{
public:
    void Pick( vector&v_picked_cols, int count, int bright = 50 );
private:
    DWORD HSL2RGB( int h, int s, int v );
    unsigned char ToRGB1(float rm1, float rm2, float rh);
};
/**

  Evenly allocate RGB colors around HSL color wheel

  @param[out] v_picked_cols  a vector of colors in RGB format
  @param[in]  count   number of colors required
  @param[in]  bright  0 is all black, 100 is all white, defaults to 50

  based on Fig 3 of http://epub.wu-wien.ac.at/dyn/virlib/wp/eng/mediate/epub-wu-01_c87.pdf?ID=epub-wu-01_c87

*/

void cColorPicker::Pick( vector&v_picked_cols, int count, int bright )
{
    v_picked_cols.clear();
    for( int k_hue = 0; k_hue < 360; k_hue += 360/count )
        v_picked_cols.push_back( HSL2RGB( k_hue, 100, bright ) );
}
/**

  Convert HSL to RGB

  based on http://www.codeguru.com/code/legacy/gdi/colorapp_src.zip

*/

DWORD cColorPicker::HSL2RGB( int h, int s, int l )
{
    DWORD ret = 0;
    unsigned char r,g,b;

    float saturation = s / 100.0f;
    float luminance = l / 100.f;
    float hue = (float)h;

    if (saturation == 0.0) 
    {
      r = g = b = unsigned char(luminance * 255.0);
    }
    else
    {
      float rm1, rm2;

      if (luminance <= 0.5f) rm2 = luminance + luminance * saturation;  
      else                     rm2 = luminance + saturation - luminance * saturation;
      rm1 = 2.0f * luminance - rm2;   
      r   = ToRGB1(rm1, rm2, hue + 120.0f);   
      g = ToRGB1(rm1, rm2, hue);
      b  = ToRGB1(rm1, rm2, hue - 120.0f);
    }

    ret = ((DWORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)));

    return ret;
}


unsigned char cColorPicker::ToRGB1(float rm1, float rm2, float rh)
{
  if      (rh > 360.0f) rh -= 360.0f;
  else if (rh <   0.0f) rh += 360.0f;

  if      (rh <  60.0f) rm1 = rm1 + (rm2 - rm1) * rh / 60.0f;   
  else if (rh < 180.0f) rm1 = rm2;
  else if (rh < 240.0f) rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f;      

  return static_cast(rm1 * 255);
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector myCols;
    cColorPicker colpick;
    colpick.Pick( myCols, 20 );
    for( int k = 0; k < (int)myCols.size(); k++ )
        printf("%d: %d %d %d\n", k+1,
        ( myCols[k] & 0xFF0000 ) >>16,
        ( myCols[k] & 0xFF00 ) >>8,
        ( myCols[k] & 0xFF ) );

    return 0;
}
0
额外
不是当我不明白所有变化的东西时,除其他外:/
额外 作者 CodeGuy,
如果我想包括颜色与我提供的背景颜色不同,该怎么办?
额外 作者 CodeGuy,
AFAIK可以直接将代码从C ++移植到Java
额外 作者 ravenspoint,
我提供了链接到解释代码的URL的URL。
额外 作者 ravenspoint,
计算生成的颜色和背景颜色之间的“距离”。不要使用最接近背景的颜色。
额外 作者 ravenspoint,
这可能会工作一点,但这会给结果不佳,CIELAB更好
额外 作者 adrienlucca.wordpress.com,

最好在“感知均匀”的颜色空间中找到最远距离的颜色,例如, CIELAB(使用L *,a *,b *坐标之间的欧几里得距离作为距离度量),然后转换为您选择的颜色空间。感知均匀性是通过调整色彩空间来逼近人类视觉系统中的非线性来实现的。

0
额外
这可能是最好的解决方案,因为它非常简单。不过还有其他色差公式需要考虑,比如CIE2000甚至CIECAM
额外 作者 adrienlucca.wordpress.com,

为了实现“最明显的”,我们需要使用像Lab这样的感知色彩空间(或任何其他感知线性色彩空间)而不是RGB。另外,我们可以量化这个空间来减小空间的大小。

使用所有可能的量化条目生成完整的3D空间,并使用 k = N 运行K-means算法。由此产生的中心/“手段”应该大致相互区分。

0
额外

我知道这是一个旧帖子,但我在寻找该主题的PHP解决方案时发现了它,并最终提供了一个简单的解决方案:

function random_color($i = null, $n = 10, $sat = .5, $br = .7) {
    $i = is_null($i) ? mt_rand(0,$n) : $i;
    $rgb = hsv2rgb(array($i*(360/$n), $sat, $br));
    for ($i=0 ; $i<=2 ; $i++) 
        $rgb[$i] = dechex(ceil($rgb[$i]));
    return implode('', $rgb);
}

function hsv2rgb($c) { 
    list($h,$s,$v)=$c; 
    if ($s==0) 
        return array($v,$v,$v); 
    else { 
        $h=($h%=360)/60; 
        $i=floor($h); 
        $f=$h-$i; 
        $q[0]=$q[1]=$v*(1-$s); 
        $q[2]=$v*(1-$s*(1-$f)); 
        $q[3]=$q[4]=$v; 
        $q[5]=$v*(1-$s*$f); 
        return(array($q[($i+4)%6]*255,$q[($i+2)%6]*255,$q[$i%6]*255)); //[1] 
    } 
}

所以只需调用random_color()函数,其中$ i表示颜色,$ n表示可能的颜色数量,$表示饱和度和$ br亮度。

0
额外
你能解释一下在这种情况下“我”是什么吗?这个问题要求输入N个数字。什么是“我”参数?
额外 作者 CodeGuy,
我懂了!感谢您的解释。还有一件事......如果我有一个背景颜色,并且我想尽可能远离所有颜色,我该怎么办?
额外 作者 CodeGuy,
random_color()$ i 是生成色调的“种子”,应该是从0到 $ n 的数字,如果你输入没有种子(NULL),该函数随机选择一个。 $ n 是给定饱和度和亮度的可能颜色数量,即调色板中的颜色数量。我们基本上将360度色相分成 $ n$ i 作为乘数。换句话说,更高的 $ n 会给你更多的颜色,更低的 $ n 会给你更少的颜色,但是彼此会有更多的不同。如果您继续使用此功能, $ i 将识别颜色并始终保持不变。我希望有所帮助。
额外 作者 Mauro,
您需要为保持饱和度和价值的色彩添加180度。为此发布一个新问题,将链接粘贴到此处,我会进一步解释!
额外 作者 Mauro,