〜相同的问题这里,但遗憾的是没有有用的答案。
我使用 PlayStation Remote Play 将实时视频从 PS5 传输到我的电脑。该流正在我的计算机上名为“PS Remote Play”的窗口中显示。我想从此窗口读取帧以在
opencv
中进行最终处理。
使用库
mss
和 pygetwindow
,我能够正确捕获此窗口:
import cv2
import mss
import pygetwindow as gw
import numpy as np
def fetch_window_image(window_name):
#
window = gw.getWindowsWithTitle(window_name)[0]
window_rect = {'left': window.left + 10, 'top': window.top + 45,
'width': window.width - 20, 'height': window.height - 60}
with mss.mss() as sct:
screenshot = sct.grab(window_rect)
img = np.array(screenshot)
img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
return img
def main():
WINDOW_NAME = 'PS Remote Play'
cv2.namedWindow('Computer Vision', cv2.WINDOW_NORMAL)
while cv2.waitKey(1) != ord('q'):
img = fetch_window_image(WINDOW_NAME)
cv2.imshow('Computer Vision', img)
if __name__ == '__main__':
main()
问题在于,当窗口被其他窗口遮挡(同时保持活动状态)时,此方法无法捕获它。能够捕获隐藏的窗口对于我的用例来说至关重要。
我遇到了以下代码,它能够捕获隐藏的窗口(源):
import win32gui
import win32ui
import win32con
w = 1920
h = 1080
hwnd = win32gui.FindWindow(None, 'PS Remote Play')
wDC = win32gui.GetWindowDC(hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, w, h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (w, h), dcObj, (0, 0), win32con.SRCCOPY)
dataBitMap.SaveBitmapFile(cDC, 'saved.bmp')
# Free Resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
不幸的是,在 PS Remote Play 窗口上使用时,它显示黑屏。我在其他一些窗口上尝试过,结果好坏参半。它能够捕获 Spotify、Paint 和 VSCode 编辑器。它返回 PS Remote Play、Microsoft To Do、Whiteboard 和 Calendar 的空白屏幕。无论可见与否,这些行为都保持不变。
为什么会发生这种情况?我们如何才能持续捕获隐藏的窗口?
很多游戏都有多种窗口模式,其中一些在未聚焦时会黑屏以节省图形。我不确定 PS Remote Play 中是否存在此设置,但请尝试查看游戏设置并找到一个显示“窗口模式”或“显示模式”的选项,如果看到它,请选择“窗口全屏”或“无边框”。
我不久前遇到了类似的问题,OBS 没有正确广播特定的失焦窗口,这就是我解决它的方法。由于您的代码适用于其他隐藏窗口,这可能也是您的问题。
感谢 Github 上的 @wchill 找到此解决方案(link)!适用于 Windows,适用于硬件加速且被其他窗口遮挡的窗口。
import cv2
import numpy as np
from ctypes import windll
import win32gui
import win32ui
def capture_win_alt(window_name: str):
# Adapted from https://stackoverflow.com/questions/19695214/screenshot-of-inactive-window-printwindow-win32gui
windll.user32.SetProcessDPIAware()
hwnd = win32gui.FindWindow(None, window_name)
left, top, right, bottom = win32gui.GetClientRect(hwnd)
w = right - left
h = bottom - top
hwnd_dc = win32gui.GetWindowDC(hwnd)
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
save_dc = mfc_dc.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(mfc_dc, w, h)
save_dc.SelectObject(bitmap)
# If Special K is running, this number is 3. If not, 1
result = windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 3)
bmpinfo = bitmap.GetInfo()
bmpstr = bitmap.GetBitmapBits(True)
img = np.frombuffer(bmpstr, dtype=np.uint8).reshape((bmpinfo["bmHeight"], bmpinfo["bmWidth"], 4))
img = np.ascontiguousarray(img)[..., :-1] # make image C_CONTIGUOUS and drop alpha channel
if not result: # result should be 1
win32gui.DeleteObject(bitmap.GetHandle())
save_dc.DeleteDC()
mfc_dc.DeleteDC()
win32gui.ReleaseDC(hwnd, hwnd_dc)
raise RuntimeError(f"Unable to acquire screenshot! Result: {result}")
return img
def main():
WINDOW_NAME = "PS Remote Play"
while cv2.waitKey(1) != ord('q'):
screenshot = capture_win_alt(WINDOW_NAME)
cv2.imshow('Computer Vision', screenshot)
if __name__ == '__main__':
main()
我有一个错误:
File "c:\Users\karolkens\automategame\tets.py", line 31, in capture_win_alt
img = np.frombuffer(bmpstr, dtype=np.uint8).reshape((bmpinfo["bmHeight"], bmpinfo["bmWidth"], 4))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: cannot reshape array of size 2 into shape (1,1,4)
知道如何解决吗?