我正试图从一个Windows安装的应用程序中捕捉点击。因此,我们的目标是获得与打开的应用程序的宽度和高度相关的点击位置,而不是屏幕的宽度和高度。
例如,假设你在屏幕的上半部分打开了 "Paint",你点击了菜单上的 "Brushes "选项。
例如,你可以使用Python模块pynput很容易地得到点击的位置,但这将得到相对于屏幕大小的位置。所以如果你有一个1920x1080的屏幕,点击位置将在这些坐标之间。然而,我想要的是相对于应用程序(Paint)大小的位置(即在600和900之间;假设Paint是在屏幕左侧打开的)。
这有点难以解释,所以请看下面的图片,它应该可以解释我试图实现的目标。
图片上有两个Paint窗口,上面的那个是我想跟踪点击的窗口。顶部的那个窗口是我想跟踪点击的窗口(在这种情况下,你实际上看不到光标,但它正指向 "刷子 "箭头)。第二个窗口是OpenCV的,它试图显示点击发生的位置(蓝色圆圈),但它与实际应该的位置相差甚远。
下面是我的算法的概述。
import ctypes
import win32gui
import cv2
import mss
import time
import numpy as np
## Set countdown to have enough time to put the mouse in the correct position
for i in range(5, 0, -1):
print(i)
time.sleep(1)
## Get application width and height
ctypes.windll.user32.SetProcessDPIAware() ## No idea why but I must set this, otherwise I get wrong results from win32gui.GetWindowRect()
hwnd = win32gui.FindWindow(None, "Untitled - Paint")
left, top, right, bottom = win32gui.GetWindowRect(hwnd)
left = left + 8
width = right - left - 8
height = bottom - top - 8
monitor = {"top": top, "left": left, "width": width, "height": height}
print(width, height)
## Get current mouse screen position
x, y = win32gui.GetCursorPos()
print(x, y)
## Grab a screenshoot of the application
with mss.mss() as sct:
screen = sct.grab(monitor)
img = np.array(screen)
img = cv2.rectangle(img, (0, 0), (width, height), (255, 0, 0), 2) ## Drawing rectangle around screenshot of the application
img = cv2.circle(img, (x*width//1920, y*height//1080), 20, (255, 0, 0), -1) ## Drawing set of points from the current mouse screen position
cv2.imshow('window', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
第3个参数的坐标是 cv2.circle
与背景图相关的圆心(img
).
你可以使用 ScreenToClient
获取将屏幕上指定点的屏幕坐标转换为客户端区域坐标。
import ctypes
import win32gui
import cv2
import mss
import time
import numpy as np
## Set countdown to have enough time to put the mouse in the correct position
for i in range(5, 0, -1):
print(i)
time.sleep(1)
## Get application width and height
ctypes.windll.user32.SetProcessDPIAware() ## No idea why but I must set this, otherwise I get wrong results from win32gui.GetWindowRect()
hwnd = win32gui.FindWindow(None, "Untitled - Paint")
left, top, right, bottom = win32gui.GetWindowRect(hwnd)
left = left + 8
width = right - left - 8
height = bottom - top - 8
monitor = {"top": top, "left": left, "width": width, "height": height}
print(width, height)
## Get current mouse screen position
x, y = win32gui.GetCursorPos()
print(x, y)
## Grab a screenshoot of the application
with mss.mss() as sct:
screen = sct.grab(monitor)
img = np.array(screen)
img = cv2.rectangle(img, (0, 0), (width, height), (255, 0, 0), 2) ## Drawing rectangle around screenshot of the application
pos = win32gui.ScreenToClient(hwnd,(x,y))
x = pos[0]
y = pos[1]
print(x, y)
img = cv2.circle(img, (x, y), 20, (255, 0, 0), -1) ## Drawing set of points from the current mouse screen position
cv2.imshow('window', img)
cv2.waitKey(0)
cv2.destroyAllWindows()