2010-06-10 8 views
15

Me gustaría ordenar una lista unidimensional de colores para que los colores que un humano típico percibiría como "similares" entre sí se encuentren uno cerca del otro.¿Cómo ordenar una lista de colores en una dimensión?

Obviamente, este es un problema difícil o imposible para obtener "perfectamente", ya que los colores se describen típicamente con tres dimensiones, pero eso no significa que no haya algunos métodos de clasificación que se vean más naturales que otros.

Por ejemplo, la clasificación por RGB no funciona muy bien, ya que va a clasificar en el orden siguiente, por ejemplo:

(1) R = 254 G = 0 B = 0 (2) R = 254 G = 255 B = 0 (3) R = 255 G = 0 B = 0 (4) R = 255 G = 255 B = 0

Eso es, alternará esos colores rojo, amarillo, rojo, amarillo, con los dos "rojos" que son imperceptiblemente diferentes entre sí, y los dos amarillos también son imperceptiblemente diferentes el uno del otro.

Pero clasificar por HLS funciona mucho mejor, en términos generales, y creo que HSL es incluso mejor que eso; con cualquiera, los rojos estarán uno al lado del otro, y los amarillos estarán uno al lado del otro.

Pero HLS/HSL también tiene algunos problemas; las cosas que las personas percibirían como "negras" podrían separarse una de la otra, al igual que las cosas que las personas percibirían como "blancas".

De nuevo, entiendo que tengo que aceptar que habrá algunas divisiones como esta; Me pregunto si alguien ha encontrado una mejor manera que HLS/HSL. Y soy consciente de que "mejor" es algo arbitrario; Me refiero a "más natural para un humano típico".

Por ejemplo, un pensamiento vago que he tenido, pero que aún no he intentado, es quizás "L es lo más importante si es muy alto o muy bajo", pero por lo demás es lo menos importante. ¿Alguien ha probado esto? ¿Ha funcionado bien? ¿Qué específicamente decidiste que significaba "muy bajo" y "muy alto"? Y así. ¿O alguien ha encontrado algo más que mejore en HSL?

También debo tener en cuenta que soy consciente de que puedo definir una curva de relleno de espacio a través del cubo de colores y ordenarlos de forma unidimensional tal como se encontrarían al viajar a lo largo de esa curva. Eso eliminaría las discontinuidades percibidas. Sin embargo, no es realmente lo que quiero; Quiero agrupaciones generales de gran escala decentes más de lo que quiero agrupaciones perfectas a pequeña escala.

Gracias de antemano por cualquier ayuda.

+0

¿Cuántos colores (más o menos) estamos hablando? ¿Y necesita un algoritmo para esto, o bastaría un enfoque basado en tabla o en cubo? –

Respuesta

4

Hay dos enfoques que puede tomar. El enfoque simple es destilar cada color en un solo valor, y la lista de valores puede ser ordenada. El enfoque complejo dependerá de todos los colores que tiene que ordenar; tal vez sería una solución iterativa que mezcla repetidamente los colores tratando de minimizar la "energía" de toda la secuencia.

Supongo que quiere algo simple y rápido que se vea "lo suficientemente agradable" (en lugar de tratar de descubrir el tipo de color estético "óptimo"), por lo que el enfoque simple es suficiente para usted.

Yo diría que HSL es el camino a seguir. Algo así como

sortValue = L * 5 + S * 2 + H 

suponiendo que H, S y L son cada uno en el intervalo [0, 1].

+0

Lo he intentado y realmente funciona muy bien. Gracias. – liviucmg

+1

¿Se te ocurrió esto o tienes una referencia para mí? – Sander

0

He aquí una idea que surgió después de un par de minutos de reflexión. Puede ser una porquería, o puede que ni siquiera funcione en absoluto, pero lo escupiré de todos modos.

definir una función de la distancia en el espacio de colores, d(x, y) (donde las entradas x y y son los colores y la salida es tal vez un número de coma flotante). La función de distancia que elijas puede no ser muy importante. Podría ser la suma de los cuadrados de las diferencias en los componentes R, G y B, por ejemplo, o podría ser un polinomio en las diferencias en los componentes H, L y S (con los componentes ponderados de manera diferente según la importancia que tengas son).

Luego se calcula la "distancia" de cada color en su lista, lo que efectivamente le da un gráfico. A continuación, calcula el árbol de expansión mínimo de su gráfico. Luego identifica el camino más largo (sin retroceso) que existe en su MST. Los puntos finales de esta ruta serán los puntos finales de la lista final. A continuación, intenta "aplanar" el árbol en una línea al poner puntos en las "ramas" fuera de su camino en la ruta misma.

Hmm. Es posible que esto no funcione tan bien si su MST termina en la forma de un círculo cercano en el espacio de color. Pero tal vez cualquier enfoque tendría ese problema.

0
A. R=254 G=0 B=0 
B. R=254 G=255 B=0 
C. R=255 G=0 B=0 
D. R=255 G=255 B=0 

Debe tener en cuenta la diferencia entre los colores vecinos.

El diff entre A y B es 0 + 255 + 0 = 255. El diff entre A y C es de 1 + 0 + 0 = 1.

El diff entre A y B es mayor que A y C de modo que a está más cerca de C así intercambiar B y C.

A. R=254 G=0 B=0 
C. R=255 G=0 B=0 
B. R=254 G=255 B=0 
D. R=255 G=255 B=0 

El diff entre C y B es 1 + 255 + 0 = 256. El diff entre C y D es 0 + 255 + 0 = 255

La diferencia entre C y B es mayor que C y D, por lo que C está más cerca de D, por lo que se intercambian B y D.

A. R=254 G=0 B=0 
C. R=255 G=0 B=0 
D. R=255 G=255 B=0 
B. R=254 G=255 B=0 

Trátelo como una especie de burbuja. Este no es un algoritmo perfecto de ninguna manera y probablemente haya mejores formas de abordarlo, pero esto podría ser una patada en la dirección correcta.

también ...

que había necesidad alguna manera cobarde para hacer comparaciones entre el sujeto.

5

No puede hacer esto sin reducir las 3 dimensiones de color a una sola medición. Hay muchas formas (infinitas) de reducir esta información, pero no es matemáticamente posible hacerlo de una manera que asegure que dos puntos de datos cercanos entre sí en el continuo reducido también estarán cerca el uno del otro en los tres colores de sus componentes valores. Como resultado, cualquier fórmula de este tipo terminará agrupando colores diferentes.

Como mencionó en su pregunta, una forma de hacer esto sería ajustar una curva compleja a través del espacio de color tridimensional ocupado por los puntos de datos que está tratando de clasificar, y luego reducir cada punto de datos a su ubicación más cercana en la curva y luego a la distancia de ese punto a lo largo de la curva. Esto funcionaría, pero en cada caso sería una solución personalizada, adaptada a un conjunto particular de puntos de datos (en lugar de una solución generalmente aplicable).También sería relativamente caro (tal vez), y simplemente no funcionaría en un conjunto de datos que no estaba bien distribuido en una especie de línea curva.

Una alternativa más simple (que no funcionaría perfectamente) sería elegir dos colores de "punto final", preferiblemente en lados opuestos de la rueda de colores. Entonces, por ejemplo, puede elegir Rojo como un color de punto final y Azul como el otro. Luego convertiría cada punto de datos de color a un valor en una escala de 0 a 1, donde un color muy rojizo obtendría un puntaje cercano a 0 y un color que es muy azulado obtendría un puntaje cercano a 1. Una puntuación de. 5 indicaría un color que no tiene Rojo o Azul (también conocido como Verde) o tiene cantidades iguales de Rojo y Azul (también conocido como Púrpura). Este enfoque no es perfecto, pero es lo mejor que puede hacer con este problema.

4

Existen varias técnicas estándar para reducir las dimensiones múltiples a una sola dimensión con alguna noción de "proximidad".

Creo que deberías en particular ver el z-order transform.

Puede implementar una versión rápida de esto intercalando los bits de sus tres componentes de color y clasificando los colores en función de este valor transformado.

El siguiente código Java debería ayudar a empezar:

public static int zValue(int r, int g, int b) { 
      return split(r) + (split(g)<<1) + (split(b)<<2); 
    } 

    public static int split(int a) { 
      // split out the lowest 10 bits to lowest 30 bits 
      a=(a|(a<<12))&00014000377; 
      a=(a|(a<<8)) &00014170017; 
      a=(a|(a<<4)) &00303030303; 
      a=(a|(a<<2)) &01111111111; 
      return a; 
    } 
+1

p.s.Vale la pena señalar que este enfoque también es muy rápido gracias al hecho de que puede implementar esto con operaciones bit a bit. – mikera

+1

También vale la pena señalar que una curva de Hilbert podría ser una buena alternativa – mikera

+0

Extremadamente tarde, pero para aquellos más curiosos sobre cómo una curva de hilbert se libera para ordenar el color, vea (específicamente la sección llamada "Clasificación de Hilbert") http://www.alanzucconi.com/2015/09/30/clasificación del color / – Zimm3r

7

Si desea ordenar una lista de colores en una dimensión primero tiene que decidir, por lo que las métricas que se va a ordenar. El mayor sentido para mí es el brillo percibido (related question).

He encontrado 4 algoritmos para ordenar colores por brillo y compararlos. Aquí está el resultado.

He generado colores en el ciclo en el que se utilizaba aproximadamente cada 400º color. Cada color está representado por 2x2 píxeles, los colores se ordenan de más oscuro a más claro (de izquierda a derecha, de arriba a abajo).

primera imagen - Luminance (relative)

0.2126 * R + 0.7152 * G + 0.0722 * B 

segunda imagen - http://www.w3.org/TR/AERT#color-contrast

0.299 * R + 0.587 * G + 0.114 * B 

tercera foto - imagen HSP Color Model

sqrt(0.299 * R^2 + 0.587 * G^2 + 0.114 * B^2) 

4TD - WCAG 2.0 SC 1.4.3relative luminance y contrast ratio fórmula

El patrón a veces se puede ver en la 1ª y la 2da imagen dependiendo del número de colores en una fila. Nunca vi ningún patrón en la imagen del 3er o 4to algoritmo.

Si tuviera que elegir me iría con algoritmo número 3, ya que es mucho más fácil de implementar y sus cerca de 33% más rápido que el cuarto

Perceived brightness algorithm comparison

Cuestiones relacionadas