代码之家  ›  专栏  ›  技术社区  ›  Louis Brandy

用于创建颜色轮的功能[关闭]

  •  66
  • Louis Brandy  · 技术社区  · 17 年前

    这是我多次伪解的问题,从来没有找到一个解。

    问题是想出一种方法 N 颜色,在 n 是一个参数。

    8 回复  |  直到 7 年前
        1
  •  24
  •   Rann Lifshitz rul    7 年前

    我的第一个想法是“如何在一个最大化彼此距离的空间中生成n个向量”。

    您可以看到,RGB(或任何其他在颜色空间中构成基础的比例)只是向量。看一看 Random Point Picking . 一旦你有了一组分开最大化的向量,你就可以把它们保存在哈希表或其他东西中,稍后再对它们进行随机旋转,得到你想要的所有颜色,这些颜色彼此最大限度地分开!

    更多地考虑这个问题,最好以线性方式映射颜色,可能是(0,0,0)(255255255),然后均匀地分布它们。

    我真的不知道这会有多好的效果,但应该是这样,让我们说:

    n = 10
    

    我们知道我们有16777216种颜色(256^3)。

    我们可以使用 Buckles Algorithm 515 查找字典索引颜色。 \frac {\binom {256^3} {3}} {n} * i . 您可能需要编辑该算法以避免溢出,并可能添加一些较小的速度改进。

        2
  •  17
  •   Jeff Holt    9 年前

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

        3
  •  7
  •   Collin    17 年前

    一些相关资源:

    ColorBrewer -为在地图上使用而设计的可最大限度区分的一组颜色。

    Escaping RGBland: Selecting Colors for Statistical Graphics -描述在HCL颜色空间中生成良好(即最大可分辨)颜色集的一组算法的技术报告。

        4
  •  6
  •   ravenspoint    9 年前

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

    class cColorPicker
    {
    public:
        void Pick( vector<DWORD>&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<DWORD>&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<unsigned char>(rm1 * 255);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        vector<DWORD> 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;
    }
    
        5
  •  5
  •   svrist    17 年前

    这不是你设置颜色的一个因素吗?

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

    这有道理吗?

        6
  •  2
  •   helloandre    17 年前

    我在某个地方读到了人眼无法区分小于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个值检查一次,并在上面的示例中为数组添加颜色。

        7
  •  1
  •   Mauro    14 年前

    我知道这是一篇老文章,但我在寻找主题的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] 
        } 
    }
    

    所以只需调用随机的_color()函数,其中$i标识颜色,$n表示可能的颜色数,$sat表示饱和度,$br表示亮度。

        8
  •  0
  •   Adi Shavit    11 年前

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

    使用所有可能的量化条目生成完整的三维空间,并使用 k=N . 由此产生的中心/“平均值”应该是彼此最明显的区别。