2

In C#, how do I generate a binary mask which has no gray values/noise in the image?

Right now I am able to generate a fairly simple output which looks very close to what I want but has noise around the edges both inside and outside of the white blob (You need to zoom all the way in to see the noise). I am planning to use the image later for image processing but cannot have anything other than black and white values in the image.

Pictures: Crop 1 Crop 2

Code:

    public CropedImage(List<Node> nodes)
    {
        InitializeComponent();
        //List<PointF> listpoints = new List<PointF>();
        nodes.ToArray();
        PointF[] points = new PointF[nodes.Count];
        for(int i = 0; i < nodes.Count; ++i)
        {
            points[i].X = nodes[i].X;
            points[i].Y = nodes[i].Y;
        }

        Image SourceImage = ImageOperations.GetImage(MainForm.imageMatrix, pictureBox1);

        using (Graphics g = Graphics.FromImage(SourceImage))
        {
            Color black = ColorTranslator.FromHtml("#000000");
            Color white = ColorTranslator.FromHtml("#FFFFFF");


            using (Brush b = new SolidBrush(black))
            {
                Rectangle rect = new Rectangle();
                g.FillRectangle(b, 0, 0, MainForm.WIDTH, MainForm.HEIGHT);
            }
            using (Brush b2 = new SolidBrush(white))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.FillClosedCurve(b2, points, 0);
            }
        }

    }
Telahun
  • 25
  • 4
  • Just run through every pixel and round its value to white or black. – eocron Oct 01 '18 at 19:21
  • [Here](https://stackoverflow.com/questions/33189112/remove-the-black-background-color-of-a-bitmap/33191068#33191068) is a function and a link; use the function in the linked code for a fast solution.. - If sped is not so importants do this: double loop over the x*y pixels, getpixel&getbrightness then setpixel.. – TaW Oct 01 '18 at 19:26
  • If you're using antialiasing, it's expected that you get gray values when you draw white on black (or vice-versa). That's exactly what Antialiasing is about. Try `SmoothingModeNone` instead. – PMF Oct 01 '18 at 19:47

2 Answers2

2

How about changing

g.SmoothingMode = SmoothingMode.AntiAlias;

to

g.SmoothingMode = SmoothingMode.None;

If I understand correctly, that would solve your problem.

Zombie
  • 41
  • 2
1

As eocron said you have to check all the pixels and round them to black or white. the most simple way of doing it (if only you are creating a temp application to do this for a few images) is to use GetPixel() and SetPixel() methods:

Bitmap bmp = Bitmap.FromFile("image.png");
for(int i=0;i<bmp.Width;i++)
   for(int j=0;j<bmp.Height;j++)
      bmp.SetPixel(i,j, bmp.GetPixel(i,j).R > 127? Color.White: Color.Black); // as its gray I'm only checking Red

However if you are dealing with lots of images especially large ones, or its not a temp application to deal with a few images, and its going to be a feature of your application, the above code is not what you would like to use as it is very slow, and you should use LockBits as it is way faster:

 Bitmap bmp = Bitmap.FromFile("image.png"); 
 Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
 System.Drawing.Imaging.BitmapData bmpData = 
 bmp.LockBits(rect,System.Drawing.Imaging.ImageLockMode.ReadWrite,bmp.PixelFormat;
 IntPtr ptr = bmpData.Scan0;
 int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;
 byte[] rgbValues = new byte[bytes];
 System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
 for (int counter = 0; counter < rgbValues.Length; counter += 4)
 {
    int c = rgbValues[counter] > 127 ? 255: 0;
    rgbValues[counter] = c;
    rgbValues[counter+1] = c;
    rgbValues[counter+2] = c;
 }
 System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
 bmp.UnlockBits(bmpData);
Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
  • 1
    This seems like this will be the right fix. I was looking for a way to solve this using one of the GDI+ wrapper functions but this appears to handle the problem the right way. I will mark it as the answer when I am able to implement this. Thanks Ashkan and eocron – Telahun Oct 01 '18 at 21:47
  • @Telahun I'm glad I could help. & Thanks – Ashkan Mobayen Khiabani Oct 02 '18 at 05:20