Билинейная интерполяция цветовой схемы - PullRequest
2 голосов
/ 03 января 2012

В настоящее время я работаю над программой фрактального генератора Мандельброта на C #. Для схемы раскраски я использую линейную интерполяцию и массив в качестве справочной таблицы.

Проблема с линейной интерполяцией заключается в том, что я могу использовать только два цвета.

Я хотел бы использовать как минимум три цвета, и я искал алгоритм программирования билинейной интерполяции, но я не нашел ни одного хорошего.

Мне было интересно, есть ли у кого-нибудь из вас решение этой проблемы.

Вот мой код линейной интерполяции:

private void InitColors()
{
    int range = 255;
    lookup = new Color[range];
    Color from = Color.White;
    Color to = Color.Blue;
    int red;
    int green;
    int blue;

    for (int i = 0; i < range; i++)
    {
        red = ((from.R * (range - i)) + (to.R * i)) / range;
        green = ((from.G * (range - i)) + (to.G * i)) / range;
        blue = ((from.B * (range - i)) + (to.B * i)) / range;
        lookup[i] = Color.FromArgb(red, green, blue);
    }
}

РЕДАКТИРОВАТЬ: Возможно, есть более простая интерполяция, чем билинейная, чтобы получить градиент между более чем двумя цветами. Мне все равно, какой метод, если он выполняет свою работу: -)

Ответы [ 2 ]

2 голосов
/ 03 января 2012

То, что вы ищете, на самом деле не называется билинейной интерполяцией.Билинейная подразумевает двухмерную цветовую карту с использованием двух аргументов i и j в диапазоне 0-1 и смешивает четыре цвета с использованием этих двух значений i, j - т.е.

C = C_00 (1-i) (1-j) + C_10 * i * (1-j) + C_01 * (1-i) * j + C_11 * i * j

, где C_ij - угловые цвета.

Если я правильно вас понимаю, то вы действительно хотите иметь возможность создавать градиент, который включает в себя более одного цвета, но при этом остается одномерным, используя один параметр.Для этого существует множество методов.Простейшим из них является смешение от цвета A до цвета B в диапазоне от 0 до 0,5 и от B до C в диапазоне от 0,5 до 1,0.

Конечно, вы можете разделить на несколько цветов больше, чем просто 3 ...

Код для этого будет выглядеть примерно так:

private void InitColors( Color * colors, int n_colors)
{
    int range = 255;
    lookup = new Color[range];
    int red;
    int green;
    int blue;

    for (int i = 0; i < range; i++)
    {
        float f = float(i)/float(range);
        //Work out which interval we're in
        int interval = f*(n_colors);

        //Special case for the end point to prevent out-of-bounds access. 
        if(f>=1.0) { interval = n_colors-1; }

        //Work out how far into that interval we are
        float ff = f * (n_colors-1) - interval;

        int R = (colors[interval].R * (1-f) + colors[interval+1].R*f;
        int G = (colors[interval].G * (1-f) + colors[interval+1].G*f;
        int B = (colors[interval].B * (1-f) + colors[interval+1].B*f;

        lookup[i] = Color.FromArgb(R, G, B);
    }
}

Теперь есть параиз проблем с этим, которые вы, вероятно, не будете беспокоиться, но я упомяну на всякий случай:

  • Это не очень плавный переход цвета.Если вы хотите более плавного поведения, вам нужно использовать сплайн-подход (который технически является самой простой версией).Я бы посоветовал посмотреть на сплайны Каттмул-Рома для этого.

  • Цветовые переходы не очень однородны или хороши.Я бы посоветовал сделать вычисления в пространстве, отличном от RGB, и в конце преобразовать обратно в RGB.Для этого я бы рассмотрел Lab пробел (HSV - другой вариант, но тогда вам нужно беспокоиться о переносе в направлении H.)

Надеюсь, это поможет.

1 голос
/ 03 января 2012

Как предполагается в вашем коде, каждый цвет может быть представлен в виде вектора в евклидовом пространстве 3.

Таким образом, учитывая 3 произвольных цвета C1, C2 и C3, сначала найдите соответствующие векторы RGB v1, v2,v3, а затем построить треугольную область с вершиной на конце каждого вектора, взяв все «выпуклые комбинации» этих 3 векторов:

c1 * v1 + c2 * v2 + c3 * v3

, где c1, c2 и c3 - скалярные значения между 0и 1, и c1 + c2 + c3 = 1, и применяются обычные евклидовы правила сложения векторов (и скалярного умножения).

ПРИМЕЧАНИЕ: Это также работает для произвольного числа цветов,Для N цветов у вас есть N связанных векторов, и «выпуклые комбинации» этих векторов являются N-1-мерным «симплексом».Это все линейно и очень легко рассчитать.Но полученный таким образом цветовой градиент может быть эстетически не оптимальным - нелинейный метод может дать более красивый результат.

РЕДАКТИРОВАТЬ: Геометрически говоря, ваш «симплекс» с N вершинами не будетфактически N-1-мерный, если N> 3, потому что все ваши «векторы» живут в RGB-пространстве, которое является 3-мерным, и поэтому не может быть линейно независимым.Это означает, что в целом (для N> 3) в «симплексе» будет много точек с разными координатами, но с одинаковым видимым «цветом».

...