连续捕获屏幕的某个区域



我希望连续捕获屏幕的一个区域。

我可以使用LockBitsBitBlt等来做到这一点,但我所有的测量都表明,捕获一帧平均需要 30 毫秒。它似乎与VSynch非常相似...这将尝试将屏幕更新率保持在恒定的 30 毫秒......

但是,我刚刚遇到了以下帖子。

在其中,有人声称在1000 毫秒内获得 95 帧......这是闻所未闻的(对我来说!这是他发布的代码:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private readonly Stopwatch sw = new Stopwatch();
private static Bitmap CaptureImage(int x, int y)
{
Bitmap b = new Bitmap(100, 100);
using (Graphics g = Graphics.FromImage(b))
{
g.CopyFromScreen(x, y, 0, 0, new Size(100, 100), CopyPixelOperation.SourceCopy);
g.DrawLine(Pens.Black, new Point(0, 27), new Point(99, 27));
g.DrawLine(Pens.Black, new Point(0, 73), new Point(99, 73));
g.DrawLine(Pens.Black, new Point(52, 0), new Point(52, 99));
g.DrawLine(Pens.Black, new Point(14, 0), new Point(14, 99));
g.DrawLine(Pens.Black, new Point(85, 0), new Point(85, 99));
}
return b;
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = null;
sw.Restart();
for (int i = 0; i < 1000; i++)
{
bmp = CaptureImage(390, 420);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
}

我试过了,你猜怎么着....我得到~30k毫秒打印到控制台。很明显,这个完全相同的代码在我的系统上仍然只以 30 毫秒/帧的速度捕获。在他的帖子中,他说:

如果相同,您的系统一定存在严重问题 程序需要 35 毫秒才能捕获 1 帧。

这让我很纳闷,所以我更新了我的显卡驱动程序。相同的结果。然后我想也许我的显卡是旧的......好的,它是:AMD Radeon HD 5700系列。由于我怀疑VSync,我安装了AMD Catalyst Software Suite,禁用了Vsyc并重新启动。再次运行测试,我得到了相同的结果:30 帧的 ~1000k 毫秒。

然后,我安装了Windows 10和NVIDIA GRID K520驱动程序(最新(加载了Amazon EC2 g2.2xlarge instance。相同的结果:每帧 30 毫秒。

有经验的人可以向我解释一下这里发生了什么吗?

难道就不可能做到作者声称的并在 1000 毫秒内捕获 95 帧吗?

我的系统有问题吗?我不知道还能尝试什么。

以目前的技术基本上不可能达到 100,000 fps。指向 social.msdn.microsoft.com 的链接包括有关实现此类结果的声明,但它们是错误的,或者可能在从内存复制到内存与从屏幕复制到内存之间混淆。

下面的示例使用核心 WinAPI 函数。在我的计算机上(使用便宜的板载显卡(,对于 60 x 100 像素的小区域,它只能达到每秒 100 帧。这将比有问题的代码略快,但如果清理代码,则使用 .net 可能会获得相同的结果。

无论如何,它只会导致您的计算机略有增加,60 FPS 或 100 FPS(如果您尝试复制整个屏幕,则更少(

请注意,从内存复制到内存要快得多。我确实获得了超过 100,000 FPS,但它不是屏幕上的实际帧。它只是从内存复制到内存。如果将区域增加到大于 100x100 像素的值,则此速度将降低。

使用云计算机进行测试不可靠。我什至不确定在云计算机上复制屏幕意味着什么。尝试在具有更好显卡的桌面上进行测试。

class Program
{
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr ptr);
[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("Gdi32.dll")]
static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("Gdi32.dll")]
static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int w, int h);
[DllImport("Gdi32.dll")]
static extern IntPtr BitBlt(IntPtr hDC, int x, int y, int w, int h, IntPtr hSrc, int sx, int sy, int mode);
[DllImport("Gdi32.dll")]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr obj);
[DllImport("Gdi32.dll")]
static extern int DeleteObject(IntPtr hdc);
[DllImport("Gdi32.dll")]
static extern int DeleteDC(IntPtr hdc);
static void Main(string[] args)
{
const int SRCCOPY = 0x00CC0020;
int w = 100;
int h = 100;
//get screen dc:
IntPtr hdc = GetDC((IntPtr)0);
//create memory dc and bitmap, select bitmap in to memory:
IntPtr memdc = CreateCompatibleDC(hdc);
IntPtr hbitmap = CreateCompatibleBitmap(hdc, w, h);
IntPtr holdbmp = SelectObject(memdc, hbitmap);
//create another memory dc and bitmap:
IntPtr memdc2 = CreateCompatibleDC(hdc);
IntPtr hbitmap2 = CreateCompatibleBitmap(hdc, w, h);
IntPtr holdbmp2 = SelectObject(memdc2, hbitmap2);
Stopwatch sw = new Stopwatch();
//copy the screen for 1 second
sw.Restart();
int fps = 0; //frames per second
for (fps = 0; sw.ElapsedMilliseconds < 1000; fps++)
BitBlt(memdc, 0, 0, w, h, hdc, 0, 0, SRCCOPY);
sw.Stop();
Console.WriteLine($"screen capture, FPS: {fps}");
//copy from memory to memory for 1 second
sw.Restart();
fps = 0;
for (fps = 0; sw.ElapsedMilliseconds < 1000; fps++)
BitBlt(memdc, 0, 0, w, h, memdc2, 0, 0, SRCCOPY);
sw.Stop();
Console.WriteLine($"memory to memory copy, FPS: {fps}");
//cleanup:
SelectObject(memdc, holdbmp);
SelectObject(memdc2, holdbmp2);
DeleteObject(hbitmap);
DeleteObject(hbitmap2);
DeleteDC(memdc);
DeleteDC(memdc2);
ReleaseDC((IntPtr)0, hdc);
}
}

最新更新