Я пытаюсь сделать скрипт для фишинговой мини-игры, есть пост с фишинг-скриптом для albion онлайн, проблема в том, что в этой игре очень тонкий указатель и много разных текстур и цветов, к простому Сопоставление в оттенках серого хорошо работает на одной части ползунка (например, на текстуре воды), иногда работает на других (текстура деревьев) и не работает на третьей (например, небо). Если я переключаюсь на более низкий порог, он часто активируется без соответствия.
screen
import numpy as np
import cv2
from mss.windows import MSS as mss
from PIL import Image
import time
import pyautogui as pg
import cv2
import mss
import numpy
template = cv2.imread("perfect3.png", cv2.IMREAD_GRAYSCALE)
w, h = template.shape[::-1]
fgbg = cv2.createBackgroundSubtractorMOG2(
history=10,
varThreshold=2,
detectShadows=False)
with mss.mss() as sct:
monitor = {"top": 344, "left": 4419, "width": 150, "height": 666}
while "Screen capturing":
last_time = time.time()
img = numpy.array(sct.grab(monitor))
gray_frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
res = cv2.matchTemplate(gray_frame, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(res >= 0.85)
for pt in zip(*loc[::-1]):
cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0, 255, 0), 3)
print('click')
cv2.imshow("OpenCV/Numpy normal", img)
key = cv2.waitKey(1)
if cv2.waitKey(25) & 0xFF == ord("q"):
cv2.destroyAllWindows()
break
Пробовал также с обнаружением края cv2.canny без удачи.
Смысл в том, чтобы нажать кнопку, когда fi sh находится в самом маленьком зеленом поле. Поле появляется в случайных частях ползунка.
Есть идеи?
================
ОБНОВЛЕНИЕ
Пробное сопоставление цветов, как сказал Фурас
# import the necessary packages
from collections import deque
from imutils.video import VideoStream
import numpy as np
import argparse
import cv2
import imutils
import time
from mss.linux import MSS as mss
from PIL import Image
import mss
import numpy
import pyautogui
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video",
help="path to the (optional) video file")
ap.add_argument("-b", "--buffer", type=int, default=64,
help="max buffer size")
args = vars(ap.parse_args())
# define the lower and upper boundaries of the "green"
# ball in the HSV color space, then initialize the
# list of tracked points
greenLower = (42, 84, 211)
greenUpper = (69, 130, 255)
blueLower = (88, 76, 255)
blueUpper = (151, 76, 255)
pts = deque(maxlen=args["buffer"])
# grab video from screen(monitor area)
with mss.mss() as sct:
monitor = {"top": 325, "left": 4423, "width": 136, "height": 662}
while "Screen capturing":
#last_time = time.time()
#vs = numpy.array(sct.grab(monitor))
#print("fps: {}".format(1 / (time.time() - last_time)))
vs = sct.grab(monitor)
# grab the current frame
#frame = vs
frame = np.array(vs)
# resize the frame, blur it, and convert it to the HSV
# color space
blurred = cv2.GaussianBlur(frame, (11, 11), 0)
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
# construct a mask for the color "green", then perform
# a series of dilations and erosions to remove any small
# blobs left in the mask
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
mask2 = cv2.inRange(hsv, blueLower, blueUpper)
mask2 = cv2.erode(mask2, None, iterations=2)
mask2 = cv2.dilate(mask2, None, iterations=2)
# find contours in the mask and initialize the current
# (x, y) center of the ball
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
center = None
cnts2 = cv2.findContours(mask2.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts2 = imutils.grab_contours(cnts2)
center2 = None
# only proceed if at least one contour was found
if len(cnts) > 0:
# find the largest contour in the mask, then use
# it to compute the minimum enclosing rectangle and
# centroid
c = max(cnts, key=cv2.contourArea)
(x, y, w, h) = cv2.boundingRect(c)
M = cv2.moments(c)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
c2 = max(cnts2, key=cv2.contourArea)
(x2, y2, w2, h2) = cv2.boundingRect(c2)
M2 = cv2.moments(c2)
center2 = (int(M2["m10"] / M2["m00"]), int(M2["m01"] / M2["m00"]))
# draw the rectangle and centroid on the frame,
# then update the list of tracked points
cv2.rectangle(frame, (int(x), int(y)), (int(x+w), int(y+h)),(0, 255, 255), 2)
cv2.circle(frame, center, 5, (0, 0, 255), -1)
cv2.rectangle(frame, (int(x2), int(y2)), (int(x2+w2), int(y2+h2)),(0, 255, 255), 2)
cv2.circle(frame, center2, 5, (0, 0, 255), -1)
# update the points queue
pts.appendleft(center)
if y-15 < y2 < y+15:
pyautogui.click(4908, 984)
time.sleep(2)
y2 = 0
cv2.imshow("frame", frame)
key = cv2.waitKey(1)
if cv2.waitKey(25) & 0xFF == ord("q"):
cv2.destroyAllWindows()
break
Но перед раундом или между раундами я получаю ошибку
Traceback (most recent call last):
File "C:\Users\Game\Desktop\Py\Fish.py", line 74, in <module>
c2 = max(cnts2, key=cv2.contourArea)
ValueError: max() arg is an empty sequence
Как ее можно решить?
Собираемся поменять две маски в одной, как советовал Фурас
mask = cv2.bitwise_or(mask1, mask2)
Но что я могу использовать, чтобы найти как максимум для зеленого поля, так и fi sh? до сих пор это были 2 маски, 2 cnts и 2 max значения.
С mss sct.grab у меня не такой большой FPS (в среднем 25 кадров в секунду), есть ли другие способы захвата?
Большое спасибо !