[英]Degrade performance of C# for-loop for bigger range over C for-loop
[英]c# Low performance in for-loop while searching pixels in image
當我使用下面的代碼時,如果找不到我在圖像中搜索的圖像,則在完成循環之前大約需要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 :
以下代碼示例演示如何使用PixelFormat,Height,Width和Scan0屬性; LockBits和UnlockBits方法; 和ImageLockMode枚舉。 此示例旨在與Windows窗體一起使用。 要運行此示例,請將其粘貼到表單中,並通過調用LockUnlockBitsExample方法處理表單的Paint事件,並將e作為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四個字節。
使用新的新線程來處理圖像,你的程序在處理線程時不會凍結
這看起來像飢餓的algorytm。 再考慮一下並定義點,您可以放心地離開該功能。 例如,之后添加返回
Console.Add("Ok button found.");
Console.Add("");
ConsoleUpdate();
return;
我相信你可以找到更多可以離開的地方,因為你可以肯定,沒有什么可以找到的,或者你為什么要完成你的周期,即使你已經找到了你想要的東西?
或者也許你可以用不同的方式進行設置。 您可以從第一個像素掃描圖片開始,找到后,您可以檢查第二個,第三個像素等,如果第三個像素不正確,則需要返回並繼續。
因此,如果連一個像素都不正確,那么您只需要瀏覽一次。
換句話說,不要試圖比較兩個x * y區域,嘗試先比較像素,稍后再區域。 你應該能夠顯着減少時間。
我對圖像處理一無所知,你的問題似乎很普遍,有人可能已經開發了一個特定的算法。 但是,如果沒有,這是我的兩分錢:你的算法運行緩慢並不奇怪,如果兩個圖像的大小為W1xH1和W2xH2,那么在最壞的情況下你的運行時間是O(W1.H1.W2.H2)
。 平均情況要少得多,但仍然不夠快。
在字符串中搜索子字符串是您的任務的一維模擬,這是一個很好的研究問題。 您可能需要檢查Boyer-Moore字符串搜索算法,看看是否可以根據您的問題調整基本思路。
我在http://www.tmorley.net上放了一些初學者的教程。 這些解釋了使用C#的圖像處理。 首先要做的是圖像文件(jpg,bmp等)立即將像素數據提取到數組中。 可以快速完成處理,然后將結果放回到位圖中以顯示或保存到光盤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.