This repository has been archived by the owner on Apr 9, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
imagesearch.py
241 lines (173 loc) · 7.51 KB
/
imagesearch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
import cv2
import numpy as np
import pyautogui
import random
import time
import platform
import subprocess
is_retina = False
if platform.system() == "Darwin":
is_retina = subprocess.call("system_profiler SPDisplaysDataType | grep 'retina'", shell=True)
'''
grabs a region (topx, topy, bottomx, bottomy)
to the tuple (topx, topy, width, height)
input : a tuple containing the 4 coordinates of the region to capture
output : a PIL image of the area selected.
'''
def region_grabber(region):
if is_retina: region = [n * 2 for n in region]
x1 = region[0]
y1 = region[1]
width = region[2] - x1
height = region[3] - y1
return pyautogui.screenshot(region=(x1, y1, width, height))
'''
Searchs for an image within an area
input :
image : path to the image file (see opencv imread for supported types)
x1 : top left x value
y1 : top left y value
x2 : bottom right x value
y2 : bottom right y value
precision : the higher, the lesser tolerant and fewer false positives are found default is 0.8
im : a PIL image, usefull if you intend to search the same unchanging region for several elements
returns :
the top left corner coordinates of the element if found as an array [x,y] or [-1,-1] if not
'''
def imagesearcharea(image, x1, y1, x2, y2, precision=0.8, im=None):
if im is None:
im = region_grabber(region=(x1, y1, x2, y2))
if is_retina:
im.thumbnail((round(im.size[0] * 0.5), round(im.size[1] * 0.5)))
# im.save('testarea.png') usefull for debugging purposes, this will save the captured region as "testarea.png"
img_rgb = np.array(im)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread(image, 0)
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
if max_val < precision:
return [-1, -1]
return max_loc
'''
click on the center of an image with a bit of random.
eg, if an image is 100*100 with an offset of 5 it may click at 52,50 the first time and then 55,53 etc
Usefull to avoid anti-bot monitoring while staying precise.
this function doesn't search for the image, it's only ment for easy clicking on the images.
input :
image : path to the image file (see opencv imread for supported types)
pos : array containing the position of the top left corner of the image [x,y]
action : button of the mouse to activate : "left" "right" "middle", see pyautogui.click documentation for more info
time : time taken for the mouse to move from where it was to the new position
'''
def click_image(image, pos, action, timestamp, offset=5):
img = cv2.imread(image)
height, width, channels = img.shape
pyautogui.moveTo(pos[0] + r(width / 2, offset), pos[1] + r(height / 2, offset),
timestamp)
pyautogui.click(button=action)
'''
Searchs for an image on the screen
input :
image : path to the image file (see opencv imread for supported types)
precision : the higher, the lesser tolerant and fewer false positives are found default is 0.8
im : a PIL image, usefull if you intend to search the same unchanging region for several elements
returns :
the top left corner coordinates of the element if found as an array [x,y] or [-1,-1] if not
'''
def imagesearch(image, precision=0.8):
im = pyautogui.screenshot()
if is_retina:
im.thumbnail((round(im.size[0] * 0.5), round(im.size[1] * 0.5)))
# im.save('testarea.png') useful for debugging purposes, this will save the captured region as "testarea.png"
img_rgb = np.array(im)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread(image, 0)
template.shape[::-1]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
if max_val < precision:
return [-1, -1]
return max_loc
'''
Searchs for an image on screen continuously until it's found.
input :
image : path to the image file (see opencv imread for supported types)
time : Waiting time after failing to find the image
precision : the higher, the lesser tolerant and fewer false positives are found default is 0.8
returns :
the top left corner coordinates of the element if found as an array [x,y]
'''
def imagesearch_loop(image, timesample, precision=0.8):
pos = imagesearch(image, precision)
while pos[0] == -1:
print(image + " not found, waiting")
time.sleep(timesample)
pos = imagesearch(image, precision)
return pos
'''
Searchs for an image on screen continuously until it's found or max number of samples reached.
input :
image : path to the image file (see opencv imread for supported types)
time : Waiting time after failing to find the image
maxSamples: maximum number of samples before function times out.
precision : the higher, the lesser tolerant and fewer false positives are found default is 0.8
returns :
the top left corner coordinates of the element if found as an array [x,y]
'''
def imagesearch_numLoop(image, timesample, maxSamples, precision=0.8):
pos = imagesearch(image, precision)
count = 0
while pos[0] == -1:
print(image + " not found, waiting")
time.sleep(timesample)
pos = imagesearch(image, precision)
count = count + 1
if count > maxSamples:
break
return pos
'''
Searchs for an image on a region of the screen continuously until it's found.
input :
image : path to the image file (see opencv imread for supported types)
time : Waiting time after failing to find the image
x1 : top left x value
y1 : top left y value
x2 : bottom right x value
y2 : bottom right y value
precision : the higher, the lesser tolerant and fewer false positives are found default is 0.8
returns :
the top left corner coordinates of the element as an array [x,y]
'''
def imagesearch_region_loop(image, timesample, x1, y1, x2, y2, precision=0.8):
pos = imagesearcharea(image, x1, y1, x2, y2, precision)
while pos[0] == -1:
time.sleep(timesample)
pos = imagesearcharea(image, x1, y1, x2, y2, precision)
return pos
'''
Searches for an image on the screen and counts the number of occurrences.
input :
image : path to the target image file (see opencv imread for supported types)
precision : the higher, the lesser tolerant and fewer false positives are found default is 0.9
returns :
the number of times a given image appears on the screen.
optionally an output image with all the occurances boxed with a red outline.
'''
def imagesearch_count(image, precision=0.9):
img_rgb = pyautogui.screenshot()
if is_retina:
img_rgb.thumbnail((round(img_rgb.size[0] * 0.5), round(img_rgb.size[1] * 0.5)))
img_rgb = np.array(img_rgb)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread(image, 0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(res >= precision)
count = 0
for pt in zip(*loc[::-1]): # Swap columns and rows
# cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2) // Uncomment to draw boxes around found occurances
count = count + 1
# cv2.imwrite('result.png', img_rgb) // Uncomment to write output image with boxes drawn around occurances
return count
def r(num, rand):
return num + rand * random.random()