Función para crear ruedas de color

votos
63

Esto es algo que he pseudo-resuelto muchas veces y nunca he encontrado una solución para él.

El problema es encontrar una forma de generar Ncolores, que sea tan distinguible como sea posible donde se Nencuentra un parámetro.

Publicado el 01/08/2008 a las 19:42
fuente por usuario
En otros idiomas...                            


8 respuestas

votos
1

He leído en alguna parte que el ojo humano no puede distinguir entre menos de 4 valores aparte. así que esto es algo a tener en cuenta. El siguiente algoritmo no compensa esto.

No estoy seguro de que esto sea exactamente lo que quiere, pero esta es una manera de generar aleatoriamente valores de color no repetitivos:

(cuidado, pseudo-código inconsistente adelante)

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

Una forma de optimizar esto para una mejor visibilidad sería comparar la distancia entre cada nuevo color y todos los colores en la matriz:

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

Pero este enfoque ralentizaría significativamente su algoritmo.

Otra forma sería eliminar la aleatoriedad y examinar sistemáticamente cada 4 valores y agregar un color a una matriz en el ejemplo anterior.

Respondida el 01/08/2008 a las 20:36
fuente por usuario

votos
3

¿No es también un factor que ordenas configurar los colores?

Como si usara la idea de Dillie-Os, necesita mezclar los colores tanto como sea posible. 0 64 128 256 es de uno a otro. pero 0 256 64 128 en una rueda sería más "aparte"

¿Esto tiene sentido?

Respondida el 02/08/2008 a las 19:16
fuente por usuario

votos
23

Mi primer pensamiento sobre esto es "cómo generar N vectores en un espacio que maximiza la distancia el uno del otro".

Puede ver que el RGB (o cualquier otra escala que use que forme una base en el espacio de color) son solo vectores. Eche un vistazo a la selección aleatoria de puntos . Una vez que tiene un conjunto de vectores que están maximizados por separado, puede guardarlos en una tabla hash o algo para más adelante, y simplemente realizar rotaciones al azar en ellos para obtener todos los colores que desea que estén separados el uno del otro.

Pensando más en este problema, sería mejor mapear los colores de forma lineal, posiblemente (0,0,0) → (255,255,255) lexicográficamente, y luego distribuirlos de manera uniforme.

Realmente no sé qué tan bien funcionará esto, pero debería hacerlo, digamos:

n = 10

sabemos que tenemos 16777216 colores (256 ^ 3).

Podemos usar el algoritmo 515 de Hebillas para encontrar el color indexado lexicográficamente. \ frac {\ binom {256 ^ 3} {3}} {n} * i. Probablemente tengas que editar el algoritmo para evitar el desbordamiento y probablemente agregar algunas mejoras menores de velocidad.

Respondida el 02/08/2008 a las 20:03
fuente por usuario

votos
17

Lo mejor sería encontrar los colores más distantes en un espacio de color "perceptualmente uniforme", por ejemplo, CIELAB (usando la distancia euclidiana entre las coordenadas L *, a *, b * como su métrica de distancia) y luego convirtiendo al espacio de color de su elección. La uniformidad perceptiva se logra ajustando el espacio de color para aproximar las no linealidades en el sistema visual humano.

Respondida el 12/09/2008 a las 20:00
fuente por usuario

votos
7

Algunos recursos relacionados:

ColorBrewer : conjuntos de colores diseñados para ser distinguibles al máximo para su uso en mapas.

Escapar RGBland: Seleccionar colores para gráficos estadísticos : un informe técnico que describe un conjunto de algoritmos para generar conjuntos de colores buenos (es decir, distinguibles al máximo) en el espacio de color hcl.

Respondida el 18/09/2008 a las 17:01
fuente por usuario

votos
6

Aquí hay un código para asignar colores RGB de manera uniforme alrededor de una rueda de color HSL de luminosidad especificada.

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;
}
Respondida el 27/09/2008 a las 17:39
fuente por usuario

votos
1

Sé que esto una entrada antigua, pero lo encontré en la búsqueda de una solución PHP con el tema y finalmente llegó con una solución sencilla:

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

Por lo que sólo llamar a la función random_color () donde $ i identifica el color, $ n el número de posibles colores, $ sentó la saturación y el brillo $ sa.

Respondida el 19/10/2011 a las 02:58
fuente por usuario

votos
0

Para lograr "más distinguibles" tenemos que utilizar un espacio de percepción del color como Laboratorio (o cualquier otro espacio de color perceptualmente lineal) y no RGB. También, podemos cuantificar este espacio para reducir el tamaño del espacio.

Generar el espacio 3D completa con todas las posibles entradas cuantificados y ejecutar el algoritmo k-medias con k=N. Los centros resultantes / "significa" debe ser aproximadamente más distinguishabl unos de otros.

Respondida el 07/02/2014 a las 18:43
fuente por usuario

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