Python 实现现代游戏窗口无闪烁高性能 DX11/DX12 截图方案
为什么普通截图方式对现代游戏失效?
在 Windows 平台上,很多现代游戏(尤其是使用 DirectX 11/12 或 Vulkan 渲染的游戏)会启用硬件加速和独占全屏模式。传统的截图方法(如 PIL.ImageGrab、pyautogui.screenshot() 或 cv2.VideoCapture(0))往往无法捕获这些窗口的内容,结果要么是黑屏,要么是桌面背景。
这是因为:
一种基于 DXGI Desktop Duplication API 的 Python 后台截图方案,解决了传统方法无法捕获 DirectX 11/12 渲染的现代游戏窗口的问题。通过封装原生 C++ DLL 并使用 ctypes 调用,实现了无需前台激活、无闪烁的高性能截图,返回 NumPy 数组以便对接 OpenCV 或 AI 模型。方案支持 DX11/DX12 游戏,适用于自动化脚本及监控场景。
在 Windows 平台上,很多现代游戏(尤其是使用 DirectX 11/12 或 Vulkan 渲染的游戏)会启用硬件加速和独占全屏模式。传统的截图方法(如 PIL.ImageGrab、pyautogui.screenshot() 或 cv2.VideoCapture(0))往往无法捕获这些窗口的内容,结果要么是黑屏,要么是桌面背景。
这是因为:

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
那么,有没有一种能在后台稳定、高效、无闪烁地截取游戏窗口的方法?答案是:有!使用 DXGI(DirectX Graphics Infrastructure)技术。
我们开发了一个轻量级 Python 类 DxgiCapture,它通过调用一个原生 C++ 编写的 DLL(dxgi4py.dll),利用 Windows 的 DXGI Desktop Duplication API 实现对任意窗口(包括全屏/无边框游戏)的高速截图。
import ctypes
from ctypes import *
import numpy as np
import win32gui
import cv2
from pathlib import Path
root = Path(__file__).parent
class DxgiCapture:
def __init__(self):
self.dxgi = None
self.__hwnd = None
self.user32 = ctypes.windll.user32
self.user32.SetProcessDPIAware()
self.user32.SetProcessDpiAwarenessContext()
@property
def hwnd(self):
return self.__hwnd
@hwnd.setter
def hwnd(self, hwnd):
if not hwnd or self.hwnd == hwnd:
return
self.__hwnd = hwnd
self.dxgi = self.create_dxgi(hwnd)
def __del__(self):
if self.dxgi:
self.dxgi.destroy()
def __call__(self, hwnd):
self.hwnd = hwnd
shotLeft, shotTop, width, height = self.getWindowRect()
shot = np.ndarray((height, width, 4), dtype=np.uint8)
shotPointer = shot.ctypes.data_as(POINTER(c_ubyte))
buffer = self.dxgi.grab(shotPointer, shotLeft, shotTop, width, height)
image = np.ctypeslib.as_array(buffer, shape=(height, width, 4))
image = cv2.cvtColor(image, cv2.COLOR_BGRA2RGB)
return image
def getWindowRect(self):
left, top, right, bottom = win32gui.GetWindowRect(self.hwnd)
shotLeft, shotTop = 0, 0
height = bottom - top
width = right - left
return shotLeft, shotTop, width, height
def create_dxgi(self, hwnd):
if getattr(self, "dxgi", None):
self.dxgi.destroy()
dxgi = ctypes.CDLL(str(root / "dxgi4py.dll"))
dxgi.grab.argtypes = (POINTER(ctypes.c_ubyte), ctypes.c_int, c_int, c_int, c_int,)
dxgi.grab.restype = POINTER(c_ubyte)
dxgi.init_dxgi(hwnd)
return dxgi
import win32gui
from dxgi_capture import DxgiCapture
# 获取目标窗口句柄(例如:查找'原神'窗口)
hwnd = win32gui.FindWindow(None, "原神")
# 初始化截图器
capture = DxgiCapture()
capture.hwnd = hwnd
# 单次截图
frame = capture(hwnd)
# 返回 RGB 格式的 numpy.ndarray (H, W, 3)
# 可直接用于 OpenCV 显示或模型推理
import cv2
cv2.imshow("Game Capture", frame)
cv2.waitKey(0)
注意:首次使用需安装 pywin32 和 opencv-python:
pip install pywin32 opencv-python numpy
我们的 dxgi4py.dll 封装了以下关键步骤:
整个过程绕过 GDI,直接与 DirectX 交互,因此能捕获受保护内容。
Q:是否支持 Vulkan 游戏?
A:部分支持。Vulkan 内容若通过 DXGI 共享(如 Steam Overlay 开启),可被捕获;否则需额外层(如 OBS 的 Vulkan 钩子)。
Q:能否截取 UWP 应用(如 Xbox Game Bar)?
A:受限于 Windows 安全策略,部分 UWP 应用无法捕获。
Q:是否需要管理员权限?
A:不需要!普通用户权限即可运行。