Как обработать альфу в ручной операции наложения "Наложение"?

Я играю с некоторой ручной обработкой изображений, и я воссоздаю стандартную смесь "наложения". Я смотрю макросы "Photoshop math" здесь:

http://www.nathanm.com/photoshop-blending-math/( Смотрите также здесь для более читаемой версии Overlay)

Оба исходных изображения в достаточно стандартном формате RGBA (8 бит каждый), как и пункт назначения. Когда оба изображения полностью непрозрачны (альфа равен 1,0), результат смешивается правильно, как и ожидалось:

Но если в моем "смешанном" слое (верхнем изображении) есть прозрачность, я немного озадачен тем, как правильно включить этот альфа в уравнение смешивания. Я ожидаю, что он будет работать так, что прозрачные пиксели в слое смешения не влияют на результат, непрозрачные пиксели в слое смешения делают наложение наложения как обычно, а полупрозрачные пиксели слоя смешения имеют некоторый масштабированный эффект на результат.

Может кто-нибудь объяснить мне смешанные уравнения или концепцию, стоящую за этим?

Бонусные баллы, если вы можете помочь мне сделать это так, чтобы полученное изображение имело правильно предварительно умноженную альфа (я думаю, что она вступает в игру только для пикселей, которые не являются непрозрачными в обоих слоях).

Спасибо!

// factor in blendLayerA, (1-blendLayerA) somehow?
resultR = ChannelBlend_Overlay(baseLayerR, blendLayerR); 
resultG = ChannelBlend_Overlay(baseLayerG, blendLayerG);
resultB = ChannelBlend_Overlay(baseLayerB, blendLayerB);
resultA = 1.0; // also, what should this be??

4 ответа

Решение

Просто предположение, но я бы попробовал

resultA = 1 - (1-baseAlpha) * (1-blendAlpha)

После смешивания основного цвета и смешанного цвета смешайте исходный базовый цвет и цвет, полученный в результате смешивания, используя альфа смешанного цвета:

vec4 baseColor = ...;
vec4 blendColor = ...;
vec4 blendedColor = blend(baseColor, blendColor);
vec4 fragmentColor = (1.0 - blendColor.a) * baseColor + blendColor.a * blendedColor;

Я использую это для "наложения" наложения непрозрачного основного цвета и наложения текстуры, которая имеет много (полупрозрачных) пикселей.

Фактически вы хотите подтянуть значения RGB к их среднему значению (например, 127 или 0,5 в цветах 0-1) по мере уменьшения их альфа-канала, а затем использовать стандартную альфа-композицию для выходного альфа-канала. Этот код немного сбивает с толку, потому что я передаю массив rgba, который может быть нескольких целочисленных типов (maxValDouble() возвращает максимальное значение типа T как двойное, а не максимальное значение двойного), в то время как DoubleColor всегда является плавающим -точечное значение цвета со значениями rgba в диапазоне от 0 до 1. Но этот код, похоже, работает и правильно смешивается:

      template<typename T> static inline void blendColorOverlay(T* rgba, DoubleColor overColor) {
    if (overColor.a == 0)
        return;
    
    double underAlpha = rgba[3]/maxValDouble<T>();
    double middleVal = maxValDouble<T>()/2.0;
    
    // pull vals towards medium grey as alpha decreases
    for (int k = 0; k < 3; k++) {
        rgba[k] = rgba[k]*underAlpha + middleVal*(1.0 - underAlpha);
        overColor[k] = overColor[k]*overColor[3] + .5*(1.0 - overColor[3]);
        }
    
    for (int k = 0; k < 3; k++) {
        if (rgba[k] <= middleVal)
            rgba[k] = (2 * rgba[k] * overColor[k]);
        else
            rgba[k] = maxValDouble<T>() - 2*(maxValDouble<T>() - rgba[k])*(1.0 - overColor[k]);
        }
    
    // standard output blended alpha
    rgba[3] = (overColor.a + underAlpha*(1.0 - overColor.a)) * maxValDouble<T>();
    }

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

Другие вопросы по тегам