Alpha blend two RGBA colors?


#1

Hi,

I am trying to overlay one color on top of another using the alpha value to determine the strength of overlay. Can i do this using Cinder or do i need to write my own?

Related Wikipedia page https://en.wikipedia.org/wiki/Alpha_compositing#Description


#2

Hi,

of course you can do this in Cinder, it’s one of the most basic things one can do :slight_smile: Here’s how you’d draw two, differently colored rectangles on top of each other:

void MyApp::draw()
{
    // Using scoped variables, we can store the current color and blend mode, 
    // so we can restore it when we're done drawing.

    // Set the current color to Red.
    gl::ScopedColor scpColor( 1, 0, 0 );

    // Draw a rectangle.
    gl::drawSolidRect( Rectf( 50, 60, 400, 360 ) );

    // Enable alpha blending and set the current color to 50% Blue.
    // Note: we don't need another scoped variable.
    gl::ScopedBlendAlpha scpBlend;
    gl::color( ColorA( 0, 0, 1, 0.5f ) ); // RGBA

    // Draw another rectangle on top of the first one.
    gl::drawSolidRect( Rectf( 100, 110, 450, 410 ) );

    // The scoped variables will now go out of scope and restore
    // the drawing color and blend mode to their original states.
}

To understand what’s happening, try to change the colors and opacity. For example, see what happens when you swap the red and blue: will the mixed color be the same? (Spoiler: no). What happens if you change the opacity to a value larger than 1? What happens if you draw more than two rectangles? What happens if you use gl::ScopedBlendAdditive instead? (For a fun experiment, try additive blending when drawing a red, green and blue circle on top of each other).

-Paul


#3

Thanks Paul! I was looking in the color header file for it. How do i get out the final blended color?

Some background into what i am trying to achieve. I am placing an overlay on each pixel in an image. I need to do something like Color final = overlay blendAlpha source. Then i set that pixels color to final and write out the image.


#4

I’m not sure I understand what you mean. The final blended color is calculated per pixel by the GPU and rendered to the window. If you want to manipulate pixels on the CPU instead, have a look at the functions in the ip namespace.


#5

Sorry hard for me to explain. Here is the code i have written to solve this for me.

ci::ColorAf AlphaBlend(const ci::ColorAf& overlay, const ci::ColorAf& color)
{
ci::ColorAf result;

float fOverlayAlpha = overlay.a / 255.f;
float fColorAlpha = color.a / 255.f;

result.r = (int) (fOverlayAlpha * overlay.r + fColorAlpha * (1 - fOverlayAlpha) * color.r);
result.g = (int) (fOverlayAlpha * overlay.g + fColorAlpha * (1 - fOverlayAlpha) * color.g);
result.b = (int) (fOverlayAlpha * overlay.b + fColorAlpha * (1 - fOverlayAlpha) * color.b);
result.a = (int) (255.f * (fOverlayAlpha + fColorAlpha * (1 - fOverlayAlpha)));
return result;
}

I then do something like this. I convert from [0,1.0] scale to [0,255] scale, call AlphaBlend then convert back to [0,1.0]. Might be easier way to do this

ci::ColorAf finalColor1 = AlphaBlend(overlay, originalColor) / 255.f;
surface.setPixel(vPixelPos, finalColor);

#6

Hi,

why would you convert to [0, 255] scale? You can omit all that and just do:

ci::ColorA AlphaBlend( const ci::ColorA &overlay, const ci::ColorA &color )
{
    return color.lerp( overlay.a, overlay );
}

, because the lerp function can be used like this to do the alpha blending for you.

-Paul


#7

Tried this lerp function and it creates different results. The lerped color has much higher transparency while the color from the function i wrote doesn’t or it isn’t that noticeable.

I converted to 255 scale so i could recreate the alpha blending algorithm in the wikipedia https://en.wikipedia.org/wiki/Alpha_compositing#Description