27

I am trying to do an alpha blend operation of an RGBA image (foreground image), on to a RGB image (background image). However, while doing so I think I may be doing the wrong alpha blending operation or doing it wrong. For example, the pixel of my RGB image is a grayish color of (127, 127, 127). The pixel of my RGBA image for the pixel will be (0, 0, 255). After I do my blending operation, the final color will be (127, 0, 255). However, I thought that was more of an additive blend and different than the operation I am doing.

For how my values are set, take a look at this

incPixelColor[0] = 0; (red)
incPixelColor[1] = 0; (green)
incPixelColor[2] = 255; (blue)
incPixelColor[3] = 255; (alpha)

currentPixelColor[0] = 127; (red)
currentPixelColor[1] = 127; (green)
currentPixelColor[2] = 127; (blue)

For how my calculation is set, take a look at this

float incAlpha = (currentPixelColor[3]/255.0f);

float red = ((float)incPixelColor[0]/255.0f * incAlpha) + ((float)currentPixelColor[0]/255.0f);
float green = ((float)incPixelColor[1]/255.0f * incAlpha) + ((float)currentPixelColor[1]/255.0f);
float blue = ((float)incPixelColor[2]/255.0f * incAlpha) + ((float)currentPixelColor[2]/255.0f);


currentPixelColor[0] = min(red * 255, 255.0f);
currentPixelColor[1] = min(green * 255, 255.0f);
currentPixelColor[2] = min(blue * 255, 255.0f);

For pixels with no alpha, I would like for the value to be (0, 0, 255) then for images with alpha I would like for it to blend in. At the end of the operation above, it will be (127, 127, 255). Should I check to see if there is alpha for every pixel, and if so, then do the blend or is there another way to do this?

mmurphy
  • 1,327
  • 4
  • 15
  • 30
  • You're doing additive blending. Consider linear mixing like this: y = (x0 * w) + (x1 * (1-w)) – Osman Turan Jan 26 '12 at 12:04
  • 1
    That's a lot of 255 scaling back and forth. It should not be necessary if your operations maintain normalization. – fche Jan 26 '12 at 15:36
  • Please check my explanation here: https://stackoverflow.com/a/73498765/2299100 – Slyv Aug 26 '22 at 09:25

2 Answers2

32

A typical "Over" blend is done in the following way:

outputRed = (foregroundRed * foregroundAlpha) + (backgroundRed * (1.0 - foregroundAlpha));

And then repeating for the blue and green channels. Do this for every pixel.

user1118321
  • 25,567
  • 4
  • 55
  • 86
  • Perhaps I am mistaken, but isn't that what I am already doing? – mmurphy Jan 26 '12 at 07:33
  • No, what you're doing is outputRed = (foreRed * foreAlpha) + backgroundRed. You need to multiply the backgroundRed by the (1.0 - foreAlpha). – user1118321 Jan 26 '12 at 16:46
  • Sorry that so late, but what happens to the alpha output alpha channel if both destination and source pixels are transparent? – Vlas Bashynskyi Jul 28 '14 at 09:40
  • It ends up transparent, too. So if you have a source pixel with 0% coverage (alpha), it shouldn't contribute to the output. If you overlay that on a pixel with 0% coverage, the background also shouldn't contribute to the output. So the result will be RGBA = (0,0,0,0). It will be "transparent black" so to speak. If you overlay the result on something that's not transparent, you'll see whatever you overlaid it on. – user1118321 Jul 28 '14 at 16:07
  • Does this assume that foregroundAlpha is in the 0-255 range or 0-1 range? – Julian Aug 09 '16 at 05:06
  • It assume alpha is in the 0-1 range. – user1118321 Aug 10 '16 at 00:51
  • This formular makes a 50% red on white background into a `rgb(255, 128, 128)` which is mathematically correct. Under macOS I notice Chrome, Safari and even Sketch App blend that setup into `rgb(255, 138, 138)`. Firefox `rgb(255, 126, 124)`. Photoshop sticks to the 128 though. So interestingly some software takes extra steps for whatever reasons and 50% red is not universally 50% red Pen: https://codepen.io/timohausmann/pen/rNLdpwJ?editors=0100 macOS Screenshot: https://imgur.com/a/2ioPPiy – Ti Hausmann Oct 30 '20 at 16:30
2

It seems that you have missed out (1-Alpha) multiplier for background (currentPixelColor)

MBo
  • 77,366
  • 5
  • 53
  • 86