algorithm - Funktion zum Erstellen von Farbrädern

Translate

Dies ist etwas, das ich viele Male pseudo-gelöst habe und für das ich nie eine Lösung gefunden habe.

Das Problem besteht darin, einen Weg zum Generieren zu findenNFarben, die wo möglich so unterscheidbar sindNist ein Parameter.

This question and all comments follow the "Attribution Required."

Alle Antworten

Translate

Mein erster Gedanke dazu ist "wie man N Vektoren in einem Raum erzeugt, der den Abstand voneinander maximiert".

Sie können sehen, dass das RGB (oder jede andere Skala, die Sie als Grundlage für den Farbraum verwenden) nur Vektoren sind. Schau es dir anZufällige Punktauswahl. Sobald Sie eine Reihe von Vektoren haben, die auseinander maximiert sind, können Sie sie in einer Hash-Tabelle oder etwas anderem für später speichern und sie einfach zufällig drehen, um alle gewünschten Farben zu erhalten, die maximal voneinander getrennt sind!

Wenn Sie mehr über dieses Problem nachdenken, ist 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 sagen wir:

n = 10

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

Wir können benutzenSchnallen-Algorithmus 515um 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 möglicherweise einige kleinere Geschwindigkeitsverbesserungen hinzuzufügen.

Quelle
Translate

Es ist am besten, Farben zu finden, die in einem "wahrnehmungsmäßig einheitlichen" Farbraum maximal entfernt sind, z. B. CIELAB (unter Verwendung des euklidischen Abstands zwischen L * -, a * -, b * -Koordinaten als Abstandsmetrik) und dann in den Farbraum Ihrer Wahl zu konvertieren. Die Wahrnehmungsgleichmäßigkeit wird erreicht, indem der Farbraum so angepasst wird, dass die Nichtlinearitäten im menschlichen visuellen System angenähert werden.

Quelle
Translate

Einige verwandte Ressourcen:

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

Escaping RGBland: Auswählen von Farben für statistische Grafiken- Ein technischer Bericht, der eine Reihe von Algorithmen zur Erzeugung guter (dh maximal unterscheidbarer) Farbsätze im hcl-Farbraum beschreibt.

Quelle
Translate

Hier ist ein Code zum gleichmäßigen Zuweisen von RGB-Farben um ein HSL-Farbrad mit der angegebenen Leuchtkraft.

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

Ist es nicht auch ein Faktor, in welcher Reihenfolge Sie die Farben einstellen?

Wenn Sie beispielsweise die Dillie-Os-Idee 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?

Quelle
Translate

Ich habe irgendwo gelesen, dass das menschliche Auge nicht zwischen weniger als 4 Werten unterscheiden kann. Dies ist also etwas zu beachten. Der folgende Algorithmus kompensiert dies nicht.

Ich bin nicht sicher, ob dies genau das ist, was Sie wollen, aber dies ist eine Möglichkeit, nicht wiederholte Farbwerte zufällig 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 einem Array im obigen Beispiel eine Farbe hinzuzufügen.

Quelle
Translate

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 schließlich eine einfache Lösung gefunden:

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 einfach die Funktion random_color () auf, bei der $ i die Farbe, $ n die Anzahl der möglichen Farben, $ die Sättigung und $ br die Helligkeit identifiziert.

Quelle
Translate

Um "am besten unterscheidbar" zu erreichen, müssen wir einen Wahrnehmungsfarbraum wie Lab (oder einen anderen wahrnehmungslinearen Farbraum) und kein RGB verwenden. Wir können diesen Raum auch quantisieren, um die Größe des Raums zu verringern.

Generieren Sie den gesamten 3D-Raum mit allen möglichen quantisierten Einträgen und führen Sie den K-Means-Algorithmus mit ausk=N. Die resultierenden Zentren / "Mittel" sollten ungefähr am besten voneinander unterscheidbar sein.

Quelle