Как использовать предварительно умноженный во время свертки изображения для решения проблемы альфа-кровотечения? - PullRequest
13 голосов
/ 31 января 2011

Я пытаюсь применить размытое изображение к прозрачному изображению и получаю «темный ореол» по краям.

Джерри Хакстейбл кратко упомянул о проблеме , и очень хорошая демонстрация, показывающая, что проблема произошла:

enter image description here

Но я, по жизни моей, не могу понять, как " предварительно умноженная альфа"может решить проблему.Теперь для очень простого примера.у меня есть изображение 3х3, содержащее один красный и один зеленый пиксель:

enter image description here

На самом деле оставшиеся пиксели прозрачны:

enter image description here

Теперь мы применим Box Blur 3x3 к изображению.Для простоты мы рассчитаем только новое значение центрального пикселя.Способ размывания прямоугольника заключается в том, что, поскольку у нас есть квадрат из 9 позиций (3x3, называемый ядром), мы берем 1/9 каждого пикселя в ядре и складываем его:

enter image description here

Итак

finalRed =   1/9 * red1 + 1/9 * red2 + 1/9 * red3+ ... + 1/9 * red9
finalGreen = 1/9*green1 + 1/9*green2 + 1/9*green3+ ... + 1/9*green9
finalBlue =  1/9* blue1 + 1/9* blue2 + 1/9* blue3+ ... + 1/9* blue9
finalAlpha = 1/9*alpha1 + 1/9*alpha2 + 1/9*alpha3+ ... + 1/9*alpha9

В этом очень упрощенном примере вычисления становятся очень простыми:

finalRed =   1/9 * 255
finalGreen = 1/9 * 255
finalBlue =  0
finalAlpha = 1/9*255 + 1/9*255

Это дает мне окончательное значение цвета:

finalRed =   28
finalGreen = 28
finalBlue =  0
finalAlpha = 56 (22.2%)

enter image description here

Этот цвет слишком темный.Когда я выполняю размытие в 3px Box на том же изображении размером 3x3 пикселя в Photoshop, я получаю то, что ожидаю:

enter image description here

, что яснее при отображении на белом фоне:

enter image description here


На самом деле я выполняю размытие окна на растровом изображении, содержащем прозрачный текст, и текст приобретает контрольный темный цвет по краям:

enter image description here

Я начинаю с растрового изображения GDI + в формате PixelFormat32bppARGB


Как использовать «предварительно умноженную альфа» при применении ядра 3x3 для свертки?

Любой ответ должен включать новый форум, поскольку:

final = 1/9*(pixel1+pixel2+pixel3...+pixel9)

Получает неправильный ответ.


Редактировать: Более простой примерэто:

Я выполню эту математику с значениями цвета и альфа в диапазоне от 0..1:

enter image description here

Я собираюсь применитьсверточный фильтр размытия рамки до среднего пикселя:

ARGB'
      = 1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0) + 
        1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0) + 
        1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0);

      = (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0) +
        (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0) +
        (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0)

      = (0, 0.33, 0, 0.33)

Что дает довольно прозрачный темно-зеленый цвет.

enter image description here

Что не то, что яожидаю увидеть.Для сравнения, Photoshop's Box Blur выглядит так:

enter image description here

Если я предполагаю, что (0, 0.33, 0, 0.33) - это предварительно умноженная альфа, и, если ее не умножить, я получаю:

(0, 1, 0, 0.33)

enter image description here

Что выглядит правильно для моего непрозрачного примера;но я не знаю, что делать, когда начинаю использовать частично прозрачные пиксели.

См. также

Ответы [ 3 ]

6 голосов
/ 03 февраля 2011

У tkerwin уже есть правильный ответ , но, похоже, требуется дальнейшее объяснение.

Математика, которую вы указали в своем вопросе, абсолютно верна до самого конца. Именно здесь вы пропускаете шаг - результаты все еще находятся в предварительно умноженном альфа-режиме и должны быть «умножены» обратно в формат PixelFormat32bppARGB. Противоположность умножения является делением, таким образом:

finalRed = finalRed * 255 / finalAlpha;
finalGreen = finalGreen * 255 / finalAlpha;
finalBlue = finalBlue * 255 / finalAlpha;

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

2 голосов
/ 31 января 2011

Следуя советам в вашей ссылке, вы предварительно умножаете перед размытием и не умножаете перед размытием.В вашем примере предварительное умножение фактически ничего не делает, так как нет полупрозрачных пикселей.Вы сделали размытие, затем вам нужно предварительно не умножать, выполняя (при условии нормализованных значений цвета от 0 до 1):

RGB' = RGB/A  (if A is > 0)
A' = A

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

0 голосов
/ 16 июня 2019

Оба ответа здесь кажутся неправильными.

Используйте правильный режим смешивания, который в соответствии с Портером Даффом:

FG.RGB + (1.0 - FG.Alpha)*BG.RGB

Не уверен, откуда поступают остальные ответы, новау.

Альфа-кодирование диктует операцию over.

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