1
+ from threading import Lock , Thread
2
+
1
3
import numpy as np
2
- import win32gui , win32ui , win32con
4
+ import win32con
5
+ import win32gui
6
+ import win32ui
3
7
4
8
5
9
class WindowCapture :
6
10
11
+ # threading properties
12
+ stopped = True
13
+ lock = None
14
+ screenshot = None
7
15
# properties
8
16
w = 0
9
17
h = 0
@@ -14,24 +22,27 @@ class WindowCapture:
14
22
offset_y = 0
15
23
16
24
# constructor
17
- def __init__ (self , window_name = None ):
25
+ def __init__ (self , window_name = None , cut_window = 1 ):
26
+ # create a thread lock object
27
+ self .lock = Lock ()
28
+
18
29
# find the handle for the window we want to capture.
19
30
# if no window name is given, capture the entire screen
20
31
if window_name is None :
21
32
self .hwnd = win32gui .GetDesktopWindow ()
22
33
else :
23
34
self .hwnd = win32gui .FindWindow (None , window_name )
24
35
if not self .hwnd :
25
- raise Exception (' Window not found: {}' .format (window_name ))
36
+ raise Exception (" Window not found: {}" .format (window_name ))
26
37
27
38
# get the window size
28
39
window_rect = win32gui .GetWindowRect (self .hwnd )
29
40
self .w = window_rect [2 ] - window_rect [0 ]
30
41
self .h = window_rect [3 ] - window_rect [1 ]
31
42
32
43
# account for the window border and titlebar and cut them off
33
- border_pixels = 8
34
- titlebar_pixels = 30
44
+ border_pixels = 8 * cut_window
45
+ titlebar_pixels = 30 * cut_window
35
46
self .w = self .w - (border_pixels * 2 )
36
47
self .h = self .h - titlebar_pixels - border_pixels
37
48
self .cropped_x = border_pixels
@@ -51,12 +62,18 @@ def get_screenshot(self):
51
62
dataBitMap = win32ui .CreateBitmap ()
52
63
dataBitMap .CreateCompatibleBitmap (dcObj , self .w , self .h )
53
64
cDC .SelectObject (dataBitMap )
54
- cDC .BitBlt ((0 , 0 ), (self .w , self .h ), dcObj , (self .cropped_x , self .cropped_y ), win32con .SRCCOPY )
65
+ cDC .BitBlt (
66
+ (0 , 0 ),
67
+ (self .w , self .h ),
68
+ dcObj ,
69
+ (self .cropped_x , self .cropped_y ),
70
+ win32con .SRCCOPY ,
71
+ )
55
72
56
73
# convert the raw data into a format opencv can read
57
- #dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
74
+ # dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
58
75
signedIntsArray = dataBitMap .GetBitmapBits (True )
59
- img = np .fromstring (signedIntsArray , dtype = ' uint8' )
76
+ img = np .fromstring (signedIntsArray , dtype = " uint8" )
60
77
img .shape = (self .h , self .w , 4 )
61
78
62
79
# free resources
@@ -66,9 +83,9 @@ def get_screenshot(self):
66
83
win32gui .DeleteObject (dataBitMap .GetHandle ())
67
84
68
85
# drop the alpha channel, or cv.matchTemplate() will throw an error like:
69
- # error: (-215:Assertion failed) (depth == CV_8U || depth == CV_32F) && type == _templ.type()
86
+ # error: (-215:Assertion failed) (depth == CV_8U || depth == CV_32F) && type == _templ.type()
70
87
# && _img.dims() <= 2 in function 'cv::matchTemplate'
71
- img = img [...,:3 ]
88
+ img = img [..., :3 ]
72
89
73
90
# make image C_CONTIGUOUS to avoid errors that look like:
74
91
# File ... in draw_rectangles
@@ -84,15 +101,40 @@ def get_screenshot(self):
84
101
# https://stackoverflow.com/questions/55547940/how-to-get-a-list-of-the-name-of-every-open-window
85
102
@staticmethod
86
103
def list_window_names ():
104
+ window_list = []
105
+
87
106
def winEnumHandler (hwnd , ctx ):
88
107
if win32gui .IsWindowVisible (hwnd ):
89
108
print (hex (hwnd ), win32gui .GetWindowText (hwnd ))
109
+ window_list .append (win32gui .GetWindowText (hwnd ))
110
+
90
111
win32gui .EnumWindows (winEnumHandler , None )
112
+ return window_list
91
113
92
114
# translate a pixel position on a screenshot image to a pixel position on the screen.
93
115
# pos = (x, y)
94
116
# WARNING: if you move the window being captured after execution is started, this will
95
117
# return incorrect coordinates, because the window position is only calculated in
96
118
# the __init__ constructor.
97
119
def get_screen_position (self , pos ):
98
- return (pos [0 ] + self .offset_x , pos [1 ] + self .offset_y )
120
+ return (pos [0 ] + self .offset_x , pos [1 ] + self .offset_y )
121
+
122
+ # threading methods
123
+
124
+ def start (self ):
125
+ self .stopped = False
126
+ t = Thread (target = self .run )
127
+ t .start ()
128
+
129
+ def stop (self ):
130
+ self .stopped = True
131
+
132
+ def run (self ):
133
+ # TODO: you can write your own time/iterations calculation to determine how fast this is
134
+ while not self .stopped :
135
+ # get an updated image of the game
136
+ screenshot = self .get_screenshot ()
137
+ # lock the thread while updating the results
138
+ self .lock .acquire ()
139
+ self .screenshot = screenshot
140
+ self .lock .release ()
0 commit comments