Предварительно умноженный альфа-композитинг - PullRequest
3 голосов
/ 01 февраля 2011

Я пытаюсь реализовать предварительно умноженное альфа-смешивание.На этой странице: Что такое смешивание цветов? , они объясняют стандартное альфа-смешивание, но не для предварительно умноженных значений.

Альфа-смешивание: (source × Blend.SourceAlpha) +(пункт назначения × Blend.InvSourceAlpha)

В соответствии с формулой это переводится так:

  a = ((srcA * srcA) >> 8) + ((tgtA * (255 - srcA)) >> 8);
  r = ((srcR * srcA) >> 8) + ((tgtR * (255 - srcA)) >> 8);
  g = ((srcG * srcA) >> 8) + ((tgtG * (255 - srcA)) >> 8);
  b = ((srcB * srcA) >> 8) + ((tgtB * (255 - srcA)) >> 8);

Это работает, очевидно ...

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

  a = ((srcA)) + ((tgtA * (255 - srcA)) >> 8);
  r = ((srcR)) + ((tgtR * (255 - srcA)) >> 8);
  g = ((srcG)) + ((tgtG * (255 - srcA)) >> 8);
  b = ((srcB)) + ((tgtB * (255 - srcA)) >> 8);

Так как это было предварительно умножено, я отбрасываю умножение в первом члене ... правильно!?Но результат находится между альфа-смешиванием и смешиванием добавок, склоняясь больше к добавкам.В конце это действительно не выглядит слишком смешанным.Это, вероятно, неправильно, так как должно выглядеть точно как классическое альфа-смешение;или это ожидаемое поведение?

Спасибо.

Ответы [ 4 ]

4 голосов
/ 26 июня 2011

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

например. Без предварительного умножения мы получаем это для данных исходного изображения:

srcA = origA
srcR = origR
srcG = origG
srcB = origB

И мы получаем это для результирующего изображения применительно к цели:

a = ((srcA * srcA) >> 8) + ((tgtA * (255 - srcA)) >> 8)
r = ((srcR * srcA) >> 8) + ((tgtR * (255 - srcA)) >> 8)
g = ((srcG * srcA) >> 8) + ((tgtG * (255 - srcA)) >> 8)
b = ((srcB * srcA) >> 8) + ((tgtB * (255 - srcA)) >> 8)

Расширяя это, мы получаем:

a = ((origA * origA) >> 8) + ((tgtA * (255 - origA)) >> 8)
r = ((origR * origA) >> 8) + ((tgtR * (255 - origA)) >> 8)
g = ((origG * origA) >> 8) + ((tgtG * (255 - origA)) >> 8)
b = ((origB * origA) >> 8) + ((tgtB * (255 - origA)) >> 8)

Никаких сюрпризов ...

Теперь для предварительно умноженных данных исходного изображения мы получаем:

srcA = (origA * origA) >> 8
srcR = (origR * origA) >> 8
srcG = (origG * origA) >> 8
srcB = (origB * origA) >> 8

Который применительно к цели:

a = (srcA >> 8) + ((tgtA * (255 - srcA)) >> 8);
r = (srcR >> 8) + ((tgtR * (255 - srcA)) >> 8);
g = (srcG >> 8) + ((tgtG * (255 - srcA)) >> 8);
b = (srcB >> 8) + ((tgtB * (255 - srcA)) >> 8);

Хорошо, мы знаем это, но если мы расширим это, вы увидите разницу:

a = (origA * origA) >> 8 + ((tgtA * (255 – ((origA * origA) >> 8))) >> 8);
r = (origR * origA) >> 8 + ((tgtR * (255 - ((origA * origA) >> 8))) >> 8);
g = (origG * origA) >> 8 + ((tgtG * (255 – ((origA * origA) >> 8))) >> 8);
b = (origB * origA) >> 8 + ((tgtB * (255 – ((origA * origA) >> 8))) >> 8);

Сравните это с расширением без умножения:

a = ((origA * origA) >> 8) + ((tgtA * (255 - origA)) >> 8)
r = ((origR * origA) >> 8) + ((tgtR * (255 - origA)) >> 8)
g = ((origG * origA) >> 8) + ((tgtG * (255 - origA)) >> 8)
b = ((origB * origA) >> 8) + ((tgtB * (255 - origA)) >> 8)

И сразу же вы можете видеть, что мы возводим в квадрат значение origA при применении его к цели, это означает, что большее количество цели достигнет результирующих значений цвета.

Если вы возводите в квадрат, я хочу, чтобы больше цели прошло.

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

Надеюсь, это прояснит ситуацию.

2 голосов
/ 02 февраля 2011

Проблема, с которой вы столкнулись, зависит от того, предварительно ли вы умножили свое альфа-значение источника как часть предварительного умножения.Если вы это сделали, то srcA, который вы используете при умножении цели, является квадратом реального альфа-источника, поэтому вам нужно взять квадратный корень для этого вычисления:предварительно умноженный на себя (что, я думаю, более вероятно), вам нужно будет умножить на себя, чтобы получить тот же результат, что и рабочий:

1 голос
/ 02 февраля 2011

Дикая догадка: варьируете ли вы количество смешивания (srcA)? Если это так, вы должны пересчитать свои предварительно умноженные альфа-значения в растровом изображении. Если вы этого не сделаете, вы получите дополнительный эффект, который может быть тем, что вы описываете.

0 голосов
/ 02 февраля 2011

После многих попыток вот что я придумал:

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

В лучших документах, которые я обнаружил, говорится об исчезновении уродливых границ при предварительном умножении: http://www.td -grafik.de / ext / xfrog / alpha / index.html и http://blogs.msdn.com/b/shawnhar/archive/2010/04/08/premultiplied-alpha-in-xna-game-studio-4-0.aspx

Что ж, обычное альфа-смешение на самом деле не было эталоном для сравнения, я думаю, что я сейчас нахожусь, так как оно выглядит лучше, чем нормальное альфа-смешение.* Но если честно, я не совсем понимаю 100% этого, (похоже) это работает;еще одна загадка ...

Вот что заставляет меня думать, что все в порядке;

Слева: альфа-смешение;Справа: предварительно умножено

Спасибо всем за помощь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...