如何在 C# 中快速捕获位图数据
How can I capture bitmap data very quickly in C#
我的目标是能够获取一行 70 个像素,分析所有 70 个像素的某种颜色,然后在满足条件时将其扔给另一个函数。这需要至少每 50 毫秒发生一次,最好比这更快。
我当前的代码是这样的
public void CaptureArea()
{
using (Bitmap capture = new Bitmap(70, 35))
{
using (Graphics g = Graphics.FromImage(capture))
{
for (int i = 0; i < 10; i++)
{
g.CopyFromScreen(copyPoint, pastePoint, new Size(70, 35));
evaluteBitmap(capture);
}
}
}
}
public void evaluteBitmap(Bitmap scanArea)
{
Rectangle rect = new Rectangle(0, 0, 70, 35);
BitmapData data = scanArea.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
IntPtr ptr = data.Scan0;
int bytes = data.Stride * scanArea.Height;
byte[] rgbValues = new byte[bytes];
byte[] r = new byte[bytes / 3];
byte[] g = new byte[bytes / 3];
byte[] b = new byte[bytes / 3];
Marshal.Copy(ptr, rgbValues, 0, bytes);
int count = 0;
int stride = data.Stride;
for (int column = 0; column < 30; column++)
{
b[count] = (byte)(rgbValues[(column * stride) + (34 * 3)]);
g[count] = (byte)(rgbValues[(column * stride) + (34 * 3) + 1]);
r[count++] = (byte)(rgbValues[(column * stride) + (34 * 3) + 2]);
}
scanArea.UnlockBits(data);
}
仅 CaptureArea() 每秒可以将大约 60 个位图放入内存,这很好,但 EvaluateBitmap() 目前需要大约 600 毫秒来抓取一个像素并将其拆分为 RGB 值 70 次。
最终的结果是单帧数据在需要更接近 50 毫秒的情况下需要花费 500 多毫秒来处理。这种问题的解决超出了我的范围,我对这种性质的代码没有足够的经验,无法眼球解决方案并知道最终会更快或更慢的速度以及速度。
有没有办法让我的性能提高一个数量级,或者我是在问不可能的事情?
给定代码的分析会话给出了明确的结果:
CopyFromScreen - 40.00% exclusive samples
Bitmap..ctor - 15.00% exclusive samples
clr.dll - 11.67% exclusive samples
KernelBase.dll - 8.33% exclusive samples
GdiPlus.dll - 6.67% exclusive samples
LockBits - 6.67% exclusive samples
Image.Dispose - 5.00% exclusive samples
....
....
EvaluateBitmap - 1.67% exclusive samples
....
....
CaptureArea - 0.0% exclusive samples
大部分时间花在无法改进的 .NET 方法上。
结论:代码没有明显的改进。
不过,您或许可以使用多线程在给定时间段内处理更多帧。
我的目标是能够获取一行 70 个像素,分析所有 70 个像素的某种颜色,然后在满足条件时将其扔给另一个函数。这需要至少每 50 毫秒发生一次,最好比这更快。
我当前的代码是这样的
public void CaptureArea()
{
using (Bitmap capture = new Bitmap(70, 35))
{
using (Graphics g = Graphics.FromImage(capture))
{
for (int i = 0; i < 10; i++)
{
g.CopyFromScreen(copyPoint, pastePoint, new Size(70, 35));
evaluteBitmap(capture);
}
}
}
}
public void evaluteBitmap(Bitmap scanArea)
{
Rectangle rect = new Rectangle(0, 0, 70, 35);
BitmapData data = scanArea.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
IntPtr ptr = data.Scan0;
int bytes = data.Stride * scanArea.Height;
byte[] rgbValues = new byte[bytes];
byte[] r = new byte[bytes / 3];
byte[] g = new byte[bytes / 3];
byte[] b = new byte[bytes / 3];
Marshal.Copy(ptr, rgbValues, 0, bytes);
int count = 0;
int stride = data.Stride;
for (int column = 0; column < 30; column++)
{
b[count] = (byte)(rgbValues[(column * stride) + (34 * 3)]);
g[count] = (byte)(rgbValues[(column * stride) + (34 * 3) + 1]);
r[count++] = (byte)(rgbValues[(column * stride) + (34 * 3) + 2]);
}
scanArea.UnlockBits(data);
}
仅 CaptureArea() 每秒可以将大约 60 个位图放入内存,这很好,但 EvaluateBitmap() 目前需要大约 600 毫秒来抓取一个像素并将其拆分为 RGB 值 70 次。
最终的结果是单帧数据在需要更接近 50 毫秒的情况下需要花费 500 多毫秒来处理。这种问题的解决超出了我的范围,我对这种性质的代码没有足够的经验,无法眼球解决方案并知道最终会更快或更慢的速度以及速度。
有没有办法让我的性能提高一个数量级,或者我是在问不可能的事情?
给定代码的分析会话给出了明确的结果:
CopyFromScreen - 40.00% exclusive samples
Bitmap..ctor - 15.00% exclusive samples
clr.dll - 11.67% exclusive samples
KernelBase.dll - 8.33% exclusive samples
GdiPlus.dll - 6.67% exclusive samples
LockBits - 6.67% exclusive samples
Image.Dispose - 5.00% exclusive samples
....
....
EvaluateBitmap - 1.67% exclusive samples
....
....
CaptureArea - 0.0% exclusive samples
大部分时间花在无法改进的 .NET 方法上。
结论:代码没有明显的改进。 不过,您或许可以使用多线程在给定时间段内处理更多帧。