So, I looked at the GIMP source code ... ew! I made it general and readable. However, pretty fast. For an explanation of math, see Sampo's answer . Here's the C # implementation (easily converted to C / C ++):
static class PixelShaders { /// <summary> /// Generic color space color to alpha. /// </summary> /// <param name="pA">Pixel alpha.</param> /// <param name="p1">Pixel 1st channel.</param> /// <param name="p2">Pixel 2nd channel.</param> /// <param name="p3">Pixel 3rd channel.</param> /// <param name="r1">Reference 1st channel.</param> /// <param name="r2">Reference 2nd channel.</param> /// <param name="r3">Reference 3rd channel.</param> /// <param name="mA">Maximum alpha value.</param> /// <param name="mX">Maximum channel value.</param> static void GColorToAlpha(ref double pA, ref double p1, ref double p2, ref double p3, double r1, double r2, double r3, double mA = 1.0, double mX = 1.0) { double aA, a1, a2, a3; // a1 calculation: minimal alpha giving r1 from p1 if (p1 > r1) a1 = mA * (p1 - r1) / (mX - r1); else if (p1 < r1) a1 = mA * (r1 - p1) / r1; else a1 = 0.0; // a2 calculation: minimal alpha giving r2 from p2 if (p2 > r2) a2 = mA * (p2 - r2) / (mX - r2); else if (p2 < r2) a2 = mA * (r2 - p2) / r2; else a2 = 0.0; // a3 calculation: minimal alpha giving r3 from p3 if (p3 > r3) a3 = mA * (p3 - r3) / (mX - r3); else if (p3 < r3) a3 = mA * (r3 - p3) / r3; else a3 = 0.0; // aA calculation: max(a1, a2, a3) aA = a1; if (a2 > aA) aA = a2; if (a3 > aA) aA = a3; // apply aA to pixel: if (aA >= mA / mX) { pA = aA * pA / mA; p1 = mA * (p1 - r1) / aA + r1; p2 = mA * (p2 - r2) / aA + r2; p3 = mA * (p3 - r3) / aA + r3; } else { pA = 0; p1 = 0; p2 = 0; p3 = 0; } } }
The GIMP implementation ( here ) uses the RGB color space, uses the alpha value as a float
with a range from 0 to 1, and R, G, B as a float
from 0 to 255.
An RGB implementation is inefficient when the image has JPEG artifacts because they mean slight perceptible color deviations, but rather significant absolute deviations of R, G, B. Using the LAB color space should do the trick for the case.
If you just want to remove a solid background from an image, a color alpha algorithm is not the best option. I got good results when I calculated the color space for each pixel using a LAB color. The calculated distance was then applied to the alpha channel of the original image. The main difference between this and the color in alpha is that the shades of the pixels will not be changed. Background deletion simply sets the alpha (opacity) to the color difference. It works well if the background color is not displayed in the foreground. If it cannot remove the background, or use the BFS algorithm to use only external pixels (something like using the magic wand selection in GIMP and then removing the selection).
The background cannot be removed if the foreground image has both holes and pixels in color similar to the background color. Such images require some manual processing.