Fonction pour créer des roues de couleur

C'est quelque chose que j'ai résolu de nombreuses fois et que je n'ai jamais trouvé de solution. C'est coincé avec moi. Le problème est de trouver un moyen de générer des couleurs N aussi distinctives que possible où N est un paramètre.

0
ajouté édité
Vues: 4
La dernière fois que j'ai vérifié JFreeChart a cet algorithme précis et comme il est open source, vous pouvez vérifier ce qu'il fait . Je sais que les couleurs que je reçois ne semblent pas être espacées au hasard le long d'un cercle ou d'une sphère, mais plutôt choisies plus spécifiquement.
ajouté l'auteur Kathy Van Stone, source

8 Réponses

Ma première réflexion à ce sujet est "comment générer N vecteurs dans un espace qui maximise la distance les uns des autres." Vous pouvez voir que le RGB (ou toute autre échelle que vous utilisez qui forme une base dans l'espace colorimétrique) ne sont que des vecteurs. Jetez un coup d'œil à Cueillette de points aléatoires . J'espère que c'est un bon début pour vous! Une fois que vous avez un ensemble de vecteurs qui sont maximisés une partie, vous pouvez les enregistrer dans une table de hachage ou quelque chose pour plus tard, et effectuer des rotations aléatoires sur eux pour obtenir toutes les couleurs que vous désirez qui sont au maximum les uns des autres!

Edit: Thinking about this problem more, it would be better to map the colors in a linear manor, possibly (0,0,0) --> (255,255,255) lexicographically, and then distribute them evenly. I really don't know how well this will work, but it should since, lets say:

n = 10 nous savons que nous avons 16777216 couleurs (256 ^ 3). Nous pouvons 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 de vitesse mineures.

0
ajouté
Je suis d'accord que cela semble logique. RGB fabrique principalement des hybrides pourpres et oranges et relativement rarement des hybrides vert-bleu ... l'échelle des couleurs est uniforme de l'infrarouge au bleu foncé, il faut donc choisir des points espacés le long de celle-ci. besoin d'un algo basé sur l'arc-en-ciel.
ajouté l'auteur com.prehensible, source
S'il vous plaît envisager d'upvoting / suivant le site de théorie des couleurs StackExchange: area51.stackexchange.com/proposals/110687/color-theory</ a>
ajouté l'auteur Adi Shavit, source
Ceci est incorrect car l'espace colorimétrique RVB n'est pas uniformément perceptuel
ajouté l'auteur adrienlucca.wordpress.com, source

J'ai lu quelque part que l'œil humain ne peut distinguer entre moins de quatre valeurs. C'est 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 aléatoirement des valeurs de couleurs 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 ceci 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 de mettre au rebut 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.

0
ajouté

N'est-ce pas aussi un facteur qui vous ordonne de configurer les couleurs?

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 ça a du sens?

0
ajouté

Quelques ressources connexes:

ColorBrewer - Sets of colours designed to be maximally distinguishable for use on maps.

Escaping RGBland: Selecting Colors for Statistical Graphics - A technical report describing a set of algorithms for generating good (i.e. maximally distinguishable) colour sets in the hcl colour space.

0
ajouté
Escaping RGBland est un must pour lire les références pour choisir des palettes de couleurs perçues perceptuellement.
ajouté l'auteur Drake Guan, source

Voici un code pour allouer les couleurs RVB uniformément autour d'une roue de couleurs HSL de luminosité spécifiée.

class cColorPicker
{
public:
    void Pick( vector&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&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(rm1 * 255);
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector 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;
}
0
ajouté
pas quand je ne comprends pas tout ce qui bouge, entre autres choses: /
ajouté l'auteur CodeGuy, source
Et si je veux inclure que les couleurs soient aussi distinctes d'une couleur de fond que je fournis?
ajouté l'auteur CodeGuy, source
AFAIK il est facile de porter le code de C ++ vers Java
ajouté l'auteur ravenspoint, source
J'ai fourni des URL qui donnent des explications sur ce que fait le code.
ajouté l'auteur ravenspoint, source
Calculez la «distance» entre les couleurs générées et votre couleur de fond. N'utilisez pas la couleur la plus proche de votre arrière-plan.
ajouté l'auteur ravenspoint, source
Ça va peut-être marcher un peu mais ça va donner de mauvais résultats, CIELAB c'est mieux
ajouté l'auteur adrienlucca.wordpress.com, source

Il serait préférable de trouver des couleurs au maximum éloignées dans un espace de couleurs "perceptivement uniforme", par ex. CIELAB (en utilisant la distance euclidienne entre les coordonnées L *, a *, b * comme mesure de distance), puis en convertissant dans l'espace de couleurs de votre choix. L'uniformité perceptive est obtenue en ajustant l'espace de couleurs pour approcher les non-linéarités dans le système visuel humain.

0
ajouté
C'est probablement la meilleure solution car elle est assez simple. Cependant, il existe d'autres formules de différences de couleur à considérer, comme CIE2000 ou même CIECAM
ajouté l'auteur adrienlucca.wordpress.com, source

Pour obtenir le "plus distinguable", nous devons utiliser un espace de couleur perceptif comme Lab (ou tout autre espace de couleur perceptuellement linéaire) et non RGB. En outre, nous pouvons 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 approximativement les plus distincts les uns des autres.

0
ajouté

Je sais que c'est un vieux post mais je l'ai trouvé en cherchant une solution PHP sur le sujet et finalement venu avec 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é.

0
ajouté
Pouvez-vous expliquer ce que "je" est dans ce cas? La question a demandé N nombres. Quel est le paramètre "i"?
ajouté l'auteur CodeGuy, source
Je vois! Merci pour l'explication. Encore une chose ... des suggestions pour quoi faire si j'ai une couleur d'arrière-plan et que je veux être aussi loin de cela que possible pour toutes les couleurs?
ajouté l'auteur CodeGuy, source
Sur random_color() , $ i est le "seed" pour générer la teinte, devrait être un nombre de 0 à $ n , si vous entrée aucune graine (NULL), la fonction choisit un aléatoire. $ n est la quantité de couleurs possibles pour une saturation et une luminosité donnée, c'est-à-dire le nombre de couleurs dans la palette. En gros, nous divisons les 360 degrés hue en $ n et en utilisant $ i comme un multiplicateur. En d'autres termes, plus $ n vous donnera plus de couleurs, plus $ n
ajouté l'auteur Mauro, source
Vous devez ajouter 180 degrés à la teinte de votre couleur en maintenant la saturation et la valeur. Postez une nouvelle question pour cela, collez le lien ici et je vous expliquerai plus loin!
ajouté l'auteur Mauro, source