检查颜色相似度算法太慢了

时间:2016-01-31 23:27:53

标签: c# .net image-processing

我尝试每隔50毫秒拍摄一次屏幕截图并删除与我在开始时决定的颜色不相似的所有颜色,但检查每个像素颜色的代码部分太慢了,所以最后它几乎每1.5秒做一次截图... 这是代码:

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;
}

屏幕截图部分需要17到21毫秒,所以它已经太高了,但是删除部分需要1300毫秒,所以我以前想修复它,但是......我不知道知道我能做些什么来使代码变得更轻。

2 个答案:

答案 0 :(得分:3)

您是否尝试过使用LockBit?它将位图锁定在系统内存中,因此您可以对其进行原始访问,这比使用GetPixelSetPixel方法快得多。

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);

您可以找到另一个如何使用它的示例here

答案 1 :(得分:0)

如果您担心效果,我强烈建议您不要使用GetPixel()SetPixel()方法。

尝试编写自己的GetPixel()SetPixel(),例如使用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);
        }