检查颜色相似性算法太慢

本文关键字:算法 相似性 颜色 检查 | 更新日期: 2023-09-27 18:32:49

我试图每 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 毫秒,所以我想之前解决这个问题,但是......我不知道我能做些什么来使代码更轻。

检查颜色相似性算法太慢

你试过用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);

您可以在此处找到如何使用它的另一个示例。

如果您担心性能,我强烈建议不要使用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);
        }