2008-09-26 18 views
63

motivaciónprogramación un color

Me gustaría encontrar una manera de tomar un color arbitrario y la ilumina algunas cortinas, de modo que pueda crear mediante programación un buen gradiente desde el color a un encendedor versión. El degradado se usará como fondo en una UI.

Posibilidad 1

Obviamente sólo puedo dividir los valores RGB y aumentar de forma individual por una cierta cantidad. ¿Es esto realmente lo que quiero?

Posibilidad 2

Mi segundo pensamiento fue para convertir el RGB a HSV/HSB/HSL (Tono, Saturación, Valor/brillo/luminosidad), aumentar el brillo un poco, disminuir la saturación de un bit, y luego convertirlo de nuevo a RGB. ¿Esto tendrá el efecto deseado en general?

+0

¿Qué lenguaje de programación? – Horcrux7

+36

El lenguaje de programación no tiene importancia. –

Respuesta

37

Me gustaría ir por la segunda opción. En términos generales, el espacio RGB no es realmente bueno para hacer la manipulación del color (crear transición de un color a otro, aclarar/oscurecer un color, etc.). A continuación se presentan dos sitios que he encontrado con una búsqueda rápida para convertir desde/hacia RGB a/desde HSL:

+0

primer enlace está roto – akira

+0

Gracias, lo actualicé. –

+8

El segundo enlace está roto. – RenniePet

0

Hubiera intentado primero con el número 1, pero el # 2 parece bastante bueno. Intente hacerlo usted mismo y vea si está satisfecho con los resultados, parece que le tomará tal vez 10 minutos para preparar una prueba.

3

Una pregunta muy similar, con respuestas útiles, se le pidió con anterioridad: How do I determine darker or lighter color variant of a given color?

Respuesta corta: multiplicar los valores RGB por una constante si sólo necesitas "lo suficientemente bueno", se traducen en VHS si necesita precisión.

+0

Se votó a favor por la referencia a una pregunta similar, pero estoy en desacuerdo con el asesoramiento de RGB: vaya a HSV. –

22

En C#:

public static Color Lighten(Color inColor, double inAmount) 
{ 
    return Color.FromArgb(
    inColor.A, 
    (int) Math.Min(255, inColor.R + 255 * inAmount), 
    (int) Math.Min(255, inColor.G + 255 * inAmount), 
    (int) Math.Min(255, inColor.B + 255 * inAmount)); 
} 

He utilizado este por todo el lugar.

+0

Muy útil y simple. Utilizándolo en una aplicación VB.NET ahora. – Kezzer

+0

Consulte http://stackoverflow.com/questions/801406/c-create-a-lighter-darker-color-based-on-a-system-color –

2

Convirtiendo a HS (LVB), aumentar el brillo y volver a convertir a RGB es la única manera de aclarar el color sin afectar los valores de tono y saturación (es decir, aclarar el color sin cambiarlo de ninguna otra manera))

8

Convierte a RGB e interpola linealmente entre el color original y el color de destino (a menudo blanco). Por lo tanto, si quieres 16 tonos entre dos colores, que hace:


for(i = 0; i < 16; i++) 
{ 
    colors[i].R = start.R + (i * (end.R - start.R))/15; 
    colors[i].G = start.G + (i * (end.G - start.G))/15; 
    colors[i].B = start.B + (i * (end.B - start.B))/15; 
} 
+0

En la mayoría de los casos, solo se necesita el color de inicio y final ya que los gráficos la biblioteca de elección probablemente haya incorporado capacidades gradientes. –

+0

Y al usar la división de enteros, elimina la necesidad de redondos (piso). Inteligente. –

2

He hecho esto en ambos sentidos - se obtiene resultados mucho mejores con Posibilidad 2.

Cualquier algoritmo simple se construye para la Posibilidad 1 probablemente solo funcionará bien para un rango limitado de saturaciones iniciales.

Desea examinar Poss 1 si (1) puede restringir los colores y los brillos utilizados, y (2) está realizando el cálculo mucho en una representación.

Generando el fondo de una interfaz de usuario no tendrá muchos cálculos de sombreado, así que sugieren Pos 2.

-Al.

0

Técnicamente, no creo que ninguno sea correcto, pero creo que desea una variante de la opción n. ° 2. El problema es que con RGB 990000 y "aligerar", realmente solo se agregaría al canal Rojo (Valor, Brillo, Luminosidad) hasta llegar a FF. Después de eso (rojo fijo), estaría tomando la saturación para llegar hasta el blanco sólido.

Las conversiones se vuelven molestas, especialmente porque no se puede ir directo a RGB y Lab, pero creo que realmente se desea separar los valores de crominancia y luminancia, y simplemente modificar la luminancia para lograr realmente lo que se desea.

46

Como Wedge said, quiere multiplicar para hacer las cosas más brillantes, pero eso solo funciona hasta que uno de los colores se satura (es decir, alcanza 255 o más). En ese punto, puede fijar los valores a 255, pero estará sutilmente cambiando el tono a medida que se aclare. Para mantener el tono, desea mantener la relación de (medio-bajo)/(más alto-más bajo).

Aquí hay dos funciones en Python. El primero implementa el enfoque ingenuo que simplemente fija los valores RGB en 255 si pasan de largo. El segundo redistribuye los valores en exceso para mantener el matiz intacto.

def clamp_rgb(r, g, b): 
    return min(255, int(r)), min(255, int(g)), min(255, int(b)) 

def redistribute_rgb(r, g, b): 
    threshold = 255.999 
    m = max(r, g, b) 
    if m <= threshold: 
     return int(r), int(g), int(b) 
    total = r + g + b 
    if total >= 3 * threshold: 
     return int(threshold), int(threshold), int(threshold) 
    x = (3 * threshold - total)/(3 * m - total) 
    gray = threshold - x * m 
    return int(gray + x * r), int(gray + x * g), int(gray + x * b) 

I creó un gradiente empezando con el valor RGB (224,128,0) y multiplicándolo por 1,0, 1,1, 1,2, etc. hasta 2,0. La mitad superior es el resultado utilizando clamp_rgb y la mitad inferior es el resultado con redistribute_rgb. Creo que es fácil ver que la redistribución de los desbordamientos da un resultado mucho mejor, sin tener que abandonar el espacio de color RGB.

Lightness gradient with clamping (top) and redistribution (bottom)

Para la comparación, aquí es el mismo gradiente en los espacios de color HLS y HSV, tal como se aplica por el módulo de Python colorsys. Solo se modificó el componente L y se realizó la fijación en los valores RGB resultantes. Los resultados son similares, pero requieren conversiones de espacio de color para cada píxel.

Lightness gradient with HLS (top) and HSV (bottom)

+0

Después de votar esto, me di cuenta de que esto es excesivo. Todo lo que necesita hacer es mezclar alfa con blanco con cierta opacidad (es decir, interpolar los componentes de color en la misma fracción hacia 255). – Andy

+0

@Andy eche un vistazo a la muestra. Los primeros dos cuadros de la izquierda no tienen ningún blanco, están completamente saturados. Hubiera sido más si hubiera empezado con un color más oscuro. –

+0

Ah, ya veo, por lo que su código tiene la misma discontinuidad lineal que el espacio de color HLS. Puedo ver cómo eso haría un gradiente más rico. Ya que solo quería aclarar un color para resaltar el aspecto en lugar de hacer un degradado, esperaba un método más simple – Andy

11

en System.Windows.Forms espacio de nombres tiene métodos estáticos Luz y Oscuridad:

public static Color Dark(Color baseColor, float percOfDarkDark); 

Estos los métodos usan la implementación privada de HLSColor. Ojalá esta estructura fuera pública y en System.Drawing.

Alternativamente, puede utilizar GetHue, GetSaturation, GetBrightness en Color struct para obtener componentes HSB. Lamentablemente, no encontré la conversión inversa.

1

SI desea producir un fundido de degradado, le sugiero la siguiente optimización: en lugar de hacer RGB-> HSB-> RGB para cada color individual, solo debe calcular el color de destino.Una vez que conoces el objetivo RGB, puedes simplemente calcular los valores intermedios en el espacio RGB sin tener que convertir de ida y vuelta. Ya sea que usted calcule una transición de uso lineal algún tipo de curva depende de usted.

0

Tengo un blog post que muestra cómo hacer esto en Delphi. Es bastante simple porque las funciones ColorRGBToHSL y ColorHLSToRGB son parte de la biblioteca estándar.

6

Con el fin de conseguir un encendedor o una versión más oscura de un color determinado que debiera modificar su brillo Puede hacerlo fácilmente incluso sin convertir su color a color HSL o HSB. Por ejemplo, para hacer un color más claro se puede utilizar el siguiente código:

float correctionFactor = 0.5f; 
float red = (255 - color.R) * correctionFactor + color.R; 
float green = (255 - color.G) * correctionFactor + color.G; 
float blue = (255 - color.B) * correctionFactor + color.B; 
Color lighterColor = Color.FromArgb(color.A, (int)red, (int)green, (int)blue); 

Si necesita más detalles, read the full story on my blog.

+0

+1, método de Nicks, la forma correcta. Pero aún puede omitir el elenco hacia y desde el flotante al hacerlo como Adam Rosenfield, dividiendo el factor de corrección en pasos e índice, lo que también le da dos valores comprensibles en lugar de un número abstracto entre 0.0 y 1.0. p.ej. su factor de corrección es el i/15 de Rosenfield, mientras que supone el blanco como color objetivo. –

3

que utilizan la respuesta de Andrés y de la respuesta de la marca para hacer this (a partir de 1/2013 ninguna entrada de gama para los siguientes).

function calcLightness(l, r, g, b) { 
    var tmp_r = r; 
    var tmp_g = g; 
    var tmp_b = b; 

    tmp_r = (255 - r) * l + r; 
    tmp_g = (255 - g) * l + g; 
    tmp_b = (255 - b) * l + b; 

    if (tmp_r > 255 || tmp_g > 255 || tmp_b > 255) 
     return { r: r, g: g, b: b }; 
    else 
     return { r:parseInt(tmp_r), g:parseInt(tmp_g), b:parseInt(tmp_b) } 
} 

enter image description here

1

pretender que mezcla alfa a blanco:

oneMinus = 1.0 - amount 
r = amount + oneMinus * r 
g = amount + oneMinus * g 
b = amount + oneMinus * b 

donde amount es de 0 a 1, con 0 devolver el color original y 1 volver blanco.

Es posible que desee combinar con cualquiera que sea el color de fondo es si usted está aligerando para mostrar algo desactivado:

oneMinus = 1.0 - amount 
r = amount * dest_r + oneMinus * r 
g = amount * dest_g + oneMinus * g 
b = amount * dest_b + oneMinus * b 

donde (dest_r, dest_g, dest_b) es el color se mezclan para y amount es de 0 a 1, con cero regresar (r, g, b) y 1 que devuelve (dest.r, dest.g, dest.b)

+0

Creo que esta debería ser la mejor respuesta. Del mismo modo, para oscurecerlo, solo se mezcla alfa a negro (es decir, se multiplican los componentes por una "cantidad <1"). – Andy

1

No he encontrado esta pregunta hasta que se convirtió en una pregunta relacionada con mi pregunta original.

Sin embargo, utilizando la información de estas excelentes respuestas. Monté una buena función de dos forro para esto:

Programmatically Lighten or Darken a hex color (or rgb, and blend colors)

Es una versión del método 1. Pero con más de saturación tenido en cuenta. Como dijo Keith en su respuesta anterior; use Lerp para resolver el mismo problema que Mark mencionó, pero sin redistribución. Los resultados de shadeColor2 deberían estar mucho más cerca de hacerlo de la manera correcta con HSL, pero sin la sobrecarga.

0

He aquí un ejemplo de aligerar un color RGB en Python:

def lighten(hex, amount): 
    """ Lighten an RGB color by an amount (between 0 and 1), 

    e.g. lighten('#4290e5', .5) = #C1FFFF 
    """ 
    hex = hex.replace('#','') 
    red = min(255, int(hex[0:2], 16) + 255 * amount) 
    green = min(255, int(hex[2:4], 16) + 255 * amount) 
    blue = min(255, int(hex[4:6], 16) + 255 * amount) 
    return "#%X%X%X" % (int(red), int(green), int(blue)) 
Cuestiones relacionadas