overlay — наложение пикселей с альфа-значением в C / Stack Overflow

Я пытаюсь создать алгоритм для наложения изображения на прозрачную пленку поверх полностью непрозрачного изображения.
На следующем примере у меня есть заднее полностью непрозрачное изображение, а переднее изображение — синяя рамка с размытыми краями.
У меня проблема в том, что моя реализация неправильно накладывает полупрозрачные области, получая темные пиксели.

введите описание изображения здесь

Вот моя реализация:

#define OPAQUE 0xFF
#define TRANSPARENT 0
#define ALPHA(argb)  (uint8_t)(argb >> 24)
#define RED(argb)    (uint8_t)(argb >> 16)
#define GREEN(argb)  (uint8_t)(argb >> 8)
#define BLUE(argb)   (uint8_t)(argb)
#define ARGB(a, r, g, b) (a << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)
#define BLEND(a, b, alpha) ((a * alpha) + (b * (255 - alpha))) / 255

void ImageUtil::overlay(const uint32_t* front, uint32_t* back, const unsigned int width, const unsigned int height)
{
const size_t totalPixels = width * height;

for (unsigned long index = 0; index < totalPixels; index++)
{
const uint32_t alpha = ALPHA(*front);

const uint32_t R = BLEND(RED(*front), RED(*back), alpha);
const uint32_t G = BLEND(GREEN(*front), GREEN(*back), alpha);
const uint32_t B = BLEND(BLUE(*front), BLUE(*back), alpha);

*backPixels++ = ARGB(OPAQUE, R , G, B);
*frontPixels++;
}
}

ОБНОВИТЬ:

Файлы тестовых изображений

СКАЧАТЬ

0

Решение

Следуя советам от комментариев GMan а также interjay, Я исследовал дальше, и да, данные загружаются с предварительно умноженной альфа.
Это приводит к потемнению при смешивании. Решение состояло в том, чтобы не умножать передние пиксели, и наконец я получил ожидаемый результат.

Умножаем формулу:

((0xFF * color) / alpha)

Финальный код:

#define OPAQUE 0xFF;
#define TRANSPARENT 0;

#define ALPHA(rgb) (uint8_t)(rgb >> 24)
#define RED(rgb)   (uint8_t)(rgb >> 16)
#define GREEN(rgb) (uint8_t)(rgb >> 8)
#define BLUE(rgb)  (uint8_t)(rgb)

#define UNMULTIPLY(color, alpha) ((0xFF * color) / alpha)
#define BLEND(back, front, alpha) ((front * alpha) + (back * (255 - alpha))) / 255
#define ARGB(a, r, g, b) (a << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF)

void ImageUtil::overlay(const uint32_t* front, uint32_t* back, const unsigned int width, const unsigned int height)
{
const size_t totalPixels = width * height;

for (unsigned long index = 0; index < totalPixels; index++)
{
const uint32_t frontAlpha = ALPHA(*front);

if (frontAlpha == TRANSPARENT)
{
*back++;
*front++;
continue;
}

if (frontAlpha == OPAQUE)
{
*back++ = *front++;
continue;
}

const uint8_t backR = RED(*back);
const uint8_t backG = GREEN(*back);
const uint8_t backB = BLUE(*back);

const uint8_t frontR = UNMULTIPLY(RED(*front), frontAlpha);
const uint8_t frontG = UNMULTIPLY(GREEN(*front), frontAlpha);
const uint8_t frontB = UNMULTIPLY(BLUE(*front), frontAlpha);

const uint32_t R = BLEND(backR, frontR, frontAlpha);
const uint32_t G = BLEND(backG, frontG, frontAlpha);
const uint32_t B = BLEND(backB, frontB, frontAlpha);

*back++ = ARGB(OPAQUE, R , G, B);
*front++;
}
}
0

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector