TransparencyExtract
Mar 1 2011 ยท Graphics and Rendering
A long while ago, I wrote a post on a method to extract transparency from images with solid-colored backgrounds, and somewhat effectively reduce the halo effect around objects in the image. I never got around to releasing the code or application, which I’m finally doing now.
All code + app is here.
It’s in C# + WinForms, and I put the entire VS solution in the bitbucket repo.
The guts of it all is the PerformExtraction() function in TransparencyExtract.cs
public void PerformExtraction()
{
    ColorF bgColorF = new ColorF(backgroundColor);
    ColorF fgColorF = new ColorF(foregroundColor);
    float backL = bgColorF.L();
    float foreL = fgColorF.L();
    float minL = Math.Min(backL, foreL);
    float deltaL = Math.Max(backL, foreL) - minL;
    newBitmap = new Bitmap(srcBmp.Width, srcBmp.Height, PixelFormat.Format32bppArgb);
            
    BitmapData bdDest = newBitmap.LockBits(new Rectangle(0, 0, newBitmap.Width, newBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, newBitmap.PixelFormat);
    IntPtr ptrDest = bdDest.Scan0;
    BitmapData bd = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, srcBmp.PixelFormat);
    IntPtr ptr = bd.Scan0;
    int bpp = 4;
    int bytes = srcBmp.Height * bd.Stride;
    byte[] rgbValues = new byte[bytes];
    byte[] rgbValuesDest = new byte[bytes];
    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
    System.Runtime.InteropServices.Marshal.Copy(ptrDest, rgbValuesDest, 0, bytes);
    Array.Copy(rgbValues, rgbValuesDest, rgbValues.Length);
    for (int y = 0; y < srcBmp.Height; y++)
    {
        for (int x = 0; x < srcBmp.Width; x++)
        {
            int idx = (x * bpp + y * bd.Stride);
            ColorF cf = new ColorF(Color.FromArgb(rgbValues[idx + 3], rgbValues[idx + 2], rgbValues[idx + 1], rgbValues[idx]));
            // scale from [minL, 1] -> [0,1] 
            float scaleUpCoeff = 1.0f / deltaL;
            float ld = (cf.L() - minL) * scaleUpCoeff;
            if (ld > 1.0f)
                ld = 1.0f;
            if (ld < 0.0f)
                ld = 0.0f;
            float alpha = 1.0f - ld;
            rgbValuesDest[idx+3] = (byte)(alpha * 255.0f); // this is the alpha
        }
    }
    System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
    System.Runtime.InteropServices.Marshal.Copy(rgbValuesDest, 0, ptrDest, bytes);
    srcBmp.UnlockBits(bd);
    newBitmap.UnlockBits(bdDest);
}
Note, this is not a generic algorithm by any means; read my original post to understand what’s going on and the limitations of this method.










