Как использовать предварительное умножение во время свертки изображения для решения проблемы альфа-кровотечения?

StackOverflow https://stackoverflow.com/questions/4854839

Вопрос

я пытаюсь применить размытие прямоугольника к прозрачному изображению, и у меня получается "темный ореол" по краям.

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

enter image description here

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

enter image description here

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

enter image description here

Теперь мы применим к изображению прямоугольное размытие размером 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

Этот цвет слишком темный.Когда я выполняю размытие прямоугольника размером 3 пикселя на том же изображении размером 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 - это:

enter image description here

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

(0, 1, 0, 0.33)

enter image description here

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

Смотрите также

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

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

Не уверен, откуда берутся остальные ответы, но ничего себе.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top