-
Notifications
You must be signed in to change notification settings - Fork 17
/
main.py
219 lines (167 loc) · 7.4 KB
/
main.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
import math
from utils.grabbers.mss import Grabber
from utils.fps import FPS
import cv2
import multiprocessing
import numpy as np
from utils.nms import non_max_suppression_fast
from utils.cv2 import filter_rectangles
from utils.controls.mouse.win32 import MouseControls
from utils.win32 import WinHelper
import keyboard
import time
from utils.time import sleep
from screen_to_world import get_move_angle
#config
ACTIVATION_HOTKEY = 58 # 58 = CAPS-LOCK
AUTO_DEACTIVATE_AFTER = 60 # seconds or None (default Aim Lab map time is 60 seconds)
_shoot = True
_show_cv2 = True
# the bigger these values, the more accurate and fail-safe bot will behave
_pause = 0.05
_shoot_interval = 0.05 # seconds
# used by the script
game_window_rect = WinHelper.GetWindowRect("aimlab_tb", (8, 30, 16, 39)) # cut the borders
_ret = None
_aim = False
_activation_time = 0
def grab_process(q):
grabber = Grabber()
while True:
img = grabber.get_image({"left": int(game_window_rect[0]), "top": int(game_window_rect[1]), "width": int(game_window_rect[2]), "height": int(game_window_rect[3])})
if img is None:
continue
q.put_nowait(img)
q.join()
def cv2_process(q):
global _aim, _shoot, _ret, _pause, _shoot_interval, _show_cv2, game_window_rect, _activation_time
fps = FPS()
font = cv2.FONT_HERSHEY_SIMPLEX
_last_shoot = None
grabber = Grabber()
mouse = MouseControls()
fov = [106.26, 73.74] # horizontal, vertical
x360 = 16364 # x value to rotate on 360 degrees
x1 = x360/360
x_full_hor = x1 * fov[0]
# 2420 = 53.13 grads
# 360 grads = 16,400 # 16364
def check_dot(hue_point):
dot_img = grabber.get_image({"left": int(game_window_rect[0] + (game_window_rect[2]/2) + 5),
"top": int(
game_window_rect[1] + (game_window_rect[3]/2) + 28),
"width": 6,
"height": 6})
dot_img = cv2.cvtColor(dot_img, cv2.COLOR_BGR2HSV)
avg_color_per_row = np.average(dot_img, axis=0)
avg_color = np.average(avg_color_per_row, axis=0)
return (hue_point - 10 < avg_color[0] < hue_point + 20) and (avg_color[1] > 120) and (avg_color[2] > 100)
while True:
if not q.empty():
img = q.get_nowait()
q.task_done()
# if _ret is not None:
# # return the mouse to base position and proceed again
# mouse.move_relative(int(_ret[0]), int(_ret[1]))
# _ret = None
# # sleep(_pause)
# continue
# some processing code
# OpenCV HSV Scale (H: 0-179, S: 0-255, V: 0-255)
hue_point = 87
sphere_color = ((hue_point, 100, 100), (hue_point + 20, 255, 255)) # HSV
min_target_size = (40, 40)
max_target_size = (150, 150)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, np.array(sphere_color[0], dtype=np.uint8),
np.array(sphere_color[1], dtype=np.uint8))
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
rectangles = []
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
if (w >= min_target_size[0] and h >= min_target_size[1])\
and (w <= max_target_size[0] and h <= max_target_size[1]):
rectangles.append((int(x), int(y), int(w), int(h)))
if not rectangles:
continue
if _show_cv2:
for rect in rectangles:
x, y, w, h = rect
cv2.rectangle(img, (x, y), (x + w, y + h), [255, 0, 0], 6)
img = cv2.putText(img, f"{(x + w, y + h)}", (x, y-10), font,
.5, (0, 255, 0), 1, cv2.LINE_AA)
# max targets count is 1, everything else is considered FP
rectangles = rectangles
targets_count = len(rectangles)
# Apply NMS
rectangles = np.array(non_max_suppression_fast(np.array(rectangles), overlapThresh=0.3))
# Filter rectangles (join intersections)
rectangles = filter_rectangles(rectangles.tolist())
# detect closest target
closest = 1000000
aim_rect = None
for rect in rectangles:
x, y, w, h = rect
mid_x = int((x+(x+w))/2)
mid_y = int((y+(y+h))/2)
dist = math.dist([960, 540], [mid_x, mid_y])
if dist < closest:
closest = dist
aim_rect = rect
rectangles = [aim_rect]
for rect in rectangles:
x, y, w, h = rect
if _show_cv2:
cv2.rectangle(img, (x, y), (x + w, y + h), [0, 255, 0], 2)
# shoot
mid_x = int((x+(x+w))/2)
mid_y = int((y+(y+h))/2)
if _show_cv2:
cv2.circle(img, (mid_x, mid_y), 10, (0, 0, 255), -1)
if _aim:
if _last_shoot is None or time.perf_counter() > (_last_shoot + _shoot_interval):
rel_diff = get_move_angle((mid_x, mid_y), game_window_rect, x1, fov)
# move the mouse
mouse.move_relative(int(rel_diff[0]), int(rel_diff[1]))
sleep(_pause)
if _shoot:
# detect if aiming the target (more accurate)
if check_dot(hue_point):
# click
mouse.hold_mouse()
sleep(0.001)
mouse.release_mouse()
sleep(0.001)
_last_shoot = time.perf_counter()
break
else:
# Aim only once if shoot is disabled
_aim = False
# Auto deactivate aiming and/or shooting after N seconds
if AUTO_DEACTIVATE_AFTER is not None:
if _activation_time+AUTO_DEACTIVATE_AFTER < time.perf_counter():
_aim = False
# cv stuff
# img = mask
if _show_cv2:
img = cv2.putText(img, f"{fps():.2f} | targets = {targets_count}", (20, 120), font,
1.7, (0, 255, 0), 7, cv2.LINE_AA)
img = cv2.resize(img, (1280, 720))
# cv2.imshow("test", cv2.cvtColor(img, cv2.COLOR_RGB2BGRA))
# mask = cv2.resize(mask, (1280, 720))
cv2.imshow("test", img)
cv2.waitKey(1)
def switch_shoot_state(triggered, hotkey):
global _aim, _ret, _activation_time
_aim = not _aim # inverse value
if not _aim:
_ret = None
else:
_activation_time = time.perf_counter()
keyboard.add_hotkey(ACTIVATION_HOTKEY, switch_shoot_state, args=('triggered', 'hotkey'))
if __name__ == "__main__":
q = multiprocessing.JoinableQueue()
p1 = multiprocessing.Process(target=grab_process, args=(q,))
p2 = multiprocessing.Process(target=cv2_process, args=(q,))
p1.start()
p2.start()