PyWin32捕获部分窗口黑屏:如何实现隐藏窗口稳定捕获?
问题原因分析
- 硬件加速渲染差异:PS Remote Play、Microsoft To Do这类应用采用DirectX/D3D硬件加速渲染,窗口内容直接存储在GPU显存中,而非传统GDI的系统内存画布。PyWin32默认的GDI捕获方式只能读取GDI绘制的内容,无法访问GPU显存,因此捕获到黑屏。而Spotify、Paint等应用部分内容使用GDI渲染,所以能正常捕获。
- 窗口防捕获机制:部分现代应用(尤其是串流、办公类)内置隐私保护机制,禁止后台进程捕获窗口内容,防止未经授权的屏幕录制或数据泄露,这也会导致捕获失败出现黑屏。
实现隐藏窗口稳定捕获的方案
方案1:使用DirectX显存捕获库
采用支持读取GPU显存的库(如dxcam),这类库直接调用DirectX接口捕获窗口,能兼容硬件加速渲染的应用:
import dxcam import cv2 import numpy as np from pygetwindow import getWindowsWithTitle # 获取PS Remote Play窗口句柄 ps_window = getWindowsWithTitle("PS Remote Play")[0] camera = dxcam.create(output_color="BGR") camera.start(target=ps_window._hWnd) while True: frame = camera.get_latest_frame() if frame is not None: cv2.imshow("PS Remote Play Capture", frame) if cv2.waitKey(1) & 0xFF == ord('q'): break camera.stop() cv2.destroyAllWindows()
- 注意:
dxcam仅支持Windows系统,需确保显卡驱动为最新版本。
方案2:关闭应用硬件加速
部分应用允许关闭硬件加速,强制切换到GDI渲染模式,之后即可用PyWin32或mss正常捕获:
- 打开PS Remote Play的设置界面,找到「视频」或「性能」选项,禁用「硬件加速」或降低渲染优先级。
- 缺点:关闭硬件加速可能会降低串流画面的流畅度,需根据实际需求权衡。
方案3:调用Windows原生Graphics Capture API
Windows 10 1809及以上版本提供的Windows Graphics Capture API是系统级捕获方式,能绕过大部分应用的防捕获机制,完美支持隐藏/遮挡窗口的硬件加速内容捕获:
import winrt.windows.graphics.capture as wgc import winrt.windows.graphics.imaging as wgi import winrt.windows.storage.streams as wss import cv2 import numpy as np from pygetwindow import getWindowsWithTitle # 获取目标窗口 ps_window = getWindowsWithTitle("PS Remote Play")[0] capture_item = wgc.GraphicsCaptureItem.from_window(ps_window._hWnd) # 初始化捕获会话 session = wgc.GraphicsCaptureSession(capture_item) session.is_cursor_capture_enabled = False # 禁用光标捕获 def frame_handler(sender, args): with sender.get_next_frame() as frame: # 将捕获帧转换为OpenCV格式 bitmap = frame.as_bitmap() buffer = bitmap.lock_buffer(wgi.BitmapBufferAccessMode.READ) ref = buffer.create_reference() stream = ref.create_stream_reader() data = stream.read_bytes(buffer.size) # 转换为numpy数组并处理颜色通道 img = np.frombuffer(data, dtype=np.uint8).reshape(bitmap.size.height, bitmap.size.width, 4) img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR) cv2.imshow("Capture", img) # 绑定帧到达事件 frame_token = session.frame_arrived.add(frame_handler) session.start_capture() cv2.waitKey(0) # 清理资源 session.close() session.frame_arrived.remove(frame_token) cv2.destroyAllWindows()
- 注意:需安装
winrt库(pip install winrt),且系统版本需满足要求,这是稳定性最高的方案。
内容的提问来源于stack exchange,提问作者Nick_2440
相关产品推荐
相关产品推荐

