C# .NET 6 WinForm如何实现1440P屏幕60FPS快速截图
优化C# WinForm .NET6下1440P屏幕截图速度方案
当前CopyFromScreen的性能瓶颈来自GDI+的封装开销,要达到接近视频设备捕获的速度,需要利用底层系统API或硬件加速机制,以下是几种可行方案:
方案1:BitBlt替代CopyFromScreen
BitBlt是底层GDI函数,跳过GDI+的部分封装逻辑,能将截图耗时压缩到10-15ms左右。
实现代码
using System.Runtime.InteropServices; using System.Drawing.Imaging; public class FastScreenshotHelper { [DllImport("gdi32.dll")] private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop); [DllImport("user32.dll")] private static extern IntPtr GetDC(IntPtr hWnd); [DllImport("user32.dll")] private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); public Bitmap CaptureScreenWithBitBlt() { var screenBounds = Screen.PrimaryScreen.Bounds; var bitmap = new Bitmap(screenBounds.Width, screenBounds.Height, PixelFormat.Format32bppArgb); using (var gDest = Graphics.FromImage(bitmap)) { var hdcDest = gDest.GetHdc(); var hdcSrc = GetDC(IntPtr.Zero); // 获取全屏设备上下文 // SRCCOPY:直接复制源区域像素到目标 BitBlt(hdcDest, 0, 0, screenBounds.Width, screenBounds.Height, hdcSrc, 0, 0, 0x00CC0020); ReleaseDC(IntPtr.Zero, hdcSrc); gDest.ReleaseHdc(hdcDest); } return bitmap; } }
方案2:Windows Graphics Capture API(推荐,硬件加速)
这是Win10 1903+支持的系统级API,直接从GPU显存捕获帧,耗时可低至1-5ms,接近视频设备捕获速度。需要依赖Microsoft.Windows.SDK.Contracts和SharpDX.Direct3D11 NuGet包。
实现代码
using Windows.Graphics.Capture; using Windows.Graphics.DirectX; using Windows.Graphics.DirectX.Direct3D11; using System.Runtime.InteropServices.WindowsRuntime; using Emgu.CV; using SharpDX.Direct3D11; using SharpDX.DXGI; using System.Drawing.Imaging; public class HardwareAcceleratedCapture { private GraphicsCaptureItem _captureItem; private Direct3D11CaptureFramePool _framePool; private GraphicsCaptureSession _session; private Mat _latestFrame; // 初始化捕获(需在UI线程调用,首次运行会弹出权限提示) public async Task Initialize() { // 获取主屏幕作为捕获目标 var display = DisplayMonitor.GetFromDisplayName(Screen.PrimaryScreen.DeviceName); _captureItem = GraphicsCaptureItem.CreateFromDisplayMonitor(display); // 创建Direct3D硬件设备 var d3dDevice = CreateD3DDevice(); _framePool = Direct3D11CaptureFramePool.Create( d3dDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, // 缓存2帧避免丢帧 _captureItem.Size); _session = _framePool.CreateCaptureSession(_captureItem); _framePool.FrameArrived += OnFrameArrived; _session.StartCapture(); } private static IDirect3DDevice CreateD3DDevice() { var device = new Device(DriverType.Hardware, DeviceCreationFlags.BgraSupport); return device.As<IDirect3DDevice>(); } // 帧到达时处理,直接转成EmguCV Mat private void OnFrameArrived(Direct3D11CaptureFramePool sender, object args) { using (var frame = sender.TryGetNextFrame()) { if (frame == null) return; using (var surface = frame.Surface) { var dxgiSurface = surface.As<Surface>(); var bitmap = new Bitmap(frame.ContentSize.Width, frame.ContentSize.Height, PixelFormat.Format32bppArgb); var rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height); // 锁定Bitmap内存,直接从显存拷贝数据 var bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, bitmap.PixelFormat); dxgiSurface.MapToMemory(out var pointer, out var pitch); System.Buffer.MemoryCopy(pointer, bitmapData.Scan0, bitmapData.Stride * bitmap.Height, bitmapData.Stride * bitmap.Height); dxgiSurface.Unmap(); bitmap.UnlockBits(bitmapData); // 转成Mat供机器学习检测使用 _latestFrame = BitmapConverter.ToMat(bitmap); } } } // 获取最新捕获帧 public Mat GetLatestFrame() { return _latestFrame?.Clone(); } // 停止捕获,释放资源 public void StopCapture() { _session?.StopCapture(); _framePool?.Dispose(); _session?.Dispose(); } }
方案3:跳过Bitmap中间转换(进一步优化)
如果你的检测逻辑直接使用EmguCV Mat,可以修改OnFrameArrived方法,直接将显存数据写入Mat,避免Bitmap的创建和转换步骤,进一步减少耗时:
private void OnFrameArrived(Direct3D11CaptureFramePool sender, object args) { using (var frame = sender.TryGetNextFrame()) { if (frame == null) return; using (var surface = frame.Surface) { var dxgiSurface = surface.As<Surface>(); var width = frame.ContentSize.Width; var height = frame.ContentSize.Height; // 创建对应尺寸的Mat var mat = new Mat(height, width, Emgu.CV.CvEnum.DepthType.Cv8U, 4); // 直接从显存拷贝到Mat内存 dxgiSurface.MapToMemory(out var pointer, out var pitch); System.Buffer.MemoryCopy(pointer, mat.DataPointer, mat.Step * mat.Rows, mat.Step * mat.Rows); dxgiSurface.Unmap(); _latestFrame = mat; } } }
性能对比
| 方案 | 耗时范围 |
|---|---|
| CopyFromScreen | 30ms+ |
| BitBlt | 10-15ms |
| Windows Graphics Capture | 1-5ms |
注意事项
- Windows Graphics Capture仅支持Win10 1903及以上版本,若需兼容旧系统,优先选择BitBlt方案。
- 使用Direct3D相关API时,务必在程序退出时调用
StopCapture释放资源,避免内存泄漏。 - 首次使用Windows Graphics Capture会触发系统权限弹窗,需用户允许屏幕捕获权限。
内容的提问来源于stack exchange,提问作者coolshrimp
相关产品推荐
相关产品推荐

