Estoy creando una demostración de 20 bolas rebotando entre sí, con un fondo lleno de un color sólido. El color de cada bola se elige al azar con randint(0, 255)
cada componente de tupla R, G, B.
El problema es que algunas bolas terminan con un color muy similar al del fondo, lo que las hace difíciles de ver. Me gustaría evitar eso, ya sea rodando otro color si el elegido es demasiado similar (dentro de un umbral dado) o alejándolo del color de fondo.
¿Cómo calcular un índice de similitud para usar como umbral? ¿O cómo transformar un color para hacerlo, digamos, menos azulado ?
Descargo de responsabilidad obvio: no sé nada sobre la teoría del color, ¡así que no sé si los conceptos anteriores existen!
Estoy codificando en Python, pero estoy buscando conceptos y estrategias, por lo que el pseudocódigo está bien (o solo la teoría).
EDITAR:
Para aclarar algunos puntos:
Cada bola tiene su propio color aleatorio. Me gustaría que permanecieran lo más aleatorios posible y que explorasen lo más posible el espacio de color (ya sea RGB o HSV,
pygame
acepta ambos formatos para definir el color)Solo me gustaría evitar que cada color esté "demasiado cerca" del fondo. El problema no es solo el tono: estoy perfectamente bien con una bola azul claro sobre un fondo azul oscuro (o un "azul completo" contra un azul "blanco-ish", etc.)
Por ahora, no me importa si una bola termina con un color similar (o incluso idéntico) a otra bola. Evitar eso es una ventaja, pero es un problema menor.
El color de fondo es un color RGB único y constante. Por ahora estoy usando azul "básico"
(0, 0, 255)
, pero no estoy decidido con eso. Por lo tanto, considere que el fondo es de un color arbitrario (con matices arbitrarios, brillo, saturación, etc.).
EDIT2:
TL, versión DR: simplemente dé una forma de crear X colores aleatorios para que ninguno "se desvanezca demasiado" en un contexto de color arbitrario (pero único y constante)
Respuestas:
Puede utilizar el hecho de que los colores forman un espacio de color (tridimensional) y calcular una distancia en este espacio de color. Luego debe definir una métrica en este espacio de color para encontrar la distancia entre dos colores.
Por ejemplo, la distancia en un espacio euclidiano entre dos puntos x = (x1, x2, x3) e y = (y1, y2, y3) viene dada por d (x, y) = sqrt ((y1-x1) * (y1- x1) + (y2-x2) * (y2-x2) + (y3-x3) * (y3-x3)).
Ahora puede calcular la distancia entre el color de las bolas y el color de fondo y, si es demasiado pequeño, cree un nuevo color aleatorio y pruebe nuevamente.
Encontrará que ni RGB ni HSV son buenos espacios de color para esta tarea. El artículo de Wikipedia sobre la diferencia de color emplea el espacio de color L a b y ofrece varias métricas posibles.
También hay un diskussion en stackoverflow sobre el tema.
fuente
La página de estándares de accesibilidad web de las Naciones Unidas ( http://www.un.org/webaccessibility/1_visual/13_colourcontrast.shtml ) indica un estándar para garantizar un contraste de texto adecuado en los sitios web, teniendo en cuenta que algunos usuarios son daltónicos. Esto puede ser particularmente importante para usted, ya que algunos de sus usuarios también pueden ser daltónicos (sería difícil distinguir una bola roja de un fondo verde si tienen la misma luminosidad).
La página de la ONU apunta al Analizador de relación de contraste de color de luminosidad de Juicy Studios en ( http://juicystudio.com/services/luminositycontrastratio.php#specify ) que establece que el texto en el fondo debe tener una relación de contraste de 4.5: 1, excepto por lo que I cree que es similar a su caso:
Ahora, ¿qué es una relación de contraste? Siguiendo los hipervínculos (¡esto es divertido!) Llegamos a una página W3 que define la relación de contraste como:
Donde L1 y L2 son las luminosidades relativas de los colores. L1 es el color más luminoso, L2 es el color menos luminoso. Nuevamente, seguimos el enlace a la misma página W3 que especifica:
NOTA : El símbolo de intercalación ^ anterior se refiere a exponenciación (x²)
Y tenemos un marco bastante bueno para un algoritmo de contraste (¡eso es compatible con daltonismo!)
fuente
^
, nunca pensaría en un XOR bit a bit en este contexto. (o en cualquier caso. Vamos C phreaks,^
es el símbolo de facto para la exponenciación en pseudocódigos (aunque muy pocos lenguajes realmente lo usan ... en Python**
))El uso de valores RGB generando un
0-255
valor aleatorio para cada componente podría no solo crear colores similares al fondo, sino que también puede terminar con colores muy similares para las bolas.Probablemente elegiría un enfoque menos aleatorio y crearía colores que están garantizados para ser diferentes. Puede crear un color para cada ~ 32 grados en el rango de tono y alternar el brillo o la saturación (use el modelo de color HSV en lugar de RGB).
Entonces algo como esto:
que creará 20 colores, muy bien distribuidos. Esto supone que está utilizando álgebra de números enteros, por lo que
i = 0
yi = 1
va a crear el mismo valor de tono.Por supuesto, esto no escala demasiado bien ... si tiene 100 valores de color para crear, el espaciado de tono puede no ser suficiente y terminará con colores similares nuevamente. En ese caso, también puede variar el
V
valor (brillo).No sé cómo es su color de fondo, pero HSV también facilita la comparación de colores (solo compare los 3 componentes y no olvide que HUE es circular (0 == 360)).
ACTUALIZAR:
Como realmente no respondí su pregunta, sino que proporcioné otro enfoque, así es como podría verse un algoritmo para un fondo arbitrario y bolas de colores completamente al azar (este es un enfoque de fuerza bruta, pero debería funcionar bien para su caso de uso):
fuente
V
(ya que el algoritmo actual no altera eso).Dado que no mencionó que tiene un fondo estacionario, el color de las bolas aún puede ser aleatorio, pero tienen que caer en ciertos rangos que aún complementan el fondo.
Lo esencial. Antes de hacerlo, debe conocer los conceptos básicos. Considere los siguientes colores:
Mezcla de colores RGB [(0..255), (0..255), (0..255)] crea nuevos colores como el anterior.
Calcular para colores negativos Calcular para colores negativos es como transformar rojo en cian, verde en morado, azul en amarillo.
Color complementario
Según la referencia en Computación de colores complementarios: http://serennu.com/colour/rgbtohsl.php
Sobre HSL
HSL expresa los colores en términos de su tono, saturación y luminosidad, dando un número para cada uno de estos tres atributos del color.
El tono es la posición del color en la rueda de color, expresada en grados de 0 ° a 359 °, que representa los 360 ° de la rueda; 0 ° es rojo, 180 ° es el color opuesto al rojo cian, y así sucesivamente.
La saturación es la intensidad del color, lo opaco o brillante que es. Cuanto más baja es la saturación, más opaco (gris) se ve el color. Esto se expresa como un porcentaje, el 100% es saturación total, la más brillante, y el 0% es saturación, gris.
La ligereza es la luz del color. Ligeramente diferente a la saturación. Cuanto más blanco sea el color, mayor será su valor de Luminosidad, cuanto más negro, menor será su Luminosidad. Entonces, el 100% de luminosidad convierte el color en blanco, el 0% de luminosidad convierte el color en negro y el color "puro" sería el 50% de luminosidad.
Es más fácil ver la diferencia entre Saturación y Luminosidad que explicarla. Si desea aclarar, intente ver las variaciones de Luminosidad y Saturación en la página de la calculadora de color, eligiendo un color bastante brillante como color inicial.
Entonces la notación HSL se ve así, dando los valores de Tono, Saturación y Luminosidad en ese orden: t
Rojo: 0 ° 100% 50% Rosa pálido: 0 ° 100% 90% Cian: 180 ° 100% 50% Estos son los pasos:
Convierte tu color a HSL.
Cambie el valor de Hue al valor del Hue opuesto (por ejemplo, si su Hue es de 50 °, el opuesto estará a 230 ° en la rueda - 180 ° más alrededor).
Deje los valores de Saturación y Luminosidad como estaban.
Convierta este nuevo valor HSL nuevamente a su notación de color original (RGB o lo que sea).
Sitios como EasyRGB.com pueden realizar conversiones genéricas de RGB a HSL o viceversa.
Ejemplo de programación realizado en PHP según referencia
Conversión de RGB a HSL
El valor por encima de Azul # 0000FF rgb (0,0,255) se puede presentar como Rojo Hexadecimal 00 + Verde Hexadecimal 00 + Azul Hexadecimal FF
También se puede presentar como Rojo Decimal 0 + Verde Decimal 0 + Azul Decimal 255
Ahora conecte estos valores a la rutina rgb2hsl. A continuación se muestra mi versión PHP del código genérico de EasyRGB.com para esa conversión:
La entrada es $ var_r, $ var_g y $ var_b desde arriba La salida es equivalente a HSL como $ h, $ sy $ l - estos se expresan nuevamente como fracciones de 1, como los valores de entrada
Entonces ahora tenemos el color como un valor HSL, en las variables $ h, $ sy $ l. Estas tres variables de salida se mantienen nuevamente como fracciones de 1 en esta etapa, en lugar de como grados y porcentajes. Entonces, por ejemplo, el cian (180 ° 100% 50%) saldría como $ h = 0.5, $ s = 1 y $ l = 0.5.
Luego, encuentre el valor del Hue opuesto, es decir, el que está a 180 °, o 0.5, de distancia (estoy seguro de que los matemáticos tienen una forma más elegante de adorar esto, pero):
Calcule el tono opuesto, $ h2
El valor HSL del color complementario ahora está en $ h2, $ s, $ l. Así que estamos listos para convertir esto nuevamente a RGB (nuevamente, mi versión PHP de la fórmula EasyRGB.com). Tenga en cuenta que los formatos de entrada y salida son diferentes esta vez, vea mis comentarios en la parte superior del código:
La entrada es el valor HSL del color complementario, se mantiene en $ h2, $ s, $ l como fracciones de 1 La salida es RGB en formato normal 255 255 255, se mantiene en $ r, $ g, $ b El tono se convierte con la función hue_2_rgb, se muestra al final de este código
Y después de esa rutina, finalmente tenemos $ r, $ gy $ b en formato 255 255 255 (RGB), que podemos convertir a seis dígitos de hexadecimal:
$ rgbhex es nuestra respuesta: el color complementario en hexadecimal.
Como su fondo de color es azul o 0,0,255, el HSL es
Tono (H): 240 grados / Saturación (S): 100% / Luminosidad (L): 4.9%
el opuesto de 240 es 60 en un círculo, luego convertir de nuevo a RGB da un valor de # 181800
fuente
Me gustaría ampliar la idea de @ ashes999 de crear un esquema.
Mi código va a ser lo más parecido a Python que pueda en la parte superior de mi cabeza (nunca he escrito una línea de Python en mi vida, pero he echado un vistazo a un libro una o dos veces).
Puede que no se vea particularmente bonito y no es realmente ideal para el código de producción, pero debería ser una solución rápida. No he probado el código, ya que no tengo exactamente un programa de "bolas rebotando alrededor de la pantalla" que pueda mutilar para probarlo.
Editar:
Al ver el código real en uso, la situación cambió de opinión, por lo que ofrezco esta solución.
Reemplace las líneas 276-284 con lo siguiente:
En esta nueva versión simplificada, un método de fábrica escupe las bolas y un método especializado genera los colores. El generador de color prueba el color generado aleatoriamente para ver si está dentro de un cierto rango de cercanía al color de fondo. Un color se considera demasiado cercano al color BG si sus tres canales de color están dentro de
leeway
cada lado de BG. Entonces, si el margen de maniobra es 0, solo se rechazarán los colores que coincidan exactamente con BG. Elegí 5 como predeterminado, que rechaza el color BG y los 5 colores a cada lado. Como el color BG es blanco, no estoy seguro de si rechazará el negro porque los dígitos se envuelven. Eso se puede evitar con el uso de las funciones min y max, pero las dejé por razones de brevedad.fuente
pygame
como biblioteca. Sin Lerp, solo conversiones básicas RGB-HSV-CYMK: pygame.org/docs/ref/color.htmllerp
función en mi respuesta es todo lo que hay que hacer. (Lerp significa 'interpolación lineal').print
diferente porque estás usando Python 3, y todavía estoy en Python 2. Y aún no estoy seguro de sipygame
fue portado a Py3. En pocas palabras: no te molestes :) La pregunta es sobre colores, no necesitas bolas reales rebotando :)Para un formato RGB, esto parece funcionar lo suficientemente bien y es trivial:
diversity_score = (abs (r1 - r2) + abs (g1 - g2) + abs (b1 - b2)) / 765.0
Esto le dará un puntaje entre 0.0 y 1.0. Cuanto más bajo, más difícil es distinguir dos colores.
Debería ser obvio, pero en aras de la exhaustividad: los valores r, g, b deben convertirse primero en un número de coma flotante, y se supone que su valor máximo es 255.
fuente