Question

C'est quelque chose que j'ai pseudo-résolu à plusieurs reprises et pour lequel je n'ai jamais vraiment trouvé de solution.

Le problème est de trouver un moyen de générer N couleurs, qui soient aussi distinctes que possible là où N est un paramètre.

Était-ce utile?

La solution

Ma première réflexion à ce sujet est "comment générer N vecteurs dans un espace qui maximisent la distance les uns par rapport aux autres".

Vous pouvez voir que le RVB (ou toute autre échelle que vous utilisez et qui constitue une base dans l'espace colorimétrique) ne sont que des vecteurs.Jeter un coup d'œil à Sélection de points aléatoire.Une fois que vous disposez d'un ensemble de vecteurs maximisés, vous pouvez les enregistrer dans une table de hachage ou quelque chose comme ça pour plus tard, et simplement effectuer des rotations aléatoires sur eux pour obtenir toutes les couleurs que vous désirez qui sont au maximum 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 dans quelle mesure cela fonctionnera bien, mais cela devrait puisque, disons :

n = 10

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

On peut utiliser Algorithme de 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.

Autres conseils

Il serait préférable de trouver des couleurs aussi éloignées que possible dans un espace colorimétrique « perceptuellement uniforme », par ex.CIELAB (en utilisant la distance euclidienne entre les coordonnées L*, a*, b* comme métrique de distance), puis en convertissant dans l'espace colorimétrique de votre choix.L'uniformité de la perception est obtenue en ajustant l'espace colorimétrique pour se rapprocher des non-linéarités du système visuel humain.

Quelques ressources connexes :

CouleurBrewer - Ensembles de couleurs conçus pour être distingués au maximum pour une utilisation sur les cartes.

Échapper à RGBland :Sélection des couleurs pour les graphiques statistiques - Un rapport technique décrivant un ensemble d'algorithmes pour générer un bien (c.-à-d.différenciables au maximum) des jeux de couleurs dans l'espace colorimétrique hcl.

Voici un code pour attribuer les couleurs RVB uniformément autour d'une roue chromatique 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;
}

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

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

Est-ce que ça a du sens?

J'ai lu quelque part que l'œil humain ne peut pas distinguer moins de 4 valeurs espacées.c'est donc quelque chose à garder à l'esprit.L'algorithme suivant ne compense pas cela.

Je ne suis pas sûr que ce soit exactement ce que vous voulez, mais c'est une façon de générer de manière aléatoire des valeurs de couleur non répétitives :

(attention, pseudo-code incohérent à venir)

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

Une façon d'optimiser cela pour une meilleure visibilité serait de comparer la distance entre chaque nouvelle couleur et toutes les couleurs du tableau :

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

Mais cette approche ralentirait considérablement votre algorithme.

Une autre façon serait d'éliminer le caractère aléatoire et de parcourir systématiquement toutes les 4 valeurs et d'ajouter une couleur à un tableau dans l'exemple ci-dessus.

Je sais que c'est un vieux post mais je l'ai trouvé en cherchant une solution PHP au sujet et j'ai finalement proposé une solution simple :

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

Il suffit donc d'appeler la fonction random_color() où $i identifie la couleur, $n le nombre de couleurs possibles, $sat la saturation et $br la luminosité.

Pour obtenir « le plus distinctif », nous devons utiliser un espace colorimétrique perceptuel comme Lab (ou tout autre espace colorimétrique perceptuellement linéaire) et non RVB.Nous pouvons également quantifier cet espace pour réduire la taille de l’espace.

Générez l'espace 3D complet avec toutes les entrées quantifiées possibles et exécutez l'algorithme K-means avec k=N.Les centres/« moyens » résultants devraient être à peu près les plus distinctifs les uns des autres.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top