Интерполяция цвета между 3 цветами in.NET
Я хотел бы плавно интерполировать цвет из цвета A (назовем его красным) в цвет C (назовем его зеленым), проходя через цвет B (назовем его желтым), на основе значения определенной переменной.
Если переменная = 100, я хочу чисто зеленые. Если переменная = 50, я хочу чистый желтый цвет. Если переменная = 0, я хочу чистый красный.
Я понимаю, что вы можете рассматривать каждый триплет RGB как координату в 3-мерном пространстве. То, что я ищу, - это быстрая и грязная линейка трюк интерполяции, который работает чисто с определенным макетом типа цвета .NET (отдельные значения для ARGB и т. д.).
2 ответов
во-первых, вы просите линейную интерполяцию, но вы не указываете, что цвет B живет на линии между цветом A и цветом C; это необходимо. Во-вторых, вы не указали, но я собираюсь сделать упрощающее предположение, что цвет B является средней точкой линии между цветом A и цветом C; следующий код легко изменить, если это не так. Наконец, я изменил ваше предположение, что параметр является целым числом от нуля до ста, чтобы быть двойным между нулем и единицей. Код легче писать и легче понимать в последнем случае, и все еще можно использовать с первым (разделите ваши входные данные на сто).
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);
}
}
как изменить это, если цвет B не является средней точкой между цветом A и цветом C? Самый простой способ заключается в следующем. Если параметр (то, что я называю "lambda
") составляет менее 0.5
, умножьте lambda
на два и возвращает интерполированный цвет между цветом A и цветом B. Если параметр больше 0.5
, умножьте lambda
на два и вычесть один (это карты [0.5, 1]
на [0, 1]
) и вернуть интерполированный цвет между цветом B и цветом C.
Если вам не нравится требование, чтобы цвет B жил на линии между цветом A и цветом C, то вы можете использовать именно ту модификацию, которую я только что описал, чтобы сделать кусочно-линейную интерполяцию между цветами.
наконец, вы не указали, хотите ли вы интерполировать так называемое альфа-значение ("A"в " ARGB"). Вышеуказанный код легко модифицируется, чтобы справиться с этой ситуацией. Добавьте еще один ComponentSelector
определяется как color => color.A
используйте InterpolateComponent
интерполировать это значение и использовать Color.FromArgb(int, int, int, int)
перегрузка Color.FromArgb
.
другой способ смешивания цветов с использованием гауссова распределения, как это (любое количество цветов для диапазона 0.0-1.0, чтобы увеличить смешивание увеличить значение 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);
}
дополнительная информация http://en.wikipedia.org/wiki/Normal_distribution
образец смешивания 3 цветов: