Способы поиска изображения и текста на экране с применением Python
Методы поиска изображения и текста на экране с помощью Python
В задачах автоматизации GUI часто требуется обнаружить определенное изображение или текст на экране. Python предоставляет несколько библиотек, позволяющих решить эту задачу. В этой статье рассматриваются различные подходы, их сильные стороны и возможные сложности.
Как наиболее эффективно найти изображение на экране с использованием встроенного механизма pyautogui и OpenCV?
Наиболее сбалансированным решением является использование библиотеки pyautogui с параметром confidence, который активирует алгоритм сопоставления шаблонов на основе OpenCV. Этот подход подходит для большинства сценариев, где изображение может быть найдено с небольшими вариациями (например, разные версии интерфейса).
import pyautogui
# Поиск изображения кнопки на экране с порогом уверенности 0.8
button_location = pyautogui.locateOnScreen('button.png', confidence=0.8)
if button_location:
pyautogui.click(button_location)
else:
print("Изображение не найдено")
Python найти на экране (поиск изображения/текста на экране с помощью python)
Пояснение: Функция locateOnScreen делает скриншот всего экрана, сравнивает его с переданным шаблоном и возвращает координаты левого верхнего угла найденной области. Параметр confidence задает минимальную степень сходства (от 0 до 1). Значение 0.8 означает, что совпадение должно быть не менее 80%.
Типичная проблема: Изображение не находится из-за разницы в разрешении экрана или масштабе интерфейса. В таких случаях можно уменьшить порог confidence (например, до 0.7) или использовать предварительную обработку изображения (например, приведение к серому).
Ошибка: pyautogui.locateOnScreen возвращает None, хотя изображение явно присутствует на экране. Причина: изображение сохранено в неверном формате (например, PNG с альфа-каналом). Решение: сохранять шаблоны без прозрачности (RGB, не RGBA).
Как найти область на экране по шаблону изображения, когда pyautogui не справляется (низкая скорость, неточность)?
Библиотека OpenCV позволяет реализовать шаблонное сопоставление напрямую, предоставляя больше контроля над алгоритмом. Это полезно, когда требуется высокая скорость или нестандартные методы поиска.
import cv2
import pyautogui
# Делаем скриншот
screenshot = pyautogui.screenshot()
screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
template = cv2.imread('template.png', 0)
screenshot_gray = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
result = cv2.matchTemplate(screenshot_gray, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val > 0.8:
top_left = max_loc
h, w = template.shape
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(screenshot, top_left, bottom_right, (0,255,0), 2)
print(f"Найдено в {top_left}")
else:
print("Не найдено")
Пояснение: Скриншот преобразуется в массив numpy, затем применяется функция matchTemplate с методом нормализованной корреляции. Максимальное значение результата указывает на наилучшее совпадение. Порог уверенности выбирается экспериментально.
Проблема: cv2.matchTemplate работает медленно на больших экранах. Решение: предварительно уменьшить разрешение скриншота или использовать метод cv2.TM_SQDIFF_NORMED (требует нахождения минимума).
Как извлечь текст из скриншота и найти нужное слово или фразу?
Библиотека pytesseract (обертка для Tesseract OCR) позволяет распознавать текст на изображениях. Это подходит для поиска текстовых элементов, которые трудно найти как изображение (например, динамические данные).
import pytesseract
from PIL import ImageGrab
# Делаем скриншот области
screenshot = ImageGrab.grab(bbox=(100, 100, 500, 300))
text = pytesseract.image_to_string(screenshot, lang='rus+eng')
if 'Нужный текст' in text:
print("Текст найден!")
else:
print("Текст не обнаружен")
Пояснение: pytesseract.image_to_string возвращает распознанный текст. Параметр lang задает языки (русский и английский). Для повышения точности можно предварительно обработать изображение (бинаризация, устранение шума).
Ошибка: pytesseract.pytesseract.TesseractNotFoundError. Решение: установить Tesseract OCR отдельно и указать путь к исполняемому файлу: pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'.
Как распознать русский текст на экране с высокой точностью, включая сложные шрифты?
Модуль easyocr использует глубокие нейронные сети и поддерживает множество языков, включая русский. Его точность выше, чем у Tesseract, но скорость ниже. Подходит для сценариев, где качество распознавания критично.
import easyocr
reader = easyocr.Reader(['ru', 'en'])
result = reader.readtext('screenshot_area.png')
for (bbox, text, confidence) in result:
if 'Искомый' in text:
print(f"Найден текст: {text} с уверенностью {confidence:.2f}")
Пояснение: easyocr.Reader загружает модель для указанных языков. Функция readtext возвращает список кортежей: координаты прямоугольника, текст и уверенность. Модель лучше распознает текст под углом или с разными размерами.
Проблема: easyocr может быть медленным при первом запуске из-за загрузки модели. Решение: сохранять экземпляр reader для повторного использования. Также возможны высокие требования к памяти (GPU рекомендуется).
Как быстро найти изображение без установки дополнительных библиотек, используя только pyautogui?
Pyautogui предоставляет функцию locateOnScreen без параметра confidence. Она использует попиксельное сравнение, что требует точного совпадения. Подходит для статичных интерфейсов.
import pyautogui
# Поиск точного совпадения
position = pyautogui.locateOnScreen('exact_button.png') # без confidence
if position:
pyautogui.click(position)
Пояснение: Изображение должно быть точной копией области экрана в текущий момент. Любое изменение (тень, другой оттенок) приведет к отсутствию совпадения. Этот метод самый простой, но наименее устойчивый.
Ошибка: Изображение сохранено с другим расширением (например, JPG вместо PNG) или с потерей качества. Решение: использовать PNG без сжатия. Также помогает уменьшение размера шаблона до минимально возможного.
Как найти все вхождения изображения на экране (например, все иконки одного типа)?
Функция locateAllOnScreen возвращает генератор всех позиций, где обнаружено совпадение. Полезна для массовых действий.
import pyautogui
for pos in pyautogui.locateAllOnScreen('icon.png', confidence=0.9):
pyautogui.click(pos)
# или сохранить координаты
Пояснение: Параметр confidence действует так же, как и для locateOnScreen. Генератор может быть преобразован в список. Важно помнить о производительности: на большом экране и множестве совпадений процесс может быть медленным.
Проблема: Ложные срабатывания при низком confidence. Решение: увеличить порог или добавить проверку размера найденной области (например, только если ширина и высота совпадают с шаблоном).
Выбор конкретного метода зависит от условий задачи: требуемой точности, скорости, стабильности интерфейса и доступных вычислительных ресурсов. Комбинирование подходов (например, поиск изображения для локализации области, а затем OCR для извлечения текста) часто дает наилучшие результаты.
Расширенные примеры и нестандартные сценарии
Поиск изображения с предварительным масштабированием шаблона
Когда интерфейс отображается в другом масштабе (например, 125% в Windows), шаблон может не совпадать. Решение: применить несколько масштабов шаблона и выбрать наилучший.
import cv2
import numpy as np
import pyautogui
def find_template_multiscale(template_path, scale_range=(0.8, 1.2), step=0.1):
screenshot = pyautogui.screenshot()
screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2GRAY)
template_orig = cv2.imread(template_path, 0)
best_val = 0
best_loc = None
best_scale = None
for scale in np.arange(scale_range[0], scale_range[1], step):
w = int(template_orig.shape[1] * scale)
h = int(template_orig.shape[0] * scale)
if w == 0 or h == 0:
continue
resized = cv2.resize(template_orig, (w, h), interpolation=cv2.INTER_AREA)
result = cv2.matchTemplate(screenshot, resized, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
if max_val > best_val:
best_val = max_val
best_loc = max_loc
best_scale = scale
return best_loc, best_val, best_scale
loc, val, scale = find_template_multiscale('template.png')
print(f"Лучшее совпадение: {val:.2f} при масштабе {scale:.2f}, координаты {loc}")
Результат:
Лучшее совпадение: 0.93 при масштабе 1.00, координаты (200, 150)
Распознавание текста с предварительной обработкой (бинаризация и удаление шума)
Для сложных фонов или неконтрастного текста улучшить качество OCR можно с помощью OpenCV.
import cv2
import pytesseract
import numpy as np
from PIL import ImageGrab
# Скриншот области
bbox = (100, 100, 800, 600)
im = ImageGrab.grab(bbox)
im_np = np.array(im)
gray = cv2.cvtColor(im_np, cv2.COLOR_RGB2GRAY)
# Бинаризация OTSU
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Удаление шума (морфологическое закрытие)
kernel = np.ones((2,2), np.uint8)
cleaned = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# OCR
custom_config = r'--oem 3 --psm 6'
text = pytesseract.image_to_string(cleaned, lang='rus+eng', config=custom_config)
print(text)
Результат:
Распознанный текст без лишних артефактов.
Поиск текста с получением координат для клика
Комбинирование OCR и pyautogui для автоматического нажатия на найденную текстовую строку.
import pytesseract
from PIL import ImageGrab
import pyautogui
import re
# Скриншот всего экрана
screen = ImageGrab.grab()
# Распознавание с данными о позициях
data = pytesseract.image_to_data(screen, lang='rus', output_type=pytesseract.Output.DICT)
# Ищем строку, содержащую "Сохранить"
n_boxes = len(data['text'])
for i in range(n_boxes):
if 'Сохранить' in data['text'][i]:
x = data['left'][i]
y = data['top'][i]
w = data['width'][i]
h = data['height'][i]
# Кликаем в центр найденного прямоугольника
pyautogui.click(x + w//2, y + h//2)
break
Пояснение: image_to_data возвращает подробную информацию о каждом слове. Координаты могут быть использованы для любого действия.
Мониторинг изменений на экране с помощью сравнения скриншотов
Обнаружение изменений (например, появление уведомления) можно реализовать через разность изображений.
import numpy as np
import pyautogui
import cv2
import time
prev = pyautogui.screenshot()
prev = cv2.cvtColor(np.array(prev), cv2.COLOR_RGB2GRAY)
while True:
time.sleep(1)
curr = pyautogui.screenshot()
curr = cv2.cvtColor(np.array(curr), cv2.COLOR_RGB2GRAY)
diff = cv2.absdiff(prev, curr)
# Сумма изменений
change = np.sum(diff) / 255
if change > 5000: # Порог чувствительности
print("Изменение обнаружено!")
# Далее можно искать конкретный шаблон или текст
break
prev = curr
Результат: Программа ждет изменения на экране и сообщает о нем.
Использование MSS для быстрых скриншотов в связке с OpenCV
MSS (Multiple Screen Shot) делает скриншоты быстрее, чем PIL.ImageGrab. Полезно для приложений реального времени.
import mss
import cv2
import numpy as np
with mss.mss() as sct:
# Захват монитора 1
monitor = sct.monitors[1]
screenshot = sct.grab(monitor)
img = np.array(screenshot)
img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
# Далее поиск шаблона
template = cv2.imread('template.png', 0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
result = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)
# ... обработка
Преимущество: MSS работает быстрее традиционных методов, особенно при частых скриншотах.