首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c#在for循环中搜索图像像素时性能较低

c#在for循环中搜索图像像素时性能较低
EN

Stack Overflow用户
提问于 2012-02-28 17:24:59
回答 5查看 1.6K关注 0票数 4

当我使用下面的代码时,如果我在图像中搜索的图像没有找到,那么在循环完成之前大约需要3-5秒。在搜索时,程序的其余部分被暂停,我的计时器变得不同步,看起来程序冻结了几秒钟。图像不是很大,"printscreen“大约是344x354,"Ok”大约是15x7。我知道这是因为for -循环,但有没有更好的方法来做这件事,或者我可以在程序的其余部分之外以某种方式运行他的部分,这样程序就不会死机几秒钟。

代码语言:javascript
复制
// 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 { }
                }
            }
        }
    }
}
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-02-28 17:31:19

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

请参阅MSDN

下面的代码示例演示如何使用PixelFormat、Height、Width和Scan0属性;LockBits和UnlockBits方法;以及ImageLockMode枚举。此示例旨在与Windows窗体一起使用。要运行此示例,请将其粘贴到窗体中,并通过将e作为PaintEventArgs传递给LockUnlockBitsExample方法来处理窗体的Paint事件。

代码语言:javascript
复制
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);

}

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

代码语言:javascript
复制
    // 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即可。上面的例子假设它是每像素24位的BGR。事实上,许多位图都是BGRA (每像素32位),因此您需要按每像素的顺序修改Blue、Gree、Red、Alpha的四个字节。

票数 11
EN

Stack Overflow用户

发布于 2012-02-28 17:36:37

使用新的线程处理图像,你的程序在处理Threading时不会死机

票数 2
EN

Stack Overflow用户

发布于 2012-02-28 17:36:45

这看起来像是饥饿算法。再考虑一次,定义一些点,在那里你可以安全地离开函数。例如,在后面添加return

代码语言:javascript
复制
Console.Add("Ok button found.");
Console.Add("");
ConsoleUpdate();
return;

我相信你可以找到更多的点,你可以离开,因为你可以肯定,没有更多的东西要找到,或者为什么你已经找到了你正在寻找的东西,但仍在完成你的周期?

或者你可以用一种不同的方式设置它。你可以从扫描图片的第一个像素开始,在找到它之后,你可以检查第二个,第三个,等等,如果第三个像素不正确,你需要返回并继续。

因此,如果没有一个像素是正确的,那么您将只浏览图片一次。

换句话说,不要尝试比较两个x*y区域,先尝试比较像素,然后再比较区域。您应该能够显著减少时间。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9479331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档