70 votes

Fonction de création de roues chromatiques

Il s'agit d'une question que j'ai maintes fois pseudo résolue, mais pour laquelle je n'ai jamais trouvé de solution.

Le problème est de trouver un moyen de générer N couleurs, qui se distinguent le plus possible lorsque N est un paramètre.

0 votes

La dernière fois que j'ai vérifié JFreeChart possède cet algorithme précis et, comme il s'agit d'une source ouverte, vous pouvez vérifier ce qu'il fait. Je sais que les couleurs que j'obtiens ne semblent pas être espacées au hasard le long d'un cercle ou d'une sphère, mais plutôt choisies de manière plus spécifique.

27voto

nlucaroni Points 21502

Ma première pensée à ce sujet est "comment générer N vecteurs dans un espace qui maximisent la distance entre eux".

Vous pouvez voir que le RVB (ou toute autre échelle que vous utilisez et qui constitue une base dans l'espace couleur) ne sont que des vecteurs. Jetez un coup d'œil à Sélection aléatoire de points . Une fois que vous avez un ensemble de vecteurs dont l'écart est maximisé, vous pouvez les sauvegarder dans une table de hachage ou autre pour plus tard, et effectuer des rotations aléatoires sur ces vecteurs pour obtenir toutes les couleurs que vous désirez et qui sont maximalement éloignées les unes des autres !

En réfléchissant davantage à ce problème, il serait préférable de mapper les couleurs de manière linéaire, éventuellement (0,0,0) → (255,255,255) lexicographiquement, puis de les répartir uniformément.

Je ne sais vraiment pas si ça va marcher, mais ça devrait puisque, disons-le :

n = 10

nous savons que nous avons 16777216 couleurs (256^3).

Nous pouvons utiliser Algorithme des boucles 515 pour trouver la couleur indexée lexicographiquement. \frac {\binom {256^3} {3}} {n} * i . Vous devrez probablement modifier l'algorithme pour éviter les débordements et probablement ajouter quelques améliorations mineures de la vitesse.

1 votes

C'est incorrect parce que l'espace couleur RVB n'est pas perceptiblement uniforme.

0 votes

Je suis d'accord, cela semble logique. L'échelle des couleurs est uniforme de l'infrarouge au bleu profond, il faut donc choisir des points également espacés le long de cette échelle. Il faut un algorithme basé sur l'arc-en-ciel.

0 votes

Veuillez envisager de voter pour ou de suivre le site StackExchange Color Theory : area51.stackexchange.com/propositions/110687/color-theory

20voto

Liudvikas Bukys Points 3578

Il serait préférable de trouver les couleurs les plus éloignées dans un espace colorimétrique "perceptuellement uniforme", par exemple CIELAB (en utilisant la distance euclidienne entre les coordonnées L*, a*, b* comme mesure de distance), puis de les convertir dans l'espace colorimétrique de votre choix. L'uniformité perceptive est obtenue en modifiant l'espace colorimétrique afin de se rapprocher des non-linéarités du système visuel humain.

0 votes

C'est probablement la meilleure solution, car elle est assez simple. Cependant, il existe d'autres formules de différence de couleur à considérer, comme la CIE2000 ou même la CIECAM.

11voto

hadley Points 33766

Quelques ressources connexes :

ColorBrewer - Séries de couleurs conçues pour se distinguer au maximum pour une utilisation sur les cartes.

S'échapper du RGBland : Sélection des couleurs pour les graphiques statistiques - Rapport technique décrivant un ensemble d'algorithmes permettant de générer de bons ensembles de couleurs (c'est-à-dire pouvant être distingués au maximum) dans l'espace couleur hcl.

1 votes

Escaping RGBland est une référence à lire absolument pour choisir des palettes de couleurs perceptibles.

10voto

ravenspoint Points 8840

Voici un code permettant de répartir les couleurs RVB de manière uniforme autour d'une roue de couleurs HSL de luminosité spécifiée.

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

2 votes

A priori, il est facile de porter du code de C++ à Java.

0 votes

Pas quand je ne comprends pas tous les trucs de décalage de bits, entre autres choses :/

0 votes

J'ai fourni des URL qui renvoient à des explications sur ce que fait le code.

5voto

svrist Points 3408

L'ordre dans lequel vous placez les couleurs n'est-il pas également un facteur ?

Comme si vous utilisiez l'idée de Dillie-Os, vous devez mélanger les couleurs autant que possible. 0 64 128 256 est de l'un à l'autre. Mais 0 256 64 128 dans une roue serait plus "à part".

Est-ce que cela a un sens ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X