Как перейти между двумя изображениями с помощью карты перехода в градациях серого

Представьте, что у вас есть два изображения A и B и третье изображение в градациях серого T. A и B содержат что угодно, но давайте предположим, что это две сцены из игры.

Теперь предположим, что T содержит ромбовидный градиент. Будучи оттенками серого, он переходит от черного снаружи к белому внутри.

Со временем, давайте предположим, что 256 без дополнительной обработки «тиков» для соответствия оттенкам серого, A должен перейти в B, создавая эффект ромбовидного стирания. Если бы T вместо этого содержал сетку меньших прямоугольных градиентов, это было бы так, как если бы каждая часть изображения сама по себе делала прямоугольное вытеснение.

Вы можете узнать эту концепцию, если вы когда-либо работали с RPG Maker или большинством движков визуальных новелл.

Вопрос, конечно, как это делается. Я знаю, что это включает попиксельное смешивание между A и B, но это все, что у меня есть.

В качестве дополнительного бонуса, как насчет мягких краев?

А теперь вывод

Последний эксперимент, основанный на коде eJames

http://helmet.kafuka.org/TransitionsSample.png


person Kawa    schedule 08.11.2009    source источник


Ответы (2)


Значения в градациях серого на изображении T представляют сдвиги во времени. Ваш эффект стирания будет работать в основном следующим образом для каждого пикселя:

for (timeIndex from 0 to 255)
{
    for (each pixel)
    {
        if (timeIndex < T.valueOf[pixel])
        {
            compositeImage.colorOf[pixel] = A.colorOf[pixel];
        }
        else
        {
            compositeImage.colorOf[pixel] = B.colorOf[pixel];
        }
    }
}

Для иллюстрации представьте, что происходит при нескольких значениях timeIndex:

  1. timeIndex == 0 (0%): Это самое начало перехода. В этот момент большинство пикселей в составном изображении будут пикселями изображения A, за исключением случаев, когда соответствующий пиксель в T полностью черный. В этих случаях пиксели составного изображения будут пикселями изображения B.

  2. timeIndex == 63 (25%): к этому моменту больше пикселей из изображения B превратилось в составное изображение. Каждый пиксель, в котором значение T меньше 25% белого, будет взят из изображения B, а остальные по-прежнему будут изображением A.

  3. timeIndex == 255 (100%): в этот момент каждый пиксель в T будет отрицать условное выражение, поэтому все пиксели в составном изображении будут пикселями изображения B.

Чтобы «сгладить» переход, можно сделать следующее:

for (timeIndex from 0 to (255 + fadeTime))
{
    for (each pixel)
    {
        blendingRatio = edgeFunction(timeIndex, T.valueOf[pixel], fadeTime);
        compositeImage.colorOf[pixel] =
                    (1.0 - blendingRatio) * A.colorOf[pixel] + 
                    blendingRatio * B.colorOf[pixel];
    }
}

Выбор edgeFunction за вами. Этот производит линейный переход от A к B:

float edgeFunction(value, threshold, duration)
{
    if (value < threshold) { return 0.0; }
    if (value >= (threshold + duration)) { return 1.0; }

    // simple linear transition:
    return (value - threshold)/duration;
}
person e.James    schedule 08.11.2009
comment
Поздравляем! Предварительное вычисление коэффициентов смешивания и использование прямой манипуляции с растровыми изображениями сделали ваш метод достаточно быстрым. - person Kawa; 09.11.2009
comment
И спасибо за публикацию вашего окончательного кода. Приятно видеть, что ответ применяется на практике, и теперь другие люди могут учиться на улучшениях, которые вы сделали. Ваше здоровье! - person e.James; 09.11.2009

Я бы сказал, что вы начинаете с изображения A, затем на каждом шаге I вы используете пиксели изображения A для каждой позиции, где T меньше, чем I, и пиксели изображения B в противном случае.

Для мягкого края вы можете определить другой параметр d и вычислить ваши пиксели P следующим образом:

Для каждой точки (x,y) вы выбираете один из следующих трех вариантов:

  • I ‹ T(x,y) - d, то точка равна точке A
  • T(x,y) - d ‹= I ‹ T(x,y) + d, тогда пусть z = I - (T(x,y) -d) и точка равна A(x,y)(1 -z/(2d)) + B(x,y)(z/(2d))
  • I ‹ T(x,y) + d, то точка равна точке B

Это создает линейное ребро, конечно, вы можете выбирать между произвольным количеством функций для ребра.

person Jens Schauder    schedule 08.11.2009