Despeckle - remove spots or dots from the image

I am using Winforms. In my form, I have an image that displays a black and white image. I also have a button that, if you click on it, the button will delete points / points in the images. When the image size is small, it quickly removes stains. If the image is large, it takes some time. Also, sometimes this function removes some words from an image that it considers to be its stain. How can I improve the performance of this function and more accurately remove spots or dots, basically casting an image?

Update After researching, I found this library that seemed promising for this question:

http://www.aforgenet.com/framework/docs/html/cdf93487-0659-e371-fed9-3b216efb6954.htm

Link for the spotted image: http://www.filedropper.com/testing-image3

Image example

The note in the link has a larger version:

enter image description here

Image Information

It should be noted here that this is a black and white image - bit depth 1

enter image description here

My code

    private int[] mask = new int[9];
    private void remove_spot_btn_Click(object sender, EventArgs e)
    {
        Bitmap img = new Bitmap(pictureBox1.Image);
        Color c;

        for (int ii = 0; ii < img.Width; ii++)
        {
            for (int jj = 0; jj < img.Height; jj++)
            {

                if (ii - 1 >= 0 && jj - 1 >= 0)
                {
                    c = img.GetPixel(ii - 1, jj - 1);
                    mask[0] = Convert.ToInt16(c.R);
                }
                else
                {
                    mask[0] = 0;
                }

                if (jj - 1 >= 0 && ii + 1 < img.Width)
                {
                    c = img.GetPixel(ii + 1, jj - 1);
                    mask[1] = Convert.ToInt16(c.R);
                }
                else
                    mask[1] = 0;

                if (jj - 1 >= 0)
                {
                    c = img.GetPixel(ii, jj - 1);
                    mask[2] = Convert.ToInt16(c.R);
                }
                else
                    mask[2] = 0;

                if (ii + 1 < img.Width)
                {
                    c = img.GetPixel(ii + 1, jj);
                    mask[3] = Convert.ToInt16(c.R);
                }
                else
                    mask[3] = 0;

                if (ii - 1 >= 0)
                {
                    c = img.GetPixel(ii - 1, jj);
                    mask[4] = Convert.ToInt16(c.R);
                }
                else
                    mask[4] = 0;

                if (ii - 1 >= 0 && jj + 1 < img.Height)
                {
                    c = img.GetPixel(ii - 1, jj + 1);
                    mask[5] = Convert.ToInt16(c.R);
                }
                else
                    mask[5] = 0;

                if (jj + 1 < img.Height)
                {
                    c = img.GetPixel(ii, jj + 1);
                    mask[6] = Convert.ToInt16(c.R);
                }
                else
                    mask[6] = 0;


                if (ii + 1 < img.Width && jj + 1 < img.Height)
                {
                    c = img.GetPixel(ii + 1, jj + 1);
                    mask[7] = Convert.ToInt16(c.R);
                }
                else
                    mask[7] = 0;
                c = img.GetPixel(ii, jj);
                mask[8] = Convert.ToInt16(c.R);
                Array.Sort(mask);
                int mid = mask[4];
                img.SetPixel(ii, jj, Color.FromArgb(mid, mid, mid));
            }
        }

        pictureBox1.Image = img;
        MessageBox.Show("Complete");
    }
+4
source share
3 answers

As you have learned, using AForge.NET is a good idea (you just need to add it as nuget). I suggest you use a median filter , which is often used for noise reduction (see Media Filter on Wikipedia).

AForge 24- RGB-, , , , -, :

  // load the file as 24bpp RGB
  using (var bmp = LoadForFiltering(@"C:\temp\Testing-Image3.tif"))
  {
      var filter = new Median();

      // run the filter 
      filter.ApplyInPlace(bmp);

      // save the file back (here, I used png as the output format)
      bmp.Save(@"C:\temp\Testing-Image3.png");
  }


  private static Bitmap LoadForFiltering(string filePath)
  {
      var bmp = (Bitmap)Bitmap.FromFile(filePath);
      if (bmp.PixelFormat == PixelFormat.Format24bppRgb)
          return bmp;

      try
      {
          // from AForge sample code
          if (bmp.PixelFormat == PixelFormat.Format16bppGrayScale || Bitmap.GetPixelFormatSize(bmp.PixelFormat) > 32)
              throw new NotSupportedException("Unsupported image format");

          return AForge.Imaging.Image.Clone(bmp, PixelFormat.Format24bppRgb);
      }
      finally
      {
          bmp.Dispose();
      }
  }

, , , NVidia CUDA/NPP ( ), , # (, , NVidia). : 2D- CUDA CUDA : - CUDA

+2

, Bitmap , SetPixel, Bitmap.LockBits .

, , LockBits GetPixel SetPixel .


.. , . .

, , ( try/catch ), LockBits GetPixel SetPixel.

:

var bmp = new Bitmap(pictureBox1.Image);
var img = new LockBitmap(bmp);
img.LockBits();
Color c;
//...
//...
//...
img.UnlockBits();
pictureBox1.Image = bmp;
MessageBox.Show("Complete");

:

public class LockBitmap
{
    Bitmap source = null;
    IntPtr Iptr = IntPtr.Zero;
    BitmapData bitmapData = null;

    public byte[] Pixels { get; set; }
    public int Depth { get; private set; }
    public int Width { get; private set; }
    public int Height { get; private set; }

    public LockBitmap(Bitmap source)
    {
        this.source = source;
    }

    /// <summary>
    /// Lock bitmap data
    /// </summary>
    public void LockBits()
    {
        // Get width and height of bitmap
        Width = source.Width;
        Height = source.Height;

        // get total locked pixels count
        int PixelCount = Width * Height;

        // Create rectangle to lock
        Rectangle rect = new Rectangle(0, 0, Width, Height);

        // get source bitmap pixel format size
        Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);

        // Check if bpp (Bits Per Pixel) is 8, 24, or 32
        if (Depth != 8 && Depth != 24 && Depth != 32)
        {
            throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
        }

        // Lock bitmap and return bitmap data
        bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, 
                                     source.PixelFormat);

        // create byte array to copy pixel values
        int step = Depth / 8;
        Pixels = new byte[PixelCount * step];
        Iptr = bitmapData.Scan0;

        // Copy data from pointer to array
        Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);
    }

    /// <summary>
    /// Unlock bitmap data
    /// </summary>
    public void UnlockBits()
    {
        // Copy data from byte array to pointer
        Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);

        // Unlock bitmap data
        source.UnlockBits(bitmapData);
    }

    /// <summary>
    /// Get the color of the specified pixel
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    public Color GetPixel(int x, int y)
    {
        Color clr = Color.Empty;

        // Get color components count
        int cCount = Depth / 8;

        // Get start index of the specified pixel
        int i = ((y * Width) + x) * cCount;

        if (i > Pixels.Length - cCount)
            throw new IndexOutOfRangeException();

        if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
        {
            byte b = Pixels[i];
            byte g = Pixels[i + 1];
            byte r = Pixels[i + 2];
            byte a = Pixels[i + 3]; // a
            clr = Color.FromArgb(a, r, g, b);
        }
        if (Depth == 24) // For 24 bpp get Red, Green and Blue
        {
            byte b = Pixels[i];
            byte g = Pixels[i + 1];
            byte r = Pixels[i + 2];
            clr = Color.FromArgb(r, g, b);
        }
        if (Depth == 8)
        // For 8 bpp get color value (Red, Green and Blue values are the same)
        {
            byte c = Pixels[i];
            clr = Color.FromArgb(c, c, c);
        }
        return clr;
    }

    /// <summary>
    /// Set the color of the specified pixel
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="color"></param>
    public void SetPixel(int x, int y, Color color)
    {
        // Get color components count
        int cCount = Depth / 8;

        // Get start index of the specified pixel
        int i = ((y * Width) + x) * cCount;

        if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha
        {
            Pixels[i] = color.B;
            Pixels[i + 1] = color.G;
            Pixels[i + 2] = color.R;
            Pixels[i + 3] = color.A;
        }
        if (Depth == 24) // For 24 bpp set Red, Green and Blue
        {
            Pixels[i] = color.B;
            Pixels[i + 1] = color.G;
            Pixels[i + 2] = color.R;
        }
        if (Depth == 8)
        // For 8 bpp set color value (Red, Green and Blue values are the same)
        {
            Pixels[i] = color.B;
        }
    }
}
+4

9 . - . , ( ) .

0

Source: https://habr.com/ru/post/1671293/


All Articles