TransparencyExtract

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.

TransparencyExtract app

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.