Interpolación de color entre 3 colores en.NET
colors interpolation (2)
En primer lugar, solicita la interpolación lineal, pero no especifica que el color B viva en la línea entre el color A y el color C; esto es necesario. En segundo lugar, no especificó, pero voy a hacer una suposición simplificadora de que el color B es el punto medio de la línea entre el color A y el color C; el siguiente código se modifica fácilmente si esto no es cierto. Por último, cambié tu suposición de que el parámetro es un número entero entre cero y cien para ser un doble entre cero y uno. El código es más fácil de escribir y más fácil de entender en el último caso, y aún puede usarse con el primero (divida sus entradas entre cien).
class ColorInterpolator {
delegate byte ComponentSelector(Color color);
static ComponentSelector _redSelector = color => color.R;
static ComponentSelector _greenSelector = color => color.G;
static ComponentSelector _blueSelector = color => color.B;
public static Color InterpolateBetween(
Color endPoint1,
Color endPoint2,
double lambda) {
if (lambda < 0 || lambda > 1) {
throw new ArgumentOutOfRangeException("lambda");
}
Color color = Color.FromRgb(
InterpolateComponent(endPoint1, endPoint2, lambda, _redSelector),
InterpolateComponent(endPoint1, endPoint2, lambda, _greenSelector),
InterpolateComponent(endPoint1, endPoint2, lambda, _blueSelector)
);
return color;
}
static byte InterpolateComponent(
Color endPoint1,
Color endPoint2,
double lambda,
ComponentSelector selector) {
return (byte)(selector(endPoint1)
+ (selector(endPoint2) - selector(endPoint1)) * lambda);
}
}
¿Cómo se modifica esto si el color B no es el punto medio entre el color A y el color C? La forma más fácil es la siguiente. Si el parámetro (lo que llamo " lambda
") es menor que 0.5
, multiplique lambda
por dos y devuelva el color interpolado entre el color A y el color B. Si el parámetro es mayor que 0.5
, multiplique lambda
por dos y reste uno (este mapa [0.5, 1]
en [0, 1]
) y devuelve el color interpolado entre el color B y el color C.
Si no te gusta el requisito de que el color B viva en la línea entre el color A y el color C, entonces puedes usar exactamente la modificación que acabo de describir para hacer una interpolación lineal por partes entre los colores.
Finalmente, no especificó si quiere interpolar el llamado valor alfa (la ''A'' en "ARGB"). El código anterior se modifica fácilmente para manejar esta situación también. Agregue un ComponentSelector
más definido como color => color.A
, use InterpolateComponent
para interpolar este valor y use la Color.FromArgb(int, int, int, int)
de Color.FromArgb
.
Me gustaría interpolar sin problemas el color del Color A (llamémoslo rojo) al Color C (llamémoslo verde) pasando por el color B (llamémoslo amarillo), según el valor de una cierta variable.
Si la variable = 100, quiero verde puro. Si la variable = 50, quiero amarillo puro. Si la variable = 0, quiero rojo puro.
Entiendo que puede tratar cada triplete RGB como una coordenada en el espacio tridimensional. Lo que estoy buscando es un truco de interpolación lineal rápido y sucio que funcione limpiamente con el diseño específico del tipo de color .NET (valores separados para ARGB, etc.).
Otra forma de mezclar colores usando distribución gaussiana como esta (cualquier cantidad de colores para un rango de 0.0 - 1.0, para aumentar la mezcla aumenta el valor de sigma_2)
public static Color InterpolateColor(Color[] colors, double x)
{
double r = 0.0, g = 0.0, b = 0.0;
double total = 0.0;
double step = 1.0 / (double)(colors.Length - 1);
double mu = 0.0;
double sigma_2 = 0.035;
foreach (Color color in colors)
{
total += Math.Exp(-(x - mu) * (x - mu) / (2.0 * sigma_2)) / Math.Sqrt(2.0 * Math.PI * sigma_2);
mu += step;
}
mu = 0.0;
foreach(Color color in colors)
{
double percent = Math.Exp(-(x - mu) * (x - mu) / (2.0 * sigma_2)) / Math.Sqrt(2.0 * Math.PI * sigma_2);
mu += step;
r += color.R * percent / total;
g += color.G * percent / total;
b += color.B * percent / total;
}
return Color.FromArgb(255, (int)r, (int)g, (int)b);
}
Más información http://en.wikipedia.org/wiki/Normal_distribution
Muestra de mezcla de 3 colores: