Salocin
Salocin

Reputation: 403

C# get from binary Image to transparent Bitmap

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

Answers (2)

RogerN
RogerN

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:

  • New red value = 1
  • New green value = 1 - old green value
  • New blue value = 1 - old blue value
  • New alpha value = 0.5 * old red value

The new red value is calculated from the 1st column in the matrix. Green is calculated from the 2nd column, etc...

Upvotes: 1

TaW
TaW

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

Related Questions