-1

I'm trying to take a screenshot every 50 ms and remove all colors that are not similar to a color that I've decided in the beginning, but the part of code that check the color of every pixel is too slow, so in the end it do a screenshot almost every 1.5s... Here is the code:

public int upX = 114;
public int upY = 28;
public Size size = new Size(1137,640);
public Color rosa = Color.FromArgb(255, 102, 153);
public int tollerance = 20;

private void button1_Click(object sender, EventArgs e){
  button1.Enabled = false;
  do{
    Bitmap bmpScreenshot = screenshot();
    deleteColors(bmpScreenshot, rosa);
    picturebox1.image = bmpScreenshot;
    Application.DoEvents();
  } while (true);
}

public Bitmap screenshot() {
  Bitmap bmpScreenshot = new Bitmap(size.Width, size.Height, PixelFormat.Format16bppRgb555);
  Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
  gfxScreenshot.CopyFromScreen(upX, upY, 0, 0, size);
  return bmpScreenshot;
}

public void deleteColors(Bitmap bitmap, Color colorToSave) {
  for (int i = 0; i < bitmap.Width; i++){
    for (int j = 0; j < bitmap.Height; j++){
      Color c = bitmap.GetPixel(i, j);
      if (!colorsAreSimilar(c, colorToSave, tollerance)){
        bitmap.SetPixel(i, j, Color.White);
      }
     }
   }
 }

public bool colorsAreSimilar(Color a, Color b, int tollerance) {
  if (Math.Abs(a.R - b.R) < tollerance && Math.Abs(a.G - b.G) < tollerance && Math.Abs(a.B - b.B) < tollerance) {
    return true;
  }
  return false;
}

The screenshot part take 17 to 21ms, so it's already too high, but the delete part take 1300ms, so I'd like to fix that before, but... I don't know what i could do to make the code lighter.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Celeste Capece
  • 1,306
  • 2
  • 11
  • 20
  • 1
    One thing that jumps out at me is [`GetPixel` is slow](http://stackoverflow.com/q/24701703/1270789). – Ken Y-N Jan 31 '16 at 23:39
  • I would write it in C++, take screenshot and all, it would be faster. Then make it a dll and just call it from C#. You can use LockBits and write it in C#, but the program would become unsafe, which is generally not a good thing. – Antonín Lejsek Feb 01 '16 at 00:29

2 Answers2

3

Have you tried to use LockBit? It locks the bitmap in the system memory so you can have raw access to it, which is much faster than using the GetPixel and SetPixel methods.

var bmp = /* open your bitmap */
// The area you want to work on. In this case the full bitmap
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);
// Obtain a pointer to the data and copy it to a buffer
IntPtr ptr = bmpData.Scan0;
var buffer = new byte[Math.Abs(bmpData.Stride) * bmp.Height];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

for (int counter = 0; counter < rgbValues.Length; counter += 3)
{
    // Here you can edit the buffer
}

// Copy the data back to the bitmap and unlock it
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
bmp.UnlockBits(bmpData);

You can find another example of how to use it here.

mariosangiorgio
  • 5,520
  • 4
  • 32
  • 46
0

I strongly suggest not using GetPixel() and SetPixel() methods if you're concerned about performance.

Try writing your own GetPixel() and SetPixel(), for example using BitmapData:

        public static Color GetPixel(Bitmap bmp, int x, int y)
        {
            BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = bitmapData.Stride;
            Color c;
            unsafe
            {
                Byte* ptr = (byte*)bitmapData.Scan0;
                int red = ptr[(x * 3) + y * stride];
                int green = ptr[(x * 3) + y * stride + 1];
                int blue = ptr[(x * 3) + y * stride + 2];
                c = Color.FromArgb(red, green, blue);
            }
            bmp.UnlockBits(bitmapData);
            return c;
        }

        public static void SetPixel(Bitmap bmp, int x, int y, Color c)
        {
            BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = bitmapData.Stride;
            unsafe
            {
                Byte* ptr = (byte*)bitmapData.Scan0;
                ptr[(x * 3) + y * stride] = c.R;
                ptr[(x * 3) + y * stride + 1] = c.G;
                ptr[(x * 3) + y * stride + 2] = c.B;
            }
            bmp.UnlockBits(bitmapData);
        }
Eutherpy
  • 4,471
  • 7
  • 40
  • 64