C#在搜索图像中的像素时for循环性能低下

标签 c# visual-studio image for-loop

当我使用下面的代码时,如果在图像中找不到我要搜索的图像,则循环完成大约需要 3-5 秒。在搜索程序的其余部分暂停时,我的计时器不同步,程序似乎卡住了几秒钟。图片不是很大,“printscreen”大约是 344x354,“Ok”大约是 15x7。我知道这是因为 for 循环,但是有没有更好的方法来做到这一点,或者我可以以某种方式在程序的其余部分之外运行他的程序部分,这样程序就不会卡住几秒钟.

// Ok is the image I am searching for.
// printscreen is the image I am searching in.

Bitmap Ok = new Bitmap(Properties.Resources.popupok1);
int Count = 0;
for (int x = 0; x < printscreen.Width; x++)
{
    for (int y = 0; y < printscreen.Height; y++)
    {
        Count = 0;
        if (printscreen.GetPixel(x, y) == Ok.GetPixel(0, 0) && 
            printscreen.GetPixel(x + 1, y) == Ok.GetPixel(1, 0))
        {
            for (int OkX = 0; OkX <= Ok.Width; OkX++)
            {
                for (int OkY = 0; OkY <= Ok.Height; OkY++)
                {
                    try
                    {
                        if (printscreen.GetPixel(x + OkX, y + OkY) != Ok.GetPixel(OkX, OkY))
                        {
                            OkX = Ok.Width;
                            OkY = Ok.Height;
                        }
                        else
                        {
                            Count += 1;
                        }
                        if (Count == 105)
                        {
                            X = x;
                            Y = y;
                            OkX = Ok.Width;
                            OkY = Ok.Height;
                            x = printscreen.Width - 1;
                            y = printscreen.Height - 1;
                            Console.Add("Ok button found.");
                            Console.Add("");
                            ConsoleUpdate();
                        }
                    }
                    catch { }
                }
            }
        }
    }
}

最佳答案

性能问题是由 GetPixels/SetPixels 引起的,这是一种访问 .NET 位图中数据的极其缓慢的方法。相反,我会查看 Bitmap.LockBits 方法以获取指向位图的指针并直接操作数据。这将快一个数量级。

参见 MSDN :

The following code example demonstrates how to use the PixelFormat, Height, Width, and Scan0 properties; the LockBits and UnlockBits methods; and the ImageLockMode enumeration. This example is designed to be used with Windows Forms. To run this example, paste it into a form and handle the form's Paint event by calling the LockUnlockBitsExample method, passing e as PaintEventArgs.

private void LockUnlockBitsExample(PaintEventArgs e)
{

    // Create a new bitmap.
    Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");

    // Lock the bitmap's bits.  
    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);

    // Get the address of the first line.
           IntPtr ptr = bmpData.Scan0;

    // Declare an array to hold the bytes of the bitmap.
    // This code is specific to a bitmap with 24 bits per pixels.
    int bytes = bmp.Width * bmp.Height * 3;
    byte[] rgbValues = new byte[bytes];

    // Copy the RGB values into the array.
    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

    // Set every red value to 255.  
    for (int counter = 2; counter < rgbValues.Length; counter+=3)
        rgbValues[counter] = 255;

    // Copy the RGB values back to the bitmap
    System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

    // Unlock the bits.
    bmp.UnlockBits(bmpData);

    // Draw the modified image.
    e.Graphics.DrawImage(bmp, 0, 150);

}

如果你想走得更快而不是复制数组,操作它然后复制回来,你可以使用不安全指针在位图上操作。在这种情况下,内部部分将更改如下:

    // Lock the bitmap's bits.  
    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);

    // Get the address of the first line.
    IntPtr ptr = bmpData.Scan0;

    // Declare an array to hold the bytes of the bitmap.
    // This code is specific to a bitmap with 24 bits per pixels.
    int bytes = bmp.Width * bmp.Height * 3;
    unsafe
    {
        byte* rgbValues = (byte*)ptr;

        // Set every red value to 255.  
        for (int counter = 2; counter < bytes counter+=3)
            rgbValues[counter] = 255;
    } 

    // Unlock the bits.
    bmp.UnlockBits(bmpData);

只需注意位图的 PixelFormat。上面的示例假定其每像素 BGR 为 24 位。事实上,许多位图都是 BGRA(每像素 32 位),因此您需要按每个像素的顺序为蓝色、绿色、红色、Alpha 修改四个字节。

关于C#在搜索图像中的像素时for循环性能低下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9479331/

相关文章:

visual-studio-2010 - 在 Visual Studio 中运行应用程序时,对 Access 数据库的更改不会持续存在

c# - ASP.NET MVC 2 不显示 CSS 文件中的图像

c# - 从流中加载图像而不保持流打开

Android:BitmapFactory 在从 ByteArray 解码时更改图像的尺寸

java - 在C#中使用Androidjavaobject将二维数组传输到Java是可能的吗?并且也返回

c# - 在 WPF 滚动查看器中的文本框控件上启用滑动滚动

C# 获取光标处的控制权

c# - 如何调整 Windows 图标覆盖的大小?

c# - 当前不会命中 VS 2010 远程调试器断点。没有为该文档加载任何符号

c++ - 内联函数的gtest问题