Reputation: 403
I got a binary Image(from EMGU) A and I want to get out a bitmap that is transparent everywhere where A is black and a transparent red everywhere, where A is white. For the beginning I wanted to at least make the black part invisible, which already failed:
I tried to do so by the following:
private Graphics graphics;
private Bitmap bitmap;
private Image<Gray, Byte> mask;
//graphic, bitmap and mask are being initialized in the constructor of the object
public Bitmap getMask()
{
//...
graphics.clear(Color.FromArgb(0,0,0,0);
graphics.DrawImage(mask.ToBitmap(), 0, 0);
bitmap.makeTransparent(255, 0, 0, 0);
//...
}
how do I do it with the white to red - part? is there a easier/more efficient way to do it maybe by using EMGU?
Upvotes: 0
Views: 828
Reputation: 3821
As an alternative to locking the bits and manipulating pixels one at a time (which is admittedly faster), you could also use a color transformation matrix to achieve the same affect. The matrix approach is fairly flexible, and your original image doesn't have to be perfect; this approach still works if the original image is noisy.
For your specific case (black => transparent, white => red/50%) the code would look like this:
using System.Drawing;
using System.Drawimg.Imaging;
...
// Original image to be transformed
var src = Image.FromFile(@"c:\temp\test.png");
// Destination image to receive the transformation
var dest = new Bitmap(src.Width, src.Height, PixelFormat.32bppArgb);
using (var g = Graphics.FromImage(dest))
{
var attr = new ImageAttributes();
float[][] matElements = {
new float[] { 0.0f, 0.0f, 0.0f, 0.5f, 0.0f },
new float[] { 0.0f, -1.0f, 0.0f, 0.0f, 0.0f },
new float[] { 0.0f, 0.0f, -1.0f, 0.0f, 0.0f },
new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
new float[] { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }
};
attr.SetColorMatrix(new ColorMatrix(matElements), ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
g.DrawImage(src, new Rectangle(0, 0, src.Width, src.Height), 0, 0,
src.Width, src.Height, GraphicsUnit.Pixel, attr);
}
From the color matrix above we get:
The new red value is calculated from the 1st column in the matrix. Green is calculated from the 2nd column, etc...
Upvotes: 1
Reputation: 54453
Here is a fast routine that should do what you asked for:
public static Bitmap MakeSpecialTransparent(Bitmap bmp)
{
// we expect a 32bpp bitmap!
var bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadWrite, bmp.PixelFormat);
long len = bmpData.Height * bmpData.Stride;
byte[] data = new byte[len];
Marshal.Copy(bmpData.Scan0, data, 0, data.Length);
for (int i = 0; i < len; i += 4)
{
if (data[i] == 0 && data[i+1] == 0 && data[i+2] == 0 )
{
data[i] = 0; data[i + 1] = 0; data[i + 2] = 0; data[i + 3] = 0;
}
else
if (data[i] == 255 && data[i+1] == 255 && data[i+2] == 255 )
{
data[i] = 0; data[i + 1] = 0; data[i + 2] = 255; data[i + 3] = 0;
}
}
Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
bmp.UnlockBits(bmpData);
return bmp;
}
Note that this a) expects the Bitmap
to come as 32bpp
images and b) does not have any tolerance: If the black & white pixels are not 100% black & white they will not be changed.
Also note that the physical pixels we address here, are ordered BGRA
, so data[i+3
] is the Alpha
channel, data[i+2]
is Red
etc..
To add tolerance you may want to study the linked post!
Upvotes: 1