Как сделать прозрачность ARGB с помощью побитовых операторов - PullRequest
3 голосов
/ 17 марта 2011

Мне нужно сделать прозрачность, имея 2 пикселя:

pixel1: {A, R, G, B} - foreground pixel<br> pixel2: {A, R, G, B} - background pixel

A, R, G, B - байтовые значения

каждый цвет представлен байтовым значением

Теперь я вычисляю прозрачность как:

newR = pixel2_R * alpha / 255 + pixel1_R * (255 - alpha) / 255<br> newG = pixel2_G * alpha / 255 + pixel1_G * (255 - alpha) / 255<br> newB = pixel2_B * alpha / 255 + pixel1_B * (255 - alpha) / 255

но это слишком медленно Мне нужно сделать это с помощью побитовых операторов ( И, ИЛИ, XOR, ОТРИЦАНИЕ, БИТ ДВИЖЕНИЯ )

Я хочу сделать это на Windows Phone 7 XNA

--- прикрепленный код C # ---

    public static uint GetPixelForOpacity(uint reduceOpacityLevel, uint pixelBackground, uint pixelForeground, uint pixelCanvasAlpha)
    {
        byte surfaceR = (byte)((pixelForeground & 0x00FF0000) >> 16);
        byte surfaceG = (byte)((pixelForeground & 0x0000FF00) >> 8);
        byte surfaceB = (byte)((pixelForeground & 0x000000FF));

        byte sourceR = (byte)((pixelBackground & 0x00FF0000) >> 16);
        byte sourceG = (byte)((pixelBackground & 0x0000FF00) >> 8);
        byte sourceB = (byte)((pixelBackground & 0x000000FF));

        uint newR = sourceR * pixelCanvasAlpha / 256 + surfaceR * (255 - pixelCanvasAlpha) / 256;
        uint newG = sourceG * pixelCanvasAlpha / 256 + surfaceG * (255 - pixelCanvasAlpha) / 256;
        uint newB = sourceB * pixelCanvasAlpha / 256 + surfaceB * (255 - pixelCanvasAlpha) / 256;

        return (uint)255 << 24 | newR << 16 | newG << 8 | newB;
    }

Ответы [ 2 ]

3 голосов
/ 17 марта 2011

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

Вы можете сделать два метода, как указано в другомответы: используйте 256 вместо 255 или воспользуйтесь таблицей поиска.У обоих есть проблемы, но вы можете их смягчить.Это действительно зависит от того, на какой архитектуре вы это делаете: относительная скорость умножения, деления, сдвига, сложения и загрузки памяти.В любом случае:

Таблица поиска: тривиальная таблица поиска 256x256 - 64 КБ.Это разрушит ваш кеш данных и в итоге будет очень медленным.Я бы не рекомендовал это делать, если у вашего ЦП нет крайне медленного множителя, но ОЗУ имеет низкую задержку.Вы можете улучшить производительность, выбрасывая некоторые альфа-биты, например, A >> 3, что приводит к поиску 32x256 = 8 КБ, что дает больше шансов вписаться в кэш.

Используйте 256 вместо 255: идея заключается в том, чтоделение на 256 - это просто сдвиг вправо на 8. Это будет слегка смещено и будет иметь тенденцию округляться, слегка затемняя изображение, например, если R = 255, A = 255, то (R * A) / 256 = 254. Вы можете обмануть немного и сделать это: (R * A + R + A) / 256 или просто (R * A + R) / 256 или (R * A + A) / 256 = 255. Или масштабироватьСначала от А до 0.566, например: А = (256 * А) / 255.Это просто один дорогой делитель на 255 вместо 6. Тогда (R * A) / 256 = 255.

0 голосов
/ 17 марта 2011

Я не думаю, что это можно сделать с той же точностью, используя только эти операторы.Лучше всего, я полагаю, использовать LUT (если LUT может помещаться в кэш процессора, в противном случае он может быть даже медленнее)

// allocate the LUT (64KB)
unsigned char lut[256*256] __cacheline_aligned; // __cacheline_aligned is a GCC-ism

// macro to access the LUT
#define LUT(pixel, alpha) (lut[(alpha)*256+(pixel)])

// precompute the LUT
for (int alpha_value=0; alpha_value<256; alpha_value++) {
  for (int pixel_value=0; pixel_value<256; pixel_value++) {
    LUT(pixel_value, alpha_value) = (unsigned char)((double)(pixel_value) * (double)(alpha_value) / 255.0));
  }
}

// in the loop
unsigned char ialpha = 255-alpha;
newR = LUT(pixel2_R, alpha) + LUT(pixel1_R, ialpha);
newG = LUT(pixel2_G, alpha) + LUT(pixel1_G, ialpha);
newB = LUT(pixel2_B, alpha) + LUT(pixel1_B, ialpha);

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

...