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.
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.
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. . Vous devrez probablement modifier l'algorithme pour éviter les débordements et probablement ajouter quelques améliorations mineures de la vitesse.
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.
Veuillez envisager de voter pour ou de suivre le site StackExchange Color Theory : area51.stackexchange.com/propositions/110687/color-theory
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.
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.
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;
}
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.
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.