Frage

Das ist etwas, was ich schon oft pseudogelöst habe und nie eine Lösung dafür gefunden habe.

Das Problem besteht darin, einen Weg zur Generierung zu finden N Farben, die möglichst unterscheidbar sind N ist ein Parameter.

War es hilfreich?

Lösung

Mein erster Gedanke dazu ist: „Wie man N Vektoren in einem Raum erzeugt, die den Abstand zueinander maximieren.“

Sie können sehen, dass RGB (oder jede andere von Ihnen verwendete Skala, die eine Grundlage im Farbraum bildet) nur Vektoren sind.Schauen Sie mal rein Zufällige Punktauswahl.Sobald Sie eine Reihe von Vektoren haben, die maximal voneinander entfernt sind, können Sie sie für später in einer Hash-Tabelle oder etwas Ähnlichem speichern und einfach zufällige Rotationen an ihnen durchführen, um alle gewünschten Farben zu erhalten, die maximal voneinander entfernt sind!

Wenn man über dieses Problem genauer nachdenkt, wäre es besser, die Farben linear abzubilden, möglicherweise (0,0,0) → (255.255.255) lexikografisch, und sie dann gleichmäßig zu verteilen.

Ich weiß wirklich nicht, wie gut das funktionieren wird, aber es sollte seitdem so sein, sagen wir mal:

n = 10

Wir wissen, dass wir 16777216 Farben (256^3) haben.

Wir können benutzen Schnallen-Algorithmus 515 um die lexikographisch indizierte Farbe zu finden.\frac {\binom {256^3} {3}} {n} * i.Sie müssen wahrscheinlich den Algorithmus bearbeiten, um einen Überlauf zu vermeiden, und wahrscheinlich einige kleinere Geschwindigkeitsverbesserungen hinzufügen.

Andere Tipps

Es wäre am besten, Farben zu finden, die in einem „wahrnehmungsmäßig einheitlichen“ Farbraum maximal entfernt sind, z. B.CIELAB (unter Verwendung des euklidischen Abstands zwischen den Koordinaten L*, a*, b* als Abstandsmetrik) und anschließende Konvertierung in den Farbraum Ihrer Wahl.Durch die Anpassung des Farbraums an die Nichtlinearitäten im menschlichen visuellen System wird eine einheitliche Wahrnehmung erreicht.

Einige verwandte Ressourcen:

ColorBrewer - Farbsätze, die so konzipiert sind, dass sie für die Verwendung auf Karten maximal unterscheidbar sind.

RGBland entkommen:Auswählen von Farben für statistische Grafiken - Ein technischer Bericht, der eine Reihe von Algorithmen zur Generierung von Gütern beschreibt (d. h.maximal unterscheidbare) Farbsätze im hcl-Farbraum.

Hier ist ein Code, um RGB-Farben gleichmäßig um einen HSL-Farbkreis mit angegebener Helligkeit zu verteilen.

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

Spielt es nicht auch eine Rolle, in welcher Reihenfolge Sie die Farben anordnen?

Wenn Sie beispielsweise die Idee von Dillie-O verwenden, müssen Sie die Farben so weit wie möglich mischen.0 64 128 256 ist von einem zum nächsten.aber 0 256 64 128 in einem Rad wäre mehr „auseinander“

Macht das Sinn?

Ich habe irgendwo gelesen, dass das menschliche Auge nicht zwischen weniger als 4 Werten unterscheiden kann.Das ist also etwas, das man im Hinterkopf behalten sollte.Der folgende Algorithmus kompensiert dies nicht.

Ich bin mir nicht sicher, ob das genau das ist, was Sie wollen, aber dies ist eine Möglichkeit, zufällig nicht wiederkehrende Farbwerte zu generieren:

(Vorsicht, inkonsistenter Pseudocode voraus)

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

Eine Möglichkeit, dies für eine bessere Sichtbarkeit zu optimieren, besteht darin, den Abstand zwischen jeder neuen Farbe und allen Farben im Array zu vergleichen:

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

Dieser Ansatz würde Ihren Algorithmus jedoch erheblich verlangsamen.

Eine andere Möglichkeit wäre, die Zufälligkeit zu beseitigen und systematisch alle 4 Werte durchzugehen und im obigen Beispiel eine Farbe zu einem Array hinzuzufügen.

Ich weiß, dass dies ein alter Beitrag ist, aber ich habe ihn gefunden, als ich nach einer PHP-Lösung für das Thema gesucht habe, und bin schließlich auf eine einfache Lösung gestoßen:

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

Rufen Sie also einfach die Funktion random_color() auf, wobei $i die Farbe angibt, $n die Anzahl der möglichen Farben, $sat die Sättigung und $br die Helligkeit.

Um eine „höchste Unterscheidbarkeit“ zu erreichen, müssen wir einen wahrnehmungsbezogenen Farbraum wie Lab (oder einen anderen wahrnehmungsmäßig linearen Farbraum) und nicht RGB verwenden.Außerdem können wir diesen Raum quantisieren, um die Größe des Raums zu reduzieren.

Erzeugen Sie den vollständigen 3D-Raum mit allen möglichen quantisierten Einträgen und führen Sie den K-Means-Algorithmus aus k=N.Die resultierenden Zentren/„Mittel“ sollten annähernd am besten voneinander unterscheidbar sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top