Funksjon for å etablere fargehjul

stemmer
65

Dette er noe jeg har pseudo-løst mange ganger og har aldri helt funnet en løsning for.

Problemet er å komme opp med en måte å generere Nfarger, som er så gjenkjennelig som mulig der Ner en parameter.

Publisert på 01/08/2008 klokken 18:42
kilden bruker
På andre språk...                            


8 svar

stemmer
24

Min første tanke på dette er "hvordan å generere N vektorer i et rom som maksimerer avstand fra hverandre."

Du kan se at RGB (eller en annen skala du bruker som danner utgangspunkt i fargeområde) er bare vektorer. Ta en titt på tilfeldig Point plukking . Når du har et sett med vektorer som er maksimert hverandre, kan du lagre dem i en hash tabell eller noe til senere, og bare utføre tilfeldige rotasjoner på dem for å få alle de fargene du ønsker at er maksimalt fra hverandre!

Tenker dette problemet mer, ville det være bedre å kartlegge farger i en lineær måte, muligens (0,0,0) → (255255255) leksikografisk, og deretter distribuere dem jevnt.

Jeg vet ikke hvor godt dette vil fungere, men det bør da, la oss si:

n = 10

vi vet vi har 16777216 farger (256 ^ 3).

Vi kan bruke Spenner Algoritme 515 for å finne den leksikografisk indeksert farge. \ Frac {\ Binom {256 ^ 3} {3}} {n} * i. Du vil sannsynligvis nødt til å redigere algoritme for å unngå overløp og sannsynligvis legge noen mindre hastighetsforbedringer.

Svarte 02/08/2008 kl. 19:03
kilden bruker

stemmer
17

Det ville være best å finne farger maksimalt fjerntliggende i en "perseptuelt uniform" fargerom, f.eks CIELAB (ved hjelp av euklidske avstand mellom L *, a *, b * koordinater som avstanden metrisk) og deretter omdannelse til den fargerom etter eget valg. Perseptuell ensartethet oppnås ved å tilpasse fargerom til tilnærmet de ikke-lineariteter i det menneskelige visuelle system.

Svarte 12/09/2008 kl. 19:00
kilden bruker

stemmer
7

Noen relaterte ressurser:

ColorBrewer - Sett med farger designet for å være mest mulig gjenkjennelig for bruk på kart.

Rømmer RGBland: Velge farger for statistiske Graphics - En teknisk rapport som beskriver et sett av algoritmer for å generere gode (dvs. maksimalt skjelnes) fargesettene i hcl fargerom.

Svarte 18/09/2008 kl. 16:01
kilden bruker

stemmer
6

Her er noen kode å bevilge RGB-farger jevnt rundt en HSL fargehjul med spesifisert lysstyrke.

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;
}
Svarte 27/09/2008 kl. 16:39
kilden bruker

stemmer
4

Er det ikke også en faktor hvilken rekkefølge du setter opp fargene?

Som hvis du bruker Dillie-Os idé du trenger å blande fargene så mye som mulig. 0 64 128 256 er fra den ene til den neste. men 0 256 64 128 i et hjul ville være mer "apart"

gir dette mening?

Svarte 02/08/2008 kl. 18:16
kilden bruker

stemmer
2

Jeg har lest et sted det menneskelige øyet ikke kan skille mellom mindre enn 4 verdier fra hverandre. Så dette er noe å huske på. Følgende algoritme ikke kompenserer for dette.

Jeg er ikke sikker på at dette er akkurat hva du vil, men dette er en måte å tilfeldig generere ikke-repeterende fargeverdier:

(Vær forsiktig, inkonsekvent pseudo-kode fremover)

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

En måte du kan optimalisere dette for bedre synlighet ville være å sammenligne avstanden mellom hver nye farger og alle fargene i matrisen:

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

Men denne tilnærmingen ville betydelig tregere algoritme.

En annen måte ville være å skrap vilkårlighet og systematisk gå gjennom hver 4. verdier og legge en farge til en matrise i eksempelet ovenfor.

Svarte 01/08/2008 kl. 19:36
kilden bruker

stemmer
1

Jeg vet at dette er et gammelt innlegg, men jeg fant det mens du leter etter en PHP løsning til temaet og til slutt kom med en enkel løsning:

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

Så bare ringe random_color () -funksjonen der $ jeg identifiserer fargen, $ n antall mulige farger, satt $ metning og $ br lysstyrken.

Svarte 19/10/2011 kl. 01:58
kilden bruker

stemmer
0

For å oppnå "mest gjenkjennelig" vi trenger å bruke en perseptuelle fargerommet som Lab (eller andre perceptually lineært fargeområde) og ikke RGB. Også kan vi kvantifisere denne plassen til å redusere størrelsen på plass.

Generere hele 3D-rom med alle mulige kvantiserte oppføringer og kjøre K-betyr algoritme med k=N. De resulterende sentrene / "betyr" bør være omtrent mest distinguishabl fra hverandre.

Svarte 07/02/2014 kl. 17:43
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more