【发布时间】:2015-08-25 10:00:40
【问题描述】:
我正在编写一个 Visual Basic 应用程序,它会截取桌面的屏幕截图并将其裁剪为围绕屏幕中心的 200 像素 x 200 像素的图像。应用程序的一部分将遍历每个像素并检查该像素的 RGB 是否是某种颜色(这意味着它需要不到一秒钟才能有效),不幸的是 Bitmap.Getpixel 对我没有任何好处是否通过 Bitmap.Lock 加载到内存中。
有没有更快(几乎是即时)的方法?谢谢。
【问题讨论】:
我正在编写一个 Visual Basic 应用程序,它会截取桌面的屏幕截图并将其裁剪为围绕屏幕中心的 200 像素 x 200 像素的图像。应用程序的一部分将遍历每个像素并检查该像素的 RGB 是否是某种颜色(这意味着它需要不到一秒钟才能有效),不幸的是 Bitmap.Getpixel 对我没有任何好处是否通过 Bitmap.Lock 加载到内存中。
有没有更快(几乎是即时)的方法?谢谢。
【问题讨论】:
当然有。通常你要做的是:
for each pixel
Get device contex
Read Pixel
Release device contex (unless you want memory leak)
为此,您需要很少的外部 Windows 库调用,例如:
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
static public System.Drawing.Color getPixelColor(int x, int y) {
IntPtr hdc = GetDC(IntPtr.Zero);
uint pixel = GetPixel(hdc, x, y);
ReleaseDC(IntPtr.Zero, hdc);
Color color = Color.FromArgb((int)(pixel & 0x000000FF),
(int)(pixel & 0x0000FF00) >> 8,
(int)(pixel & 0x00FF0000) >> 16);
return color;
}
这样会好很多
GetDC
for each pixel
read pixel and store value
ReleaseDC
但是我发现获取像素方法本身很慢。因此,为了获得更好的性能,只需将整个屏幕抓取到位图中并从那里获取像素。
这里是一些c#的示例代码,如果你想使用在线转换器,你可以在VB.net中转换它:
var maxX=200;
var maxY=200;
var screensize = Screen.PrimaryScreen.Bounds;
var xCenterSub100 = (screensize.X-maxX)/2;
var yCenterSub100 = (screensize.Y-maxY)/2;
Bitmap hc = new Bitmap(maxX, maxY);
using (Graphics gf = Graphics.FromImage(hc)){
gf.CopyFromScreen(xCenterSub100, yCenterSub100, 0, 0, new Size(maxX, maxY), CopyPixelOperation.SourceCopy);
//...
for (int x = 0; x < maxX; x++){
for (int y = 0; y < maxY; y++){
var pColor = hc.GetPixel(x, y);
//do something with the color...
}
}
}
在 Vb.net 中(使用 http://converter.telerik.com/):
Dim maxX = 200
Dim maxY = 200
Dim screensize = Screen.PrimaryScreen.Bounds
Dim xCenterSub100 = (screensize.X - maxX) / 2
Dim yCenterSub100 = (screensize.Y - maxY) / 2
Dim hc As New Bitmap(maxX, maxY)
Using gf As Graphics = Graphics.FromImage(hc)
gf.CopyFromScreen(xCenterSub100, yCenterSub100, 0, 0, New Size(maxX, maxY), CopyPixelOperation.SourceCopy)
'...
For x As Integer = 0 To maxX - 1
For y As Integer = 0 To maxY - 1
Dim pColor = hc.GetPixel(x, y)
'do something with the color...
Next
Next
End Using
在我的旧电脑上使用 c#,我得到了大约 30 fps,运行时间大约是 35 毫秒。有更快的方法,但他们开始滥用一些东西来达到那个速度。请注意,您不使用 getPixelColor,这里仅供参考。您改为使用屏幕抓取图像方法。
【讨论】:
如果您不想使用 p/invoke,可以使用 LockBits 方法。此代码将 PictureBox 中位图中心的 200 x 200 区域的每个组件设置为随机值。它的运行时间约为 100 毫秒(不包括 PictureBox 的刷新)。
编辑:我意识到您正在尝试读取像素,所以我添加了一行来说明如何做到这一点。
Private Sub DoGraphics()
Dim x As Integer
Dim y As Integer
'PixelSize is 4 bytes for a 32bpp Argb image.
'Change this value appropriately
Dim PixelSize As Integer = 4
Dim rnd As New Random()
'This code uses a bitmap that is loaded in a picture box.
'Any bitmap should work.
Dim bm As Bitmap = Me.PictureBox1.Image
'lock an area of the bitmap for editing that is 200 x 200 pixels in the center.
Dim bmd As BitmapData = bm.LockBits(New Rectangle((bm.Width - 200) / 2, (bm.Height - 200) / 2, 200, 200), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat)
'loop through the locked area of the bitmap.
For y = 0 To bmd.Height - 1
For x = 0 To bmd.Width - 1
'Get the various pixel locations This calculation is for a 32bpp Argb bitmap
Dim blue As Integer = (bmd.Stride * y) + (PixelSize * x)
Dim green As Integer = blue + 1
Dim red As Integer = green + 1
Dim alpha As Integer = red + 1
'Set each component of the pixel to a random rgb value.
'There are 4 bytes that make up each pixel (32bpp Argb)
Marshal.WriteByte(bmd.Scan0, red, CByte(rnd.Next(0, 256)))
Marshal.WriteByte(bmd.Scan0, blue, CByte(rnd.Next(0, 256)))
Marshal.WriteByte(bmd.Scan0, green, CByte(rnd.Next(0, 256)))
Marshal.WriteByte(bmd.Scan0, alpha, 255)
'Use the ReadInt32() method to read back the entire pixel
Dim intColor As Integer = Marshal.ReadInt32(bmd.Scan0)
If intColor = Color.Blue.ToArgb() Then
'The pixel is blue
Else
'The pixel is not blue
End If
Next
Next
'Important!
bm.UnlockBits(bmd)
Me.PictureBox1.Refresh()
End Sub
【讨论】: