0

Given an image, I want to convert its pixels nearby a specified color, like Color.FromArgb(210, 189, 51), to transparent area.

I tried this:

public Bitmap MakeTransparent(Image image,Color clr)
{
    Bitmap b = new Bitmap(image);

    var replacementColour = Color.FromArgb(255, 255, 255);
    var tolerance = 1;

    for (int i = b.Size.Width - 1; i >= 0; i--)
    {
        for (int j = b.Size.Height - 1; j >= 0; j--)
        {
            var col = b.GetPixel(i, j);

            if (clr.R - col.R < tolerance &&
                clr.G - col.G < tolerance &&
                clr.B - col.B < tolerance)
            {
                b.SetPixel(i, j, replacementColour);
            }
        }
    }

    b.MakeTransparent(replacementColour);

    return b;
}

But the result is wrong.

Orace
  • 7,822
  • 30
  • 45
Merbin Joe
  • 611
  • 6
  • 27

1 Answers1

1

You should learn about metrics.

Anyway, if bad colors are converted it's obviously due to your test:

if (clr.R - col.R < tolerance && clr.G - col.G < tolerance && clr.B - col.B < tolerance)

If clr is say (100,100,100) (light gray) any color with RGB less than 99 will pass the test. Like (75,57,37) (dark shitty brown)...

You may use Math.Abs:

if (Math.Abs(clr.R - col.R) < tolerance &&
    Math.Abs(clr.G - col.G) < tolerance &&
    Math.Abs(clr.B - col.B) < tolerance)

As a remark, if tolerance is 1 you check for Math.Abs(d) < 1 which is equivalent to d == 0. So if tolerance is 1, you actually check for color equality.

You may use:

if (Math.Abs(clr.R - col.R) <= tolerance &&
    Math.Abs(clr.G - col.G) <= tolerance &&
    Math.Abs(clr.B - col.B) <= tolerance)

In this case, you check for color equality when tolerance is equal to 0.

Also, you should directly set the matching pixels to transparent instead of set it to white and use your previous function:

var replacementColour = Color.Transparent;

...  // for loops

if (Math.Abs(clr.R - col.R) < tolerance &&
    Math.Abs(clr.G - col.G) < tolerance &&
    Math.Abs(clr.B - col.B) < tolerance)
{
    b.SetPixel(i, j, replacementColour);
}

Doing this may not be the good way, as color distances is a big subject. You should learn about that:

Community
  • 1
  • 1
Orace
  • 7,822
  • 30
  • 45
  • This is just work like if(clr==col), it is only convert the exact color only not near all colors. – Merbin Joe Apr 08 '15 at 10:25
  • It tolerance is `1` indeed you check for equality. You may use `<=` instead of `<` or use a bigger tolerance to capture more colors. – Orace Apr 08 '15 at 10:49
  • great it works. Can you suggest what is the min and max limit for tolerance? – Merbin Joe Apr 08 '15 at 10:58
  • `Math.Abs(clr.X - col.X)` is in `[0, 255]`. If you use `<`, `tolerance` make sense in [0, 256] (0 for never convert, 256 for always convert). If you use `<=` it will be [-1, 255] (-1 for never, 255 for always). But this is a scholar question and ask for a response on SO doesn't help you. – Orace Apr 08 '15 at 11:12
  • If I use use upto 255 it is not recommended right, because all colors will convert to transparent so only I asked this. – Merbin Joe Apr 08 '15 at 11:31