Função para a criação de rodas de cores

votos
63

Isso é algo que eu tenha resolvido-pseudo muitas vezes e nunca bastante encontrado uma solução para.

O problema é que vir acima com uma maneira de gerar Ncores que são tão distinta quanto possível, onde Né um parâmetro.

Publicado 01/08/2008 em 19:42
fonte usuário
Em outras línguas...                            


8 respostas

votos
23

Meu primeiro pensamento sobre isso é "como gerar vetores N em um espaço que maximizam a distância um do outro."

Você pode ver que o RGB (ou qualquer outra escala que você usa, que forma uma base no espaço de cor) são apenas vetores. Dê uma olhada aleatória Ponto Picking . Uma vez que você tem um conjunto de vetores que são maximizadas além, você pode salvá-los em uma tabela hash ou algo para mais tarde, e apenas realizar rotações aleatórias sobre eles para obter todas as cores que você deseja que sejam maximamente afastados uns dos outros!

Pensando nisso problema mais, seria melhor para mapear as cores de uma forma linear, possivelmente, (0,0,0) → (255,255,255) lexicographically, e, em seguida, distribuí-los uniformemente.

Eu realmente não sei o quão bem isso vai funcionar, mas deve desde, digamos:

n = 10

sabemos que temos 16777216 cores (256 ^ 3).

Podemos usar Buckles Algorithm 515 para encontrar a cor lexicographically indexado. \ Frac {\ binom {256 ^} 3 {3}} {n} * i. Você provavelmente vai ter que editar o algoritmo para evitar transbordamento e provavelmente adicionar algumas melhorias de velocidade menores.

Respondeu 02/08/2008 em 20:03
fonte usuário

votos
17

Seria melhor para encontrar cores maximamente distantes num espaço de cores "perceptivelmente uniforme", por exemplo CIELAB (utilizando distância euclidiana entre L *, a *, b * coordena como a sua distância métrica) e depois converter para o espaço de cores de sua escolha. uniformidade perceptual é conseguida ajustando o espaço de cores, que harmoniza as não-linearidades do sistema visual humano.

Respondeu 12/09/2008 em 20:00
fonte usuário

votos
7

Alguns recursos relacionados:

ColorBrewer - Conjuntos de cores projetado para ser maximamente distinguíveis para uso em mapas.

Escaping RGBland: Seleção de cores para gráficos estatísticos - Um relatório técnico que descreve um conjunto de algoritmos para gerar bons (ou seja maximamente distinguíveis) conjuntos de cores no espaço de cor HCL.

Respondeu 18/09/2008 em 17:01
fonte usuário

votos
6

Aqui está um código para alocar as cores RGB uniformemente em torno de uma roda de cores HSL de luminosidade especificada.

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;
}
Respondeu 27/09/2008 em 17:39
fonte usuário

votos
3

Não é também um fator que ordem você configurar as cores?

Como se você usar Dillie-Os idéia que você precisa misturar as cores, tanto quanto possível. 0 64 128 256 é de um para o outro. mas 0 256 64 128 numa roda seria mais "distante"

Isso faz sentido?

Respondeu 02/08/2008 em 19:16
fonte usuário

votos
1

Eu sei que isto um post antigo, mas eu achei enquanto procura uma solução PHP para o tema e, finalmente, veio com uma solução simples:

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

Então, basta chamar a função random_color (), onde $ i identifica a cor, $ n o número de cores possíveis, $ sentou-se a saturação e US $ br o brilho.

Respondeu 19/10/2011 em 02:58
fonte usuário

votos
1

Eu li em algum lugar o olho humano não consegue distinguir entre menos de 4 valores separados. então isso é algo a ter em mente. O algoritmo que se segue não compensar isso.

Eu não tenho certeza que isso é exatamente o que você quer, mas esta é uma maneira de gerar aleatoriamente valores de cor não-repetindo:

(Cuidado, pseudo-código inconsistente à frente)

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

Uma maneira que você poderia otimizar isto para melhorar a visibilidade seria comparar a distância entre cada nova cor e todas as cores na matriz:

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

Mas esta abordagem iria desacelerar significativamente o seu algoritmo.

Outra forma seria a de desfazer-se da aleatoriedade e sistematicamente passar por cada 4 valores e adicione uma cor para uma matriz no exemplo acima.

Respondeu 01/08/2008 em 20:36
fonte usuário

votos
0

Para alcançar o "mais distinguíveis" precisamos usar um espaço perceptual de cores como Lab (ou qualquer outro espaço de cor perceptivamente linear) e não RGB. Além disso, podemos quantificar este espaço para reduzir o tamanho do espaço.

Gerar o espaço 3D completa com todas as entradas quantizados possíveis e executar o K-means com k=N. Os centros resultantes / "significa" deve ser aproximadamente mais distinguishabl um do outro.

Respondeu 07/02/2014 em 18:43
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more