You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

全屏游戏截图失败:修改numpy dtype后触发ValueError报错求助

全屏游戏截图黑屏+数组重塑报错解决方法

一、当前报错的原因及修复

你遇到的ValueError: cannot reshape array of size 12288000 into shape (1600,3840,4)是因为:

  • 原代码用numpy.uint8时,bitmap.GetBitmapBits(True)返回的是32位BGRA位图的字节数据(每个像素4字节),数组元素数正好是高度×宽度×4,所以重塑形状没问题。
  • 改成numpy.uint16后,每个数组元素占2字节,总元素数变成原来的一半(1600×3840×4 ÷2 =12288000),这时候再强行设置形状为(高度,宽度,4),元素总数不匹配,自然报错。

如果非要用uint16读取,修复代码如下:

output = numpy.frombuffer(bitmap.GetBitmapBits(True), dtype = numpy.uint16)
output.shape = (height, width, 2)  # 每个像素对应2个uint16元素
# 转换回uint8的BGRA格式
output = output.view(numpy.uint8).reshape(height, width, 4)

但这只是修复报错,解决不了全屏游戏黑屏的根本问题。

二、全屏游戏黑屏的根本原因

win32gui的BitBlt只能捕获GDI绘制的普通窗口画面,而现代全屏游戏大多用Direct3D/OpenGL做硬件加速渲染,画面直接存在GPU显存里,BitBlt无法读取这部分内容,所以返回黑屏。

三、解决全屏游戏截图的正确方案

改用DXGI API捕获画面,它能直接读取GPU显存中的渲染内容,支持硬件加速窗口的截图。以下是完整实现代码:

import cv2 as cv
import numpy as np
import win32gui
import win32con
from ctypes import windll, byref, c_void_p

# 初始化DXGI相关函数与常量
dxgi = windll.dxgi
d3d11 = windll.d3d11

class DXGIScreenCapture:
    def __init__(self, hwnd):
        self.hwnd = hwnd
        # 获取窗口尺寸
        left, top, right, bottom = win32gui.GetWindowRect(hwnd)
        self.width = right - left
        self.height = bottom - top
        # 创建D3D11设备与上下文
        self._create_d3d_device()
        # 获取DXGI输出复制对象
        self._create_output_duplication()

    def _create_d3d_device(self):
        self.device = c_void_p()
        self.context = c_void_p()
        d3d11.D3D11CreateDevice(
            None,
            win32con.D3D_DRIVER_TYPE_HARDWARE,
            None,
            0,
            None,
            0,
            win32con.D3D11_SDK_VERSION,
            byref(self.device),
            None,
            byref(self.context)
        )
        # 获取DXGI适配器
        self.adapter = c_void_p()
        self.device.QueryInterface(dxgi.IDXGIAdapter, byref(self.adapter))
        # 获取DXGI输出
        self.output = c_void_p()
        self.adapter.EnumOutputs(0, byref(self.output))

    def _create_output_duplication(self):
        self.output_dup = c_void_p()
        self.output.DuplicateOutput(self.device, byref(self.output_dup))

    def capture(self):
        frame_info = dxgi.DXGI_OUTDUPL_FRAME_INFO()
        resource = c_void_p()
        # 获取下一帧
        self.output_dup.AcquireNextFrame(0, byref(frame_info), byref(resource))
        
        # 创建 staging 纹理用于CPU读取
        tex_desc = dxgi.DXGI_TEXTURE2D_DESC()
        tex_desc.Width = self.width
        tex_desc.Height = self.height
        tex_desc.MipLevels = 1
        tex_desc.ArraySize = 1
        tex_desc.Format = win32con.DXGI_FORMAT_B8G8R8A8_UNORM
        tex_desc.SampleDesc.Count = 1
        tex_desc.SampleDesc.Quality = 0
        tex_desc.Usage = dxgi.DXGI_USAGE_STAGING
        tex_desc.CPUAccessFlags = dxgi.DXGI_CPU_ACCESS_READ
        tex_desc.BindFlags = 0
        tex_desc.MiscFlags = 0

        staging_tex = c_void_p()
        self.device.CreateTexture2D(byref(tex_desc), None, byref(staging_tex))
        # 复制帧资源到staging纹理
        self.context.CopyResource(staging_tex, resource)
        
        # 映射纹理到CPU内存
        mapped_rect = dxgi.DXGI_MAPPED_RECT()
        self.context.Map(staging_tex, 0, dxgi.DXGI_MAP_READ, 0, byref(mapped_rect))
        
        # 转换为numpy数组并调整格式
        img = np.frombuffer(mapped_rect.pBits, dtype=np.uint8).reshape(self.height, self.width, 4)
        img = cv.cvtColor(img, cv.COLOR_BGRA2BGR)  # 转为OpenCV支持的BGR格式
        
        # 释放资源
        self.context.Unmap(staging_tex, 0)
        self.output_dup.ReleaseFrame()
        resource.Release()
        staging_tex.Release()
        
        return img

def get_window_handle(title_part):
    target_hwnd = None
    def enum_windows_callback(handle, extra):
        nonlocal target_hwnd
        if title_part in win32gui.GetWindowText(handle):
            target_hwnd = handle
            return False
        return True
    win32gui.EnumWindows(enum_windows_callback, None)
    return target_hwnd

# 使用示例
hwnd = get_window_handle("Marvel's Spider-Man Remastered")
if hwnd:
    capturer = DXGIScreenCapture(hwnd)
    screenshot = capturer.capture()
    cv.imshow('Game Screenshot', screenshot)
    cv.waitKey(0)
    cv.destroyAllWindows()
else:
    print("未找到目标游戏窗口")

四、注意事项

  • 运行代码需要安装pywin32和opencv-python依赖:pip install pywin32 opencv-python
  • 部分游戏可能有反作弊机制,会阻止DXGI截图,这种情况下需要调整游戏的反作弊设置或使用其他兼容方案。

内容的提问来源于stack exchange,提问作者phpjunkie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 05:15:01