RGBA -> окончательный RGB
От: muradm Россия  
Дата: 16.09.05 11:20
Оценка:
Когда мы используем цвет с альфой, то есть RGBA
И делаем SetPixel точки такого цвета на некоторую другую точку, то в итоге получаем точку некоторого 3-го цвета.

Как я понимаю в конечном итоге монитор показывает эту точку в формате RGB, то есть без альфы.
Так вот: как получить эти окончательные RGB, имея цвет исходного пикселяи и цвет нового пикселя?
Re: RGBA -> окончательный RGB
От: WinterMute Россия http://yarrr.ru
Дата: 16.09.05 12:01
Оценка:
Здравствуйте, muradm, Вы писали:

M>Когда мы используем цвет с альфой, то есть RGBA

M>И делаем SetPixel точки такого цвета на некоторую другую точку, то в итоге получаем точку некоторого 3-го цвета.

M>Как я понимаю в конечном итоге монитор показывает эту точку в формате RGB, то есть без альфы.

M>Так вот: как получить эти окончательные RGB, имея цвет исходного пикселяи и цвет нового пикселя?

Ты имеешь в виду, как наложить один RGBA цвет на другой? Я делал так:

    // Шаблон для наложения цвета colorOver на фон (bg). 
    template< bool t_bUseR  // Накладывать красную компоненту
            , bool t_bUseG  // Накладывать зелёную компоненту
            , bool t_bUseB  // Накладывать синюю компоненту
            , bool t_bUseA  // Изменять значение альфаканала
            , bool t_bBgIsOpaque // полагать, что bg.A() == 255
            , bool t_bUseScale   // домножать colorOver.A() на scale
            >
    inline void blendColors_T( const Color& bg, const Color& colorOver, Color& dst, byte scale = 255 )
    {
        uint topA = colorOver.A();

        if( t_bUseScale )
        {
            topA *= scale;
            topA /= 255;
        }

        const uint err = 255/2;

        switch( topA )
        {
        case 255:
            dst = colorOver; return;
        case 0:
            dst = bg; return;
        default:
            uint a3, a4;

            if( t_bBgIsOpaque )
            {
                a3 = uint(255) - topA;
                a4 = topA;
            }
            else
            {
                uint k  = ( uint( uint(255)-topA ) * bg.A() + err ) / 255;

                uint a2 = (topA + k);

                a3 = (k*uint(255))/a2;
                a4 = uint(255)-a3;

                if( t_bUseA ) dst.A() = a2;
            }

            if( t_bUseR ) dst.R() = (bg.R()*a3 + colorOver.R()*a4 + err) / 255;
            if( t_bUseG ) dst.G() = (bg.G()*a3 + colorOver.G()*a4 + err) / 255;
            if( t_bUseB ) dst.B() = (bg.B()*a3 + colorOver.B()*a4 + err) / 255;

            return;
        }
    }
}


Здесь используется математически правильная формула, сделав небольшое допущение можно ускорить код примерно в два раза -- для этого нужно заменить "/ 255" на ">> 8", ещё можно отказаться от округления в ближайшую сторону отбросив "+ err".

Собственно о параметрах: t_bUseR, t_bUseG, t_bUseB -- какие каналы изображения накладывать, от такой гибкости можно и отказаться, впрочем, на производительность она никак не влияет.
t_bUseA -- после наложения цветов альфаканал меняется, если вдруг не хочется перезаписывать альфаканал, то нужно установить этот параметр в false.
t_bBgIsOpaque -- предпологать что прозрачность фонового цвета равна 255, в этом случае вычисления значительно упрощаются.
t_bUseScale -- домножать прозрачность накладываемого цвета на коэфициент (scale/255), полезно, если хочется на лету делать накладываемый цвет полупрозрачным.

Color& bg -- фоновый цвет;
Color& colorOver -- накладываемый цвет;
Color& dst -- цвет, куда сохраняется результат, может совпадать с bg;

Теперь, допустим у тебя есть два цвета bg = RGBA(100,100,100,100) и colorOver = RGBA(200,200,200,200), после их наложения результирующий цвет тоже будет полупрозрачным (только если альфа bg не равна 255), т.е., в общем случае придётся наложить полученный цвет на цвет, который считается фоновым, например цвет диалога. Но если цвет bg заведомо непрозрачен, то можно обойтись только одним наложением (лучше с флагом t_bBgIsOpaque).
Re[2]: RGBA -> окончательный RGB
От: Stanky  
Дата: 18.09.05 09:17
Оценка:
> Здесь используется математически правильная формула, сделав небольшое
> допущение можно ускорить код примерно в два раза -- для этого нужно
> заменить "/ 255" на ">> 8", ещё можно отказаться от округления в
> ближайшую сторону отбросив "+ err".
>
Чёт у тя слишком громоздко всё сделано!!!
А по поводу деления, то: ((Value + 128) + ((Value + 128) /256)) / 256 == Value / 255 (естественно в целочисленной арифметике) и не нужно никаких "+ err"!!!
В коде это выглядит примерно так:
    Value += 128;
    Result =  (Value + (Value >> 8)) >> 8;


Если интересно, то можешь глянуть это
Автор: Stanky
Дата: 02.09.05
!!!
Posted via RSDN NNTP Server 1.9
Не бойся выглядеть глупо, от этого ты выглядишь ещё глупей!!!
Re[3]: RGBA -> окончательный RGB
От: WinterMute Россия http://yarrr.ru
Дата: 18.09.05 12:03
Оценка:
Здравствуйте, Stanky, Вы писали:

>> Здесь используется математически правильная формула, сделав небольшое

>> допущение можно ускорить код примерно в два раза -- для этого нужно
>> заменить "/ 255" на ">> 8", ещё можно отказаться от округления в
>> ближайшую сторону отбросив "+ err".
>>
S>Чёт у тя слишком громоздко всё сделано!!!
S>А по поводу деления, то: ((Value + 128) + ((Value + 128) /256)) / 256 == Value / 255 (естественно в целочисленной арифметике) и не нужно никаких "+ err"!!!
S>В коде это выглядит примерно так:
S>
S>    Value += 128;
S>    Result =  (Value + (Value >> 8)) >> 8;
S>


S>Если интересно, то можешь глянуть это
Автор: Stanky
Дата: 02.09.05
!!!


В твоей формуле я вижу значение канала только одного цвета (Value), где зачение канала второго цвета? От err ты тоже никуда не ушёл, оно у тебя равно 128. И, мне кажется, проще у тебя получилось потому, что ты предпологаешь что фон, на который накладывется пиксел, полностью непрозрачен, в этом случае у меня тоже всё коротко записывается (см. ветку t_bBgIsOpaque == true).

PS: Всё-таки, если не сложно, объясни, как твоя формула работает.
Re[4]: RGBA -> окончательный RGB
От: WinterMute Россия http://yarrr.ru
Дата: 18.09.05 12:10
Оценка:
WM>В твоей формуле я вижу значение канала только одного цвета (Value), где зачение канала второго цвета? От err ты тоже никуда не ушёл, оно у тебя равно 128. И, мне кажется, проще у тебя получилось потому, что ты предпологаешь что фон, на который накладывется пиксел, полностью непрозрачен, в этом случае у меня тоже всё коротко записывается (см. ветку t_bBgIsOpaque == true).

WM>PS: Всё-таки, если не сложно, объясни, как твоя формула работает.


Сорри, невнимательно прочитал, за формулу спасибо.

Твой исходник толком оценить не могу, не дружу с ассемблером, если не лень покажи эквивалент на C.
Re[4]: RGBA -> окончательный RGB
От: Stanky  
Дата: 18.09.05 14:46
Оценка: 12 (1)
> В твоей формуле я вижу значение канала только одного цвета (Value), где
> зачение канала второго цвета?
>
Этим примером я всего лишь показал уход от деления к сдвигам, сделанный в целях оптимизации скорости выполнения, при этом результат будет тем же, если бы мы делили на 255!!!

> От err ты тоже никуда не ушёл, оно у тебя равно 128.

>
Это сделано для ухода от деления!!!ъ

> И, мне кажется, проще у тебя получилось потому, что ты предпологаешь что

> фон, на который накладывется пиксел, полностью непрозрачен, в этом случае у
> меня тоже всё коротко записывается (см. ветку t_bBgIsOpaque == true).
>
Как раз-таки всё наоборот — если считать, что мы работаем с Premultiplied цветом, то всё станет гораздо проще и будет совершенно побарабану какой прозрачности цвет на который мы блендим другой!!!

> PS: Всё-таки, если не сложно, объясни, как твоя формула работает.

>
Покажу сперва абсолютно без оптимизации, а потом соптимизацией (не MMX):
struct ARGB
{
    BYTE Blue;
    BYTE Green;
    BYTE Red;
    BYTE Alpha;
};

/*************************************************************************************************/
ARGB StAlphaBlendColors(ARGB ColorDst, ARGB ColorSrc)
{
    ARGB Result;
    Result.Blue    = (ColorSrc.Alpha * ColorSrc.Blue  + (255 - ColorSrc.Alpha) * ColorDst.Blue)  / 255;
    Result.Green   = (ColorSrc.Alpha * ColorSrc.Green + (255 - ColorSrc.Alpha) * ColorDst.Green) / 255;
    Result.Red     = (ColorSrc.Alpha * ColorSrc.Red   + (255 - ColorSrc.Alpha) * ColorDst.Red)   / 255;
    Result.Alpha   = (ColorSrc.Alpha * 255            + (255 - ColorSrc.Alpha) * ColorDst.Alpha) / 255;
    return Result;
}
/*************************************************************************************************/



/*************************************************************************************************/
ARGB StAlphaBlendColors(ARGB ColorDst, ARGB ColorSrc)
{
    ARGB Result;

    //255 - Value == ~Value
    BYTE InverseAlpha = ~ColorSrc.Alpha;

    Result.Blue    = ColorSrc.Alpha * ColorSrc.Blue  + InverseAlpha * ColorDst.Blue  + 128;
    Result.Green   = ColorSrc.Alpha * ColorSrc.Green + InverseAlpha * ColorDst.Green + 128;
    Result.Red     = ColorSrc.Alpha * ColorSrc.Red   + InverseAlpha * ColorDst.Red   + 128;
    Result.Alpha   = ColorSrc.Alpha * 255            + InverseAlpha * ColorDst.Alpha + 128;

    Result.Blue    = (Result.Blue  + (Result.Blue  >> 8)) >> 8;
    Result.Green   = (Result.Green + (Result.Green >> 8)) >> 8;
    Result.Red     = (Result.Red   + (Result.Red   >> 8)) >> 8;
    Result.Alpha   = (Result.Alpha + (Result.Alpha >> 8)) >> 8;

    return Result;
}
/*************************************************************************************************/


Именно так это происходит в приведённом коде!!! Естественно можно в таком виде не запариваться с Alpha и сразу же назначать ей значение 255 или любое другое (в MMX одна формула на всех)!!!
Этот код демонстрирует блендинг не Premultiplied цвета на Premultiplied, поэтому мы можем идти только снизу вверх (по слоям) и именно поэтому компонента прозрачности назначения может иметь любое значение — на результат влияет только прозрачность источника!!!

Теперь, что такое Premultiplied цвет:
Color.Blue = (Color.Alpha * Color.Blue) / 255;
Color.Green = (Color.Alpha * Color.Green) / 255;
Color.Red = (Color.Alpha * Color.Red) / 255;
Color.Alpha = Color.Alpha;
То есть все компоненты цвета заранее перемножены на компоненту прозрачности и именно Premultiplied цвет мы всегда выводим на экран даже, когда изображение абсолютно непрозрачно!!!
В этом случае получается следующая картина:
Color.Alpha = 255;
Color.Blue = (255 * Color.Blue) / 255;
Color.Green = (255 * Color.Green) /255;
Color.Red = (255 * Color.Red) /255;

Если же мы теперь полностью перейдём к Premultiplied цвету, то формула блендинга упростится до такого варианта:
/*************************************************************************************************/
ARGB StAlphaBlendColors(ARGB ColorDst, ARGB ColorSrc)
{
    ARGB Result;
    Result.Blue    = ColorSrc.Blue  + (255 - ColorSrc.Alpha) * ColorDst.Blue  / 255;
    Result.Green   = ColorSrc.Green + (255 - ColorSrc.Alpha) * ColorDst.Green / 255;
    Result.Red     = ColorSrc.Red   + (255 - ColorSrc.Alpha) * ColorDst.Red   / 255;
    Result.Alpha   = ColorSrc.Alpha + (255 - ColorSrc.Alpha) * ColorDst.Alpha / 255;
    return Result;
}
/*************************************************************************************************/

Здесь мы получаем одну формулу для всех компонент цвета, а так же возможность блендить в любом порядке (хоть сверху-вниз, хоть снизу-вверх) так, как тут уже накладывается Premultiplied на Premultiplied и результатом опять является Premultiplied, причём с верной прозрачностью!!! 50% прозрачности на 50% == 75% или 128 + (255 — 128) * 128 / 255 == 191!!!

Естественно можно "извратнуться" и сделать формулу для наложения не Premultiplied на не Premultiplied и чтоб результатом был не Premultiplied:
/*************************************************************************************************/
ARGB StAlphaBlendColors(ARGB ColorDst, ARGB ColorSrc)
{
    //Premultiplied = (Alpha * Color) / 255;
    //Color = 255 * Premultiplied  / Alpha 
    ARGB Result;
    Result.Alpha   = (ColorSrc.Alpha * 255            + (255 - ColorSrc.Alpha) * ColorDst.Alpha)                  / 255;
    Result.Blue    = (ColorSrc.Alpha * ColorSrc.Blue  + (255 - ColorSrc.Alpha) * ColorDst.Alpha * ColorDst.Blue)  * 255 / Result.Alpha;
    Result.Green   = (ColorSrc.Alpha * ColorSrc.Green + (255 - ColorSrc.Alpha) * ColorDst.Alpha * ColorDst.Green) * 255 / Result.Alpha;
    Result.Red     = (ColorSrc.Alpha * ColorSrc.Red   + (255 - ColorSrc.Alpha) * ColorDst.Alpha * ColorDst.Red)   * 255 / Result.Alpha;
    return Result;
}
/*************************************************************************************************/

А так же в этом случае необходимо учитывать момент равенства Result.Alpha нулю!!!

Вобщем думаю преимущество Premultiplied над не Premultiplied очевидно!!!
Posted via RSDN NNTP Server 1.9
Не бойся выглядеть глупо, от этого ты выглядишь ещё глупей!!!
Re[3]: RGBA -> окончательный RGB
От: Stanky  
Дата: 18.09.05 15:06
Оценка: 9 (1)
> А по поводу деления, то: ((Value + 128) + ((Value + 128) /256)) / 256
> == Value / 255 (естественно в целочисленной арифметике) и не нужно
> никаких "+ err"!!!
>
Сорри, тут я не совсем точно выразился: ((Value + 128) + ((Value + 128) /256)) / 256 == Value / 255 + err!!!
Например:
128 / 255 == 0,501... то есть в округлённом виде это будет единица!!!
((128 + 128) + (128 + 128) / 256) / 256 == 1,00390625 то есть в целочисленной арифметике мы сразу получаем единицу без всяких округлений!!!
Posted via RSDN NNTP Server 1.9
Не бойся выглядеть глупо, от этого ты выглядишь ещё глупей!!!
Re[5]: RGBA -> окончательный RGB
От: WinterMute Россия http://yarrr.ru
Дата: 19.09.05 17:42
Оценка:
S>Естественно можно "извратнуться" и сделать формулу для наложения не Premultiplied на не Premultiplied и чтоб результатом был не Premultiplied:
S>
S>/*************************************************************************************************/
S>ARGB StAlphaBlendColors(ARGB ColorDst, ARGB ColorSrc)
S>{
S>    //Premultiplied = (Alpha * Color) / 255;
S>    //Color = 255 * Premultiplied  / Alpha 
S>    ARGB Result;
S>    Result.Alpha   = (ColorSrc.Alpha * 255            + (255 - ColorSrc.Alpha) * ColorDst.Alpha)                  / 255;
S>    Result.Blue    = (ColorSrc.Alpha * ColorSrc.Blue  + (255 - ColorSrc.Alpha) * ColorDst.Alpha * ColorDst.Blue)  * 255 / Result.Alpha;
S>    Result.Green   = (ColorSrc.Alpha * ColorSrc.Green + (255 - ColorSrc.Alpha) * ColorDst.Alpha * ColorDst.Green) * 255 / Result.Alpha;
S>    Result.Red     = (ColorSrc.Alpha * ColorSrc.Red   + (255 - ColorSrc.Alpha) * ColorDst.Alpha * ColorDst.Red)   * 255 / Result.Alpha;
S>    return Result;
S>}
S>/*************************************************************************************************/
S>

S>А так же в этом случае необходимо учитывать момент равенства Result.Alpha нулю!!!

S>Вобщем думаю преимущество Premultiplied над не Premultiplied очевидно!!!


Что такое premultiply я в курсе, но он мне не нравится -- сама по себе точность 8 бит на канал не супер, а использование premultipy снижает её ещё больше. Как следствие -- появляются невалидные цвета (например RGBA(255,255,255,0)), которые пользователь может по дури записать в битмап. Честно говоря, блиттинг происходит очень быстро, т.е., те спички, которые экономятся при использовании premultiply большой роли не играют, так что для себя я не вижу смысла использовать premultiply, по мне так недостатки перевешивают выйгрыш.

Собственно, тот исходник, который я приводил вначале, работал с не premultiply, и, в общем, если выкинуть все навороты, был анологичен твоей последней формуле, я переписал её так (с контролем нулевого делителя):
    inline void blendColors_T( const Color& bg, const Color& over, Color& dst )
    {
        typedef uint wide_type;

        wide_type overA = over.A();
        wide_type inversedOverA = 255 - overA;

        switch( overA )
        {
        case 255:
            dst = over; return;
        case 0:
            dst = bg; return;
        default:
            wide_type kBg = (inversedOverA * bg.A()) / 255;
            wide_type dstA = overA + kBg;

            dst.R() = (overA * over.R() + kBg * bg.R()) / dstA;
            dst.G() = (overA * over.G() + kBg * bg.G()) / dstA;
            dst.B() = (overA * over.B() + kBg * bg.B()) / dstA;
            dst.A() = byte(dstA);

            return;
        }
    }


-- тут появилась идея, которая у меня даёт прирост производительности порядка 30%: overA и kBg -- веса накладываемого и фонового цветов, если выразить их как доли единицы, то они будут равны overA/dstA и kBg/dstA соответсвенно. Если взять в качестве делителя не dstA, а степень двойки (например 256), тогда удастся заменить деление сдвигом. -- Соответственно изменив делитель, нужно скорректировать и делимое, так, чтобы отношение overA/256 осталось прежним.:

    typedef uint wide_type;

    wide_type kBg, kOver;
    wide_type overA = over.A();

    //...

    // weight of bg color
    // можно воспользоваться более быстрой формулой деления на 255, но не суть
    wide_type kBg = ( ( 255-overA ) * bg.A() + err ) / 255;
    wide_type dstA = overA + kBg;

    // scale weights of bg and foreground colors from W/dstA to W2/256
    kBg = ( kBg * 256 + 128 ) / dstA;
    kOver = 256 - kBg; // его не обязательно пересчитывать по той-же формуле, 
                       // нам известно что сумма kBg + kOver == 256

    dst.R() = (bg.R()*kBg + over.R()*kOver + 128) / 256;
    dst.G() = (bg.G()*kBg + over.G()*kOver + 128) / 256;
    dst.B() = (bg.B()*kBg + over.B()*kOver + 128) / 256;
    dst.A() = byte(dstA);


В первоначальном варианте я "растягивал" делитель до 255, поэтому в последних формулах у меня стояло "/255", а не "/ Result.Alpha" -- как у тебя
Re[6]: RGBA -> окончательный RGB
От: Stanky  
Дата: 20.09.05 04:34
Оценка:
> сама по себе точность 8 бит на канал не супер, а использование premultipy
> снижает её ещё больше.
>
Обоснуй!!!

> Как следствие -- появляются невалидные цвета (например

> RGBA(255,255,255,0)), которые пользователь может по дури записать в битмап.
>
Ну и кто здесь виноват?
А вообще-то никто не мешает принимать на вход не Premultiplied, перемножать и работать с Premultiplied (если блендинг будет неоднократный)!!!

> Честно говоря, блиттинг происходит очень быстро, т.е., те спички, которые

> экономятся при использовании premultiply большой роли не играют
>
А вот ты бы взял да посчитал на сколько больше операций умножения у нас будет, если взять хотя бы тот вариант, что для каждой компаненты цвета для не Premultiplied случая у нас только на одно умножение больше, чем для Premultiplied!!! Если у нас блендятся картинки 320 * 240, то мы "зазря" выполним 230400 операций умножения!!! И это ты спичками называешь?

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

>
Огласите весь список, пожалуйста!!!
Posted via RSDN NNTP Server 1.9
Не бойся выглядеть глупо, от этого ты выглядишь ещё глупей!!!
Re[7]: RGBA -> окончательный RGB
От: WinterMute Россия http://yarrr.ru
Дата: 20.09.05 11:01
Оценка:
Судя по тону, ты воспринял это как личный вызов. Зря.

Здравствуйте, Stanky, Вы писали:

>> сама по себе точность 8 бит на канал не супер, а использование premultipy

>> снижает её ещё больше.
>>
S>Обоснуй!!!

Запросто. В premultiply максимальное значение каждого канала не может быть больше альфы, таким образом, для альфы == 0, есть только одно валидное значение цвета (0,0,0,0), т.е., весь остальной диапозон значений мы не используем, только для alpha == 255 диапозон значений остаётся прежним (0..255). Если вдруг мы захотим поднять яркость альфа-канала, то увидим... в общем, не знаю что мы увидим, но если а картинке были плавные переходы то они исчезнут.

>> Как следствие -- появляются невалидные цвета (например

>> RGBA(255,255,255,0)), которые пользователь может по дури записать в битмап.
>>
S>Ну и кто здесь виноват?
S>А вообще-то никто не мешает принимать на вход не Premultiplied, перемножать и работать с Premultiplied (если блендинг будет неоднократный)!!!

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

>> Честно говоря, блиттинг происходит очень быстро, т.е., те спички, которые

>> экономятся при использовании premultiply большой роли не играют
>>
S>А вот ты бы взял да посчитал на сколько больше операций умножения у нас будет, если взять хотя бы тот вариант, что для каждой компаненты цвета для не Premultiplied случая у нас только на одно умножение больше, чем для Premultiplied!!! Если у нас блендятся картинки 320 * 240, то мы "зазря" выполним 230400 операций умножения!!! И это ты спичками называешь?

Blending это не самая частая операция, обычно, до того как заблендить картинку над ней выполняются значительно более дорогие операции, по сравнению с которыми блендинг просто ничего не стоит. С практической точки зрения, есть множество областей, где точность более важна чем скорость, которую можно почувствовать выполняя blending пачками по тысяче. Например, у меня в демке блендинг семи картинок, каждая размером 100x100, при 35fps, отжирает 0%(!) производительности (округлённо разумеется).

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

>>
S>Огласите весь список, пожалуйста!!!
Те, которые упомянуты выше -- потеря точности и как следсвие дырки (невалидные цвета) в цветовом диапозоне.
Re[8]: RGBA -> окончательный RGB
От: Stanky  
Дата: 21.09.05 20:33
Оценка:
> Судя по тону, ты воспринял это как личный вызов. Зря.
>
Совершенно нет!!!

> Если вдруг мы захотим поднять яркость альфа-канала, то увидим...

> в общем, не знаю что мы увидим, но если а картинке были плавные переходы
> то они исчезнут.
>
Ааа... Вон ты о чём!!! Тогда, да — согласен!!!

> Blending это не самая частая операция, обычно, до того как заблендить

> картинку над ней выполняются значительно более дорогие операции, по
> сравнению с которыми блендинг просто ничего не стоит.
>
Вобщем у нас просто цели и задачи разные!!!
Posted via RSDN NNTP Server 1.9
Не бойся выглядеть глупо, от этого ты выглядишь ещё глупей!!!
Re[9]: Злостный офтоп
От: McSeem2 США http://www.antigrain.com
Дата: 21.09.05 21:52
Оценка: +1
Здравствуйте, Stanky, Вы писали:

>> Судя по тону, ты воспринял это как личный вызов. Зря.

S>Совершенно нет!!!
S>Ааа... Вон ты о чём!!! Тогда, да — согласен!!!
S>Вобщем у нас просто цели и задачи разные!!!

Ну и т.д.

Урок Русского Языка (и пусть меня забянят — я не против).
Так уж исторически сложилось, что повествовательные предложения принято завершать точкой. Это примерно так же, как точка с зяпятой в конце оператора в C/C++/C#/Java/etc. Для придания предложению восклицательного оттенка используется специальный символ — восклицательный знак. Для придания очень сильного восклицательного оттенка можно поставить три восклицательных знака. В письме это является общепринятым выражением очень сильной эмоции. Если же человек ставит по три восклицательных знака после каждого предложения, то это означает, что он просто ОРЁТ!!! на собеседника. А это является признаком неуважения. Или даже презрения к собеседнику. "Ты чо?!! в натуре!!! пацан!!! не понимаешь?!!" — и распальцовка.

Stanky (кстати, ник тоже неудачный: stank — past of stink), ты как-то объяснял это "некой своей давней привычкой". Но извини, ты же не позволяешь себе громко пердеть за столом? Или позволяешь? Говоря при этом, "не обращайте внимания — это моя давняя привычка"? Три восклицательных знака в конце каждого предложения — это категория того же порядка, что и пердеж за столом. Сразу возникает впечатление, что мы имеем дело с человеком, несколько больным на голову. А избавиться от этого очень просто — когда сообщение написано, но еще не отправлено, надо заменить все восклицательные знаки на точки. Вот и все.

Пожалуйста, не воспринимай это как некую личную обиду — ты человек весьма технически грамотный и у тебя есть хороший потенциал. Только вот не надо пердеть за столом. Это нехорошо. Это все портит. Честно!
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[10]: Злостный офтоп
От: Stanky  
Дата: 22.09.05 15:06
Оценка:
> Пожалуйста, не воспринимай это как некую личную обиду — ты человек
> весьма технически грамотный и у тебя есть хороший потенциал. Только вот
> не надо пердеть за столом. Это нехорошо. Это все портит. Честно!
>
Спасибо, учту...
Posted via RSDN NNTP Server 1.9
Не бойся выглядеть глупо, от этого ты выглядишь ещё глупей!!!
Re: RGBA -> окончательный RGB
От: McSeem2 США http://www.antigrain.com
Дата: 23.09.05 15:24
Оценка: 3 (1)
Здравствуйте, muradm, Вы писали:

M>Как я понимаю в конечном итоге монитор показывает эту точку в формате RGB, то есть без альфы.

M>Так вот: как получить эти окончательные RGB, имея цвет исходного пикселяи и цвет нового пикселя?

Прежде чем приводить формулы, надо понять принцип. RGB — это тот же RGBA, у которого альфа-канал — лишь подразумеваемый и его значение всегда равно 255. Поскольку при стандартной операции AlphaBlend (Src Over Dst), значение альфа никогда не может стать меньше, чем было раньше, а наше подрразумевамое альфа и так уже максимально, то операцию с альфа-каналом можно опустить.

Однако, надо знать, в каком виде у нас цвета в буфере — premultiplied или plain. Например, в plain полупрозначный белый RGBA=(255,255,255,127). В premultiplied он становится RGBA=(127,127,127,127). То есть, в premultiplied, значенеие каналов не имеет права превышать значения Aplha. И формулы для превращения в RGB — разные.
Исчерпывающая информация здесь:
http://www.cs.princeton.edu/courses/archive/fall00/cs426/papers/smith95a.pdf

Итого, если у нас исходные цвета plain (все оптимизации опущены для простоты):
cDst' = cDst + (cSrc - cDst) * aSrc / 255;

cSrc — исходный цвет (один компонент),
aSrc — исходная Alpha,
cDst — текущий цвет в буфере (один компоненит),

В случае premultiplied:
cDst' = cSrc + cDst * (255 - aSrc) / 255;


Ну, разумеется, деление заменяем на сдвиг с коррекцией, как уже было сказано.

Из второй формулы так же следует (с учетом логики premultiplied), что если нас устраиват черный фон (и только черный), мы просто можем скопировать значения RGB и отбросить Alpha. Для любого другого цвета фона RGB, надо делать полноценный AlphaBlend. В случае Plain color space, AlphaBlend надо выполнять в любом случае.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[2]: RGBA -> окончательный RGB
От: muradm Россия  
Дата: 26.09.05 07:09
Оценка:
Спасибо, попробуем
Re[2]: RGBA -> окончательный RGB
От: muradm Россия  
Дата: 10.10.05 15:15
Оценка:
Огромное спасибо!
То, что надо.

В моём случае, это оказался вариант plain.
Re[3]: RGBA -> окончательный RGB
От: McSeem2 США http://www.antigrain.com
Дата: 10.10.05 17:26
Оценка:
Здравствуйте, muradm, Вы писали:

M>В моём случае, это оказался вариант plain.


Подозреваю, что это PNG.
Кстати, выполнять полноценный alpha-blend для plain RGBA (так, чтобы в результате получалось тоже plain) — значительно дороже. Там появляется деление не на 255, а на переменную:

static void blend_pix(value_type* p, 
                      unsigned cr, unsigned cg, unsigned cb,
                      unsigned alpha)
{
   if(alpha == 0) return;
   calc_type a = p[Order::A];
   calc_type r = p[Order::R] * a;
   calc_type g = p[Order::G] * a;
   calc_type b = p[Order::B] * a;
   a = ((alpha + a) << base_shift) - alpha * a;
   p[Order::A] = (value_type)(a >> base_shift);
   p[Order::R] = (value_type)((((cr << base_shift) - r) * alpha + (r << base_shift)) / a);
   p[Order::G] = (value_type)((((cg << base_shift) - g) * alpha + (g << base_shift)) / a);
   p[Order::B] = (value_type)((((cb << base_shift) - b) * alpha + (b << base_shift)) / a);
}

Здесь base_shift=8.

Но если у нас исходные цвета plain, а в результате надо получить premultiplied, то вычисления сокращаются:
static void blend_pix(value_type* p, 
                                 unsigned cr, unsigned cg, unsigned cb,
                                 unsigned alpha)
{
    calc_type r = p[Order::R];
    calc_type g = p[Order::G];
    calc_type b = p[Order::B];
    calc_type a = p[Order::A];
    p[Order::R] = (value_type)(((cr - r) * alpha + (r << base_shift)) >> base_shift);
    p[Order::G] = (value_type)(((cg - g) * alpha + (g << base_shift)) >> base_shift);
    p[Order::B] = (value_type)(((cb - b) * alpha + (b << base_shift)) >> base_shift);
    p[Order::A] = (value_type)((alpha + a) - ((alpha * a + base_mask) >> base_shift));
}


То есть, premultiplied получается как бы автоматически. Кстати, для WinAPI AlphaBlend требуется именно premultiplied.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: RGBA -> окончательный RGB
От: WinterMute Россия http://yarrr.ru
Дата: 10.10.05 18:06
Оценка: 30 (1)
MS>Подозреваю, что это PNG.
MS>Кстати, выполнять полноценный alpha-blend для plain RGBA (так, чтобы в результате получалось тоже plain) — значительно дороже. Там появляется деление не на 255, а на переменную:

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

MS>
MS>static void blend_pix(value_type* p, 
MS>                      unsigned cr, unsigned cg, unsigned cb,
MS>                      unsigned alpha)
MS>{
MS>   if(alpha == 0) return;
MS>   calc_type a = p[Order::A];
MS>   calc_type r = p[Order::R] * a;
MS>   calc_type g = p[Order::G] * a;
MS>   calc_type b = p[Order::B] * a;
MS>   a = ((alpha + a) << base_shift) - alpha * a;
MS>   p[Order::A] = (value_type)(a >> base_shift);
MS>   p[Order::R] = (value_type)((((cr << base_shift) - r) * alpha + (r << base_shift)) / a);
MS>   p[Order::G] = (value_type)((((cg << base_shift) - g) * alpha + (g << base_shift)) / a);
MS>   p[Order::B] = (value_type)((((cb << base_shift) - b) * alpha + (b << base_shift)) / a);
MS>}
MS>

MS>Здесь base_shift=8.
Re[5]: RGBA -> окончательный RGB
От: McSeem2 США http://www.antigrain.com
Дата: 10.10.05 19:13
Оценка:
Здравствуйте, WinterMute, Вы писали:

MS>>Подозреваю, что это PNG.

MS>>Кстати, выполнять полноценный alpha-blend для plain RGBA (так, чтобы в результате получалось тоже plain) — значительно дороже. Там появляется деление не на 255, а на переменную:

WM>Не обязательно, в одном из предыдущих постов я говорил что можно обойтись только одним делением вмечто трёх.


Спасибо! Как-то я не обратил внимания.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.