Постоянное реагирование на объект
Написал такой код, он нажимает кнопку "стрелка влево", если видит на выбранной области картинку красного цвета:
import cv2
import numpy as np
import pyautogui
import time
# Функция для нахождения картинки на экране
def find_image(target_img, screen_img):
result = cv2.matchTemplate(screen_img, target_img, cv2.TM_CCOEFF_NORMED)
return np.where(result >= 1) # Порог для совпадения
# Параметры области захвата экрана
capture_area = (320, 830, 900, 900) # (x, y, width, height)
# Загрузка изображения для поиска
target_image = cv2.imread('red.png') # Изображение, которое ищем
key_to_press = 'left' # Клавиша, которую нужно нажать
while True:
# Захват экрана
screenshot = pyautogui.screenshot(region=capture_area)
screen_image = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
# Поиск изображения на экране
locations = find_image(target_image, screen_image)
if len(locations[0]) > 0:
print("Изображение найдено!")
pyautogui.press(key_to_press) # Нажимаем клавишу
time.sleep(1) # Задержка, чтобы не нажимать слишком быстро
time.sleep(0.1) # Задержка перед следующим сканированием
Предыдущую ошибку исправил, теперь программа запускается, но условие почему-то выполняется постоянно, и постоянно нажимается кнопка "стрелка влево" и print("Изображение найдено")
, даже когда условие не должно выполняться.
Подскажите, пожалуйста, в чем ошибка?
Ответы (1 шт):
Распечатайте print(len(locations))
-> получите в консоль 2.
Следовательно даже при отсутствии найденного изображения ваше условие всегда вернёт True:
if len(locations[0]) > 0: # True всегда
Дело в том, что np.where()
возвращает кортеж из двух массивов - один массив для координат по оси Y и один для координат по оси X.
И даже если оба массива в кортеже будут пустые, то len(locations)
всё равно вернёт 2.
Изображения не найдены.
(array([], dtype=int64), array([], dtype=int64))
Вообще не вижу смысла использовать np.where
, вы же ищите не группу одинаковых изображений на скриншоте, а один конкретный объект. Фактически вас устроит один результат с самым максимальным совпадением.
Доработал для вас пример, обратите внимание - добавил нахождение координат найденного объекта, если вдруг захочется на него нажать.
Код:
import cv2
import numpy as np
import pyautogui
import time
capture_area = (320, 830, 900, 900)
x, y, _, _ = capture_area
template = cv2.imread(r'C:\Users\Amgarak\Desktop\j.png')
threshold = 0.8
while True:
screenshot = pyautogui.screenshot(region=capture_area)
screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
result = cv2.matchTemplate(screenshot, template, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
if max_val >= threshold:
print(f"Изображение найдено! {max_val}")
h, w = template.shape[:2]
bottom_right = (max_loc[0] + w, max_loc[1] + h)
cv2.rectangle(screenshot, max_loc, bottom_right, (0, 255, 0), 2)
center_x = x + (max_loc[0] + w // 2)
center_y = y + (max_loc[1] + h // 2)
print(f"Центр совпадения на экране: x={center_x}, y={center_y}")
cv2.imshow('Result', screenshot)
cv2.waitKey(0)
cv2.destroyAllWindows()
pyautogui.press('left')
break
else:
print(f"Изображение не найдено.")
time.sleep(0.1)
Вывод:
Изображение не найдено.
Изображение не найдено.
Изображение найдено! 1.0
Центр совпадения на экране: x=509, y=943
Если нужно найти все места шаблона на изображении, то придётся добавить ещё и фильтрацию, так как np.where
может вернуть кучу близких по значению совпадений для одной и той же области.
Одним словом - можно обнаружить одно и то же место несколько раз с небольшим смещением.
Код:
import cv2
import numpy as np
import pyautogui
import time
capture_area = (320, 830, 900, 900)
x, y, _, _ = capture_area
template = cv2.imread(r'C:\Users\Amgarak\Desktop\j.png')
threshold = 0.8
min_distance = max(template.shape[:2]) * 0.5 # Минимальное расстояние между совпадениями (в пикселях)
while True:
screenshot = pyautogui.screenshot(region=capture_area)
screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
result = cv2.matchTemplate(screenshot, template, cv2.TM_CCOEFF_NORMED)
locations = np.where(result >= threshold)
if len(locations[0]) > 0:
print(f"Найдено {len(locations[0])} совпадений")
h, w = template.shape[:2]
filtered_locations = []
for loc in zip(*locations[::-1]):
too_close = False
for filtered_loc in filtered_locations:
if abs(filtered_loc[0] - loc[0]) < min_distance and abs(filtered_loc[1] - loc[1]) < min_distance:
too_close = True
break
if not too_close:
filtered_locations.append(loc)
print(f"Отфильтровано до {len(filtered_locations)} уникальных совпадений")
for top_left in filtered_locations:
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(screenshot, top_left, bottom_right, (0, 255, 0), 2)
center_x = x + (top_left[0] + w // 2)
center_y = y + (top_left[1] + h // 2)
print(f"Центр совпадения на экране: x={center_x}, y={center_y}")
cv2.imshow('Result', screenshot)
cv2.waitKey(0)
cv2.destroyAllWindows()
pyautogui.press('left')
break
else:
print(f"Изображения не найдены.")
time.sleep(0.1)
Вывод:
Изображения не найдены.
Изображения не найдены.
Найдено 18 совпадений
Отфильтровано до 2 уникальных совпадений
Центр совпадения на экране: x=797, y=916
Центр совпадения на экране: x=798, y=991
P.S. В своих задачах, я обычно устанавливаю пороговое значение на 0.8 - 0.9 так как добиться 1 получиться далеко не всегда.
Так же обратите внимание, что в pyautogui
уже есть удобная реализация работы с OpenCV
- Пример.