algorithm - que - Algoritmo de mezcla de colores aditiva para valores RGB
rgb definicion (8)
Estoy buscando un algoritmo para hacer mezclas de colores aditivos para valores RGB.
¿Es tan simple como agregar los valores RGB juntos a un máximo de 256?
(r1, g1, b1) + (r2, g2, b2) =
(min(r1+r2, 256), min(g1+g2, 256), min(b1+b2, 256))
Función Javascript para combinar colores rgba
c1, c2 y resultado - JSON es como c1 = {r: 0.5, g: 1, b: 0, a: 0.33}
var rgbaSum = function(c1, c2){
var a = c1.a + c2.a*(1-c1.a);
return {
r: (c1.r * c1.a + c2.r * c2.a * (1 - c1.a)) / a,
g: (c1.g * c1.a + c2.g * c2.a * (1 - c1.a)) / a,
b: (c1.b * c1.a + c2.b * c2.a * (1 - c1.a)) / a,
a: a
}
}
Aquí hay un dominio público de clase c ++ altamente optimizado e independiente, con punto flotante y dos mecanismos de fusión de 8 bits optimizados de forma diferente en formatos de función y macro, así como una discusión técnica tanto del problema en cuestión y cómo, como de la importancia de, la optimización de este problema:
Dato curioso: los valores RGB de la computadora se derivan de la raíz cuadrada del flujo de fotones. Entonces, como una función general, tus cálculos deberían tener eso en cuenta. La función general para esto para un canal dado es:
blendColorValue(a, b, t)
return sqrt((1 - t) * a^2 + t * b^2)
Donde a y b son los colores para mezclar, y t es un número de 0-1 que representa el punto en la mezcla que desea entre a y b.
El canal alfa es diferente; no representa la intensidad de los fotones, solo el porcentaje de fondo que debería mostrarse; entonces cuando se mezclan valores alfa, el promedio lineal es suficiente:
blendAlphaValue(a, b, t)
return (1-t)*a + t*b;
Por lo tanto, para manejar la mezcla de dos colores, usando esas dos funciones, el siguiente pseudocódigo debería serle útil:
blendColors(c1, c2, t)
ret
[r, g, b].each n ->
ret[n] = blendColorValue(c1[n], c2[n], t)
ret.alpha = blendAlphaValue(c1.alpha, c2.alpha, t)
return ret
A propósito, anhelo un lenguaje de programación y teclado que permita representar matemáticamente (o más) matemáticamente (el carácter unicode superpuesto de combinación no funciona para superíndices, símbolos y una gran variedad de otros caracteres) e interpretarlo correctamente. sqrt ((1-t) * pow (a, 2) + t * pow (b, 2)) simplemente no se lee como limpio.
Depende de lo que desee, y puede ayudar a ver cuáles son los resultados de diferentes métodos.
Si tu quieres
Red + Black = Red Red + Green = Yellow Red + Green + Blue = White Red + White = White Black + White = White
a continuación, agregue con una abrazadera funciona (por ejemplo, min(r1 + r2, 255)
) Esto es más como el modelo de luz que ha mencionado.
Si tu quieres
Red + Black = Dark Red Red + Green = Dark Yellow Red + Green + Blue = Dark Gray Red + White = Pink Black + White = Gray
entonces necesitarás promediar los valores (p. ej., (r1 + r2) / 2
). Esto funciona mejor para aclarar / oscurecer colores y crear degradados.
Para mezclar usando canales alfa, puede usar estas fórmulas:
r = new Color();
r.A = 1 - (1 - fg.A) * (1 - bg.A);
if (r.A < 1.0e-6) return r; // Fully transparent -- R,G,B not important
r.R = fg.R * fg.A / r.A + bg.R * bg.A * (1 - fg.A) / r.A;
r.G = fg.G * fg.A / r.A + bg.G * bg.A * (1 - fg.A) / r.A;
r.B = fg.B * fg.A / r.A + bg.B * bg.A * (1 - fg.A) / r.A;
fg
es el color de la pintura. bg
es el fondo. r
es el color resultante. 1.0e-6
es solo un número realmente pequeño, para compensar los errores de redondeo.
NOTA: Todas las variables utilizadas aquí están en el rango [0.0, 1.0]. Debe dividir o multiplicar por 255 si desea usar valores en el rango [0, 255].
Por ejemplo, 50% rojo encima 50% verde:
// background, 50% green
var bg = new Color { R = 0.00, G = 1.00, B = 0.00, A = 0.50 };
// paint, 50% red
var fg = new Color { R = 1.00, G = 0.00, B = 0.00, A = 0.50 };
// The result
var r = new Color();
r.A = 1 - (1 - fg.A) * (1 - bg.A); // 0.75
r.R = fg.R * fg.A / r.A + bg.R * bg.A * (1 - fg.A) / r.A; // 0.67
r.G = fg.G * fg.A / r.A + bg.G * bg.A * (1 - fg.A) / r.A; // 0.33
r.B = fg.B * fg.A / r.A + bg.B * bg.A * (1 - fg.A) / r.A; // 0.00
El color resultante es: (0.67, 0.33, 0.00, 0.75)
o 75% marrón (o naranja oscuro).
También puedes invertir estas fórmulas:
var bg = new Color();
if (1 - fg.A <= 1.0e-6) return null; // No result -- ''fg'' is fully opaque
if (r.A - fg.A < -1.0e-6) return null; // No result -- ''fg'' can''t make the result more transparent
if (r.A - fg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important
bg.A = 1 - (1 - r.A) / (1 - fg.A);
bg.R = (r.R * r.A - fg.R * fg.A) / (bg.A * (1 - fg.A));
bg.G = (r.G * r.A - fg.G * fg.A) / (bg.A * (1 - fg.A));
bg.B = (r.B * r.A - fg.B * fg.A) / (bg.A * (1 - fg.A));
o
var fg = new Color();
if (1 - bg.A <= 1.0e-6) return null; // No result -- ''bg'' is fully opaque
if (r.A - bg.A < -1.0e-6) return null; // No result -- ''bg'' can''t make the result more transparent
if (r.A - bg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important
fg.A = 1 - (1 - r.A) / (1 - bg.A);
fg.R = (r.R * r.A - bg.R * bg.A * (1 - fg.A)) / fg.A;
fg.G = (r.G * r.A - bg.G * bg.A * (1 - fg.A)) / fg.A;
fg.B = (r.B * r.A - bg.B * bg.A * (1 - fg.A)) / fg.A;
Las fórmulas calcularán que el fondo o el color de la pintura tendrían que ser para producir el color resultante dado.
Si su fondo es opaco, el resultado también sería opaco. El color de primer plano podría tomar un rango de valores con diferentes valores alfa. Para cada canal (rojo, verde y azul), debe verificar qué rango de alfas arroja valores válidos (0 - 1).
Pocos puntos:
- Creo que quieres usar min en lugar de max
- Creo que quieres usar 255 en lugar de 256
Esto dará:
(r1, g1, b1) + (r2, g2, b2) = (min (r1 + r2, 255), min (g1 + g2, 255), min (b1 + b2, 255))
Sin embargo, la forma "natural" de mezclar colores es usar el promedio, y luego no necesitas el mínimo:
(r1, g1, b1) + (r2, g2, b2) = ((r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2)
Si, es tan simple como eso. Otra opción es encontrar el promedio (para crear degradados).
Realmente solo depende del efecto que quieres lograr.
Sin embargo, cuando se agrega Alpha, se vuelve complicado. Hay una serie de métodos diferentes para combinar usando un alfa.
Un ejemplo de mezcla simple alfa: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
MEZCLA DE COLOR PYTHON A TRAVÉS DE LA ADICIÓN EN EL ESPACIO CMYK
Una forma posible de hacerlo es convertir primero los colores al formato CMYK , agregarlos allí y luego reconvertirlos a RGB.
Aquí hay un código de ejemplo en Python:
rgb_scale = 255
cmyk_scale = 100
def rgb_to_cmyk(self,r,g,b):
if (r == 0) and (g == 0) and (b == 0):
# black
return 0, 0, 0, cmyk_scale
# rgb [0,255] -> cmy [0,1]
c = 1 - r / float(rgb_scale)
m = 1 - g / float(rgb_scale)
y = 1 - b / float(rgb_scale)
# extract out k [0,1]
min_cmy = min(c, m, y)
c = (c - min_cmy)
m = (m - min_cmy)
y = (y - min_cmy)
k = min_cmy
# rescale to the range [0,cmyk_scale]
return c*cmyk_scale, m*cmyk_scale, y*cmyk_scale, k*cmyk_scale
def cmyk_to_rgb(self,c,m,y,k):
"""
"""
r = rgb_scale*(1.0-(c+k)/float(cmyk_scale))
g = rgb_scale*(1.0-(m+k)/float(cmyk_scale))
b = rgb_scale*(1.0-(y+k)/float(cmyk_scale))
return r,g,b
def ink_add_for_rgb(self,list_of_colours):
"""input: list of rgb, opacity (r,g,b,o) colours to be added, o acts as weights.
output (r,g,b)
"""
C = 0
M = 0
Y = 0
K = 0
for (r,g,b,o) in list_of_colours:
c,m,y,k = rgb_to_cmyk(r, g, b)
C+= o*c
M+=o*m
Y+=o*y
K+=o*k
return cmyk_to_rgb(C, M, Y, K)
El resultado para su pregunta sería (suponiendo una mezcla a la mitad de sus dos colores:
r_mix, g_mix, b_mix = ink_add_for_rgb([(r1,g1,b1,0.5),(r2,g2,b2,0.5)])
donde los 0.5 están ahí para decir que mezclamos el 50% del primer color con el 50% del segundo color.