Pregunta

Motivación

Me gustaría encontrar una manera de tomar un color arbitrario y aclararlo unos pocos tonos, para que pueda crear un gradiente agradable desde un color hasta una versión más clara. El degradado se utilizará como fondo en una interfaz de usuario.

Posibilidad 1

Obviamente, puedo dividir los valores RGB y aumentarlos individualmente en cierta cantidad. ¿Es esto realmente lo que quiero?

Posibilidad 2

Mi segundo pensamiento fue convertir el RGB a HSV / HSB / HSL (Matiz, Saturación, Valor / Brillo / Luminosidad), aumentar un poco el brillo, disminuir un poco la saturación y luego volver a convertirlo en RGB. ¿Tendrá esto el efecto deseado en general?

¿Fue útil?

Solución

Iría por la segunda opción. En general, el espacio RGB no es realmente bueno para manipular el color (crear una transición de un color a otro, aclarar / oscurecer un color, etc.). A continuación se muestran dos sitios que he encontrado con una búsqueda rápida para convertir de / a RGB a / desde HSL:

Otros consejos

Como Wedge dijo , quieres multiplicar para hacer las cosas más brillantes, pero eso solo funciona hasta que uno de los colores se satura (es decir, llega a 255 o más). En ese momento, puede limitar los valores a 255, pero cambiará sutilmente el tono a medida que se aclara. Para mantener el tono, desea mantener la proporción de (medio-más bajo) / (más alto-más bajo).

Aquí hay dos funciones en Python. El primero implementa el enfoque ingenuo que solo limita los valores RGB a 255 si se superan. El segundo redistribuye los valores en exceso para mantener el tono 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)

Creé un gradiente comenzando 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 usando 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.

Gradiente de luminosidad con sujeción (arriba) y redistribución (abajo)

A modo de comparación, aquí está el mismo gradiente en los espacios de color HLS y HSV, según lo implementado por Módulo 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.

Gradiente de luminosidad con HLS (arriba) y HSV (abajo)

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 usado esto en todas partes.

La clase ControlPaint en el espacio de nombres System.Windows.Forms tiene métodos estáticos claros y oscuros:

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

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

Como alternativa, puede usar GetHue, GetSaturation, GetBrightness en Color struct para obtener componentes HSB. Desafortunadamente, no encontré la conversión inversa.

Conviértalo a RGB e interpole linealmente entre el color original y el color objetivo (a menudo blanco). Entonces, si quieres 16 tonos entre dos colores, lo haces:


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

Para obtener una versión más clara o más oscura de un color determinado, debes modificar su brillo. Puede hacerlo fácilmente incluso sin convertir su color a HSL o HSB. Por ejemplo, para hacer un color más claro puede usar 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, lea la historia completa en mi blog .

Una pregunta muy similar, con respuestas útiles, se hizo anteriormente: ¿Cómo puedo determinar más oscuro o ¿Variante de color más claro de un color dado?

Respuesta corta: multiplique los valores RGB por una constante si solo necesita " lo suficientemente bueno " ;, tradúzcalo a HSV si necesita precisión.

Usé la respuesta de Andrew y la respuesta de Mark para hacer esto (a partir del 1/2013 sin rango entrada para ff).

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

ingrese la descripción de la imagen aquí

La conversión a HS (LVB), aumentar el brillo y luego volver a RGB es la única forma de aclarar el color de manera confiable sin afectar los valores de matiz y saturación (es decir, iluminar el color sin cambiarlo de ninguna otra forma) .

He hecho esto en ambos sentidos: obtienes resultados mucho mejores con la posibilidad 2.

Cualquier algoritmo simple que construyas para la Posibilidad 1 probablemente funcionará bien solo para un rango limitado de saturaciones de inicio.

Desearía buscar en Pos. 1 si (1) puede restringir los colores y el brillo utilizados, y (2) está realizando mucho el cálculo en una representación.

La generación del fondo para una interfaz de usuario no requerirá muchos cálculos de sombreado, por lo que sugiero Poss 2.

-Al.

Si desea producir un degradado gradual, sugeriría la siguiente optimización: En lugar de hacer RGB- > HSB- > RGB para cada color individual, solo debe calcular el color objetivo. Una vez que conozca el RGB objetivo, simplemente puede calcular los valores intermedios en el espacio RGB sin tener que convertirlos de un lado a otro. Si usted calcula una transición lineal de uso, algún tipo de curva depende de usted.

Método 1: Convierta RGB a HSL, ajuste HSL, vuelva a convertir a RGB.

Método 2: Lerp los valores de color RGB - http: //en.wikipedia.org/wiki/Lerp_(computing)

Consulte mi respuesta a esta pregunta similar para una implementación de C # del método 2.

Haz de cuenta que alfa se combinó con blanco:

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

donde cantidad es de 0 a 1, con 0 devolviendo el color original y 1 regresando blanco.

Es posible que desee combinar con cualquier color de fondo si se está iluminando 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 que se está mezclando y la cantidad de es de 0 a 1, con cero devuelto (r, g, b) y 1 devolviendo (dest.r, dest.g, dest.b)

No encontré esta pregunta hasta que se convirtió en una pregunta relacionada con mi pregunta original.

Sin embargo, utilizando el conocimiento de estas grandes respuestas. Reuní una buena función de dos líneas para esto:

. y mezclar colores)

Es una versión del método 1. Pero teniendo en cuenta la saturación excesiva. 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 forma correcta con HSL, pero sin la sobrecarga.

Un poco tarde para la fiesta, pero si usa javascript o nodejs , puede usar tinycolor library , y manipula el color de la forma que quieras:

tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d" 

Habría intentado el número # 1 primero, pero el # 2 suena bastante bien. Trate de hacerlo usted mismo y vea si está satisfecho con los resultados, parece que le llevará aproximadamente 10 minutos preparar una prueba.

Técnicamente, tampoco creo que sea correcto, pero creo que quieres una variante de la opción # 2. El problema es que tomó RGB 990000 y " aligeramiento " realmente solo se agregaría al canal Rojo (Valor, Brillo, Luminosidad) hasta que llegara a FF. Después de eso (rojo sólido), estaría eliminando la saturación para llegar hasta el blanco sólido.

Las conversiones se vuelven molestas, especialmente porque no puedes ir directamente desde y hacia RGB y Lab, pero creo que realmente quieres separar los valores de crominancia y luminancia, y solo modificar la luminancia para lograr realmente lo que quieres.

Encontrará código para convertir entre espacios de color en color -tools ruby ??library

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

Aquí hay un ejemplo de aclarar 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))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top