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.