问题
When i run this code on my desktop pc it runs fine. but when i run it op my laptop something goes wrong when i set the bounding box for the image grab to the bounding box of the windows calculator and the screen recording of the window and places it self a little up and to the left.
import cv2
import numpy as np
from PIL import ImageGrab
import win32gui
def windowGrab(window_title=None):
if window_title:
global hwnd
hwnd = win32gui.FindWindow(None, window_title)
if hwnd:
win32gui.SetForegroundWindow(hwnd)
else:
print("window not found")
windowGrab("Calculator")
while True:
left_x, top_y, right_x, bottom_y = win32gui.GetWindowRect(hwnd)
screen = np.array(ImageGrab.grab( bbox = (left_x, top_y, right_x, bottom_y ) ) )
cv2.imshow('window', screen)
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
回答1:
Here are the problems that I faced while testing your code:
- Displaying the calculator window wasn't working correctly.
win32gui.FindWindow()
wasn't finding the correct window so I ended up replacing it. For some reason on Windows 10,win32gui.EnumWindows()
lists 2 windows for one Calculator app: one of them has negative width/height values.win32gui.GetWindowRect()
returns the incorrect position and dimensions of the window. It seems to think my resolution is 1280x720. This probably happens because DPI scaling is being used.ImageGrab.grab()
has trouble taking a screenshot of the app using coordinates and dimensions from the real monitor resolution space (1920x1080).
Obs: this application won't work if the target window is minimized.
Source code:
import cv2
import numpy as np
import sys
import ctypes
import ctypes.wintypes
from ctypes.wintypes import HWND, RECT, DWORD
from ctypes import *
import win32gui
import win32con
from PIL import ImageGrab
# global variables
dwmapi = ctypes.WinDLL("dwmapi")
APP_NAME = ''
win_hwnd = -1
def callback(hwnd, extra):
wnd_name = win32gui.GetWindowText(hwnd)
if (wnd_name == APP_NAME):
rect = win32gui.GetWindowRect(hwnd)
x = rect[0]
y = rect[1]
w = rect[2] - x
h = rect[3] - y
#print("Name: %s" % wnd_name)
#print("\tLocation: (%d, %d)" % (x, y))
#print("\t Size: (%d, %d)" % (w, h))
if (x >= 0 and y >= 0):
global win_hwnd
win_hwnd = hwnd
def windowGrab(window_title=None):
global APP_NAME, win_hwnd
APP_NAME = window_title
if (window_title is None) or (len(window_title) == 0):
print('!!! window_title == None')
sys.exit(-1)
# try to find a window with matching title and valid coordinates
win32gui.EnumWindows(callback, None)
# check if it has focus
if (win_hwnd != win32gui.GetForegroundWindow()):
print('not focused')
win32gui.SetActiveWindow(win_hwnd)
win32gui.SetForegroundWindow(win_hwnd)
# main()
windowGrab("Calculator")
# workaround to allow ImageGrab to capture the whole screen
user32 = ctypes.windll.user32
user32.SetProcessDPIAware()
# get monitor resolution
screen_w = ctypes.windll.user32.GetSystemMetrics(0)
screen_h = ctypes.windll.user32.GetSystemMetrics(1)
print('screen_w=', screen_w, 'screen_h=', screen_h)
# loop
while True:
# retrieve size and position of the window
rect = RECT()
DWMWA_EXTENDED_FRAME_BOUNDS = 9
dwmapi.DwmGetWindowAttribute(HWND(win_hwnd), DWORD(DWMWA_EXTENDED_FRAME_BOUNDS), ctypes.byref(rect), ctypes.sizeof(rect))
x = rect.left
y = rect.top
w = rect.right- x
h = rect.bottom - y
print('x=', x, 'y=', y, 'w=', w, 'h=', h)
if (w == 0 or h == 0):
continue
# take a full screenshot of the desktop
full_screen = np.array(ImageGrab.grab( bbox= (0, 0, screen_w, screen_h) ))
if (full_screen is None):
continue
# crop window area from the screenshot
cropped_rgb = full_screen[y : y+h, x : x+w]
# convert from RGB to BGR order so that colors are displayed correctly
cropped_bgr = cv2.cvtColor(cropped_rgb, cv2.COLOR_RGB2BGR)
cv2.imshow('window', cropped_bgr)
key = cv2.waitKey(25)
if (key & 0xFF) == ord('q'):
break
cv2.destroyAllWindows()
来源:https://stackoverflow.com/questions/60067002/problems-while-taking-screenshots-of-a-window-and-displaying-it-with-opencv