Альфа-композитинг с фиксированной точкой (0xff не равен 1,0)C++

Программы на C++. Форум разработчиков
Anonymous
Альфа-композитинг с фиксированной точкой (0xff не равен 1,0)

Сообщение Anonymous »

Я пишу код (предназначенный для использования как в C, так и в C++), который выполняет альфа-компоновку с использованием целочисленных вычислений (фиксированная точка), и столкнулся с проблемой: 0xff не совсем равен 1,0. . Это особенно проблематично в альфа-канале. Например (0xff * 0xff) >> 8 равно 0xfe. Итак, если у вас есть белый пиксель с альфа-0xff и RGB 0xff, и вы пытаетесь предварительно умножить альфа-канал на цветовые каналы, вы получите 0xfe в каналах RGB, поэтому у вас больше нет белого цвета.
Вот несколько примеров функций, которые выполняют предварительное умножение альфа, а затем альфа-композицию с предварительно умноженным альфа, обе из которых имеют некоторый вариант этой проблемы. Они предназначены для RGBA/BGRA с прямым порядком байтов, давайте пока проигнорируем проблемы с порядком байтов:

Код: Выделить всё

unsigned premultiply_alpha(unsigned color)
{
unsigned alpha = ((color>>24) & 0xff);
unsigned rb = color & 0xff00ffU;
unsigned g  = color & 0x00ff00U;

rb = (rb * alpha) >> 8;
g  = (g  * alpha) >> 8;

return (color & 0xff000000) | (rb & 0xff00ff) | (g & 0x00ff00);
}

Код: Выделить всё

unsigned rgb_blend(unsigned background, unsigned color)
{
unsigned alpha = color>>24;
unsigned rb = background & 0xff00ffU;
unsigned  g = background & 0x00ff00U;
rb = (color & 0xff00ff) + ((0xff - alpha) * rb >> 8);
g  = (color & 0x00ff00) + ((0xff - alpha) * g  >> 8);

unsigned dest_alpha = background>>24;
dest_alpha = alpha + dest_alpha - ((alpha*dest_alpha) >> 8);
dest_alpha = dest_alpha < 255 ? dest_alpha : 255;

return  (dest_alpha > 8 эквивалентно делению на 0x100, а не на 0xff. Поэтому замена сдвига на /0xff решает проблему. Однако, поскольку делитель является постоянным, компилятор будет избегать использования инструкции div, используя трюк из главы 10 Hacker's Delight (я подтвердил, что GCC делает это даже без включенной оптимизации). Эмпирически кажется, что обрабатывать r и b в одном регистре, как я это делал здесь, при наличии такой оптимизации небезопасно. Мне все еще интересно узнать, существуют ли «стандартные» решения этой проблемы/то, что обычно делают другие люди. 

Подробнее здесь: [url]https://stackoverflow.com/questions/78686806/alpha-compositing-in-fixed-point-0xff-is-not-1-0[/url]

Вернуться в «C++»