programing

컬러 휠 생성 기능

nasanasas 2020. 11. 12. 08:20
반응형

컬러 휠 생성 기능


이것은 내가 여러 번 의사 해결했으며 해결책을 찾지 못한 것입니다.

문제는 매개 변수가 N어디에 있는지 가능한 한 구별 할 수있는 색상 을 생성하는 방법을 찾는 것 N입니다.


이에 대한 첫 번째 생각은 "서로 거리를 최대화하는 공간에서 N 개의 벡터를 생성하는 방법"입니다.

RGB (또는 색 공간의 기초를 형성하는 다른 스케일)는 단지 벡터라는 것을 알 수 있습니다. Random Point Picking을 살펴보십시오 . 최대화 된 벡터 세트가 있으면 나중에 해시 테이블이나 다른 곳에 저장하고 무작위 회전을 수행하여 서로 최대한 떨어져있는 원하는 모든 색상을 얻을 수 있습니다!

이 문제에 대해 더 생각해 보면 (0,0,0) → (255,255,255) 사전 식으로 선형 방식으로 색상을 매핑 한 다음 균등하게 분포하는 것이 좋습니다.

나는 이것이 얼마나 잘 작동하는지 정말로 모르겠지만, 그 이후로 다음과 같이 말합시다.

n = 10

16777216 색 (256 ^ 3)이 있다는 것을 압니다.

Buckles Algorithm 515사용 하여 사 전적으로 색인 된 색상을 찾을 수 있습니다 . \ frac {\ binom {256 ^ 3} {3}} {n} * i. 오버플로를 방지하고 약간의 속도 향상을 추가하려면 알고리즘을 편집해야 할 것입니다.


CIELAB (L *, a *, b * 좌표 사이의 유클리드 거리를 거리 측정법으로 사용)와 같은 "지각 적으로 균일 한"색상 공간에서 최대한 멀리 떨어진 색상을 찾은 다음 선택한 색상 공간으로 변환하는 것이 가장 좋습니다. 지각 적 균일 성은 인간 시각 시스템의 비선형성에 근접하도록 색 공간을 조정하여 달성됩니다.


일부 관련 리소스 :

ColorBrewer- 지도에서 사용하기 위해 최대한 구별 할 수 있도록 설계된 색상 세트입니다.

Escaping RGBland : 통계 그래픽을위한 색상 선택-hcl 색상 공간에서 좋은 (즉, 최대한 구별 가능한) 색상 세트를 생성하기위한 알고리즘 세트를 설명하는 기술 보고서입니다.


다음은 지정된 광도의 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;
}

Isn't it also a factor which order you set up the colors?

Like if you use Dillie-Os idea you need to mix the colors as much as possible. 0 64 128 256 is from one to the next. but 0 256 64 128 in a wheel would be more "apart"

Does this make sense?


I've read somewhere the human eye can't distinguish between less than 4 values apart. so This is something to keep in mind. The following algorithm does not compensate for this.

I'm not sure this is exactly what you want, but this is one way to randomly generate non-repeating color values:

(beware, inconsistent pseudo-code ahead)

//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);
      }
   }
}

One way you could optimize this for better visibility would be to compare the distance between each new color and all the colors in the array:

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);
}

But this approach would significantly slow down your algorithm.

Another way would be to scrap the randomness and systematically go through every 4 values and add a color to an array in the above example.


I know this an old post but I found it while looking for a PHP solution to the topic and finally came with a simple solution:

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] 
    } 
}

So just call the random_color() function where $i identifies the color, $n the number of possible colors, $sat the saturation and $br the brightness.


To achieve "most distinguishable" we need to use a perceptual color space like Lab (or any other perceptually linear color space) and not RGB. Also, we can quantize this space to reduce the size of the space.

Generate the full 3D space with all possible quantized entries and run the K-means algorithm with k=N. The resulting centers/ "means" should be approximately most distinguishabl from each other.

참고 URL : https://stackoverflow.com/questions/180/function-for-creating-color-wheels

반응형