После внезапного обогащения энтузиастов, которые поиграли в начале года в приложение Notcoin в телеграм, подобные проекты стали расти как грибы. Да и грибников заметно поприбавилось. Но в данной статье мы не будем касаться тем блокчейна или финансов, а рассмотрим простой пример применения компьютерного зрения для фарма поинтов в самом популярном, после Notcoin, проекте - хомяке комбате. Название явно на что-то намекает, но да ладно.

Это не первый проект, который я автоматизирую, и не самый нуждающийся в этом. Да и без компьютерного зрения с автоматизацией хомяка можно спокойно обойтись. Но с ним, во-первых, интереснее, а во-вторых - это просто хороший пример с минимумом строк кода для демонстрации возможностей библиотеки cv2. Статья, соответственно, предназначена для энтузиастов и начинающих специалистов.

Начнем с того, что мы установим все необходимые зависимости и импортируем их в свой проект. Вот они, слева направо.

import pyautogui
import keyboard
import cv2
import numpy as np
import time

С помощью pyautogui наш бот будет управлять мышью. Keyboard пригодится для назначения горячих клавиш, чтобы управлять работой бота. cv2 наградит бота зрением, пусть и компьютерным, с помощью которого тот будет находить совпадения с искомым изображением. А numpy пригодится для работы с большими массивами, но тут он почти для галочки, не бойтесь. Модуль time тоже понадобится, чтобы ставить таймауты в работе программы.

Далее напишем небольшую конструкцию- переключатель.

def change():
    global work
    work = not work

work = False

Функция change при вызове всего лишь меняет значение переменной work, которая будет использована в бесконечном цикле. И если work будет False, работа нашего кода будет останавливаться. И наоборот запускаться, в противоположном случае.

Кстати, забыл упомянуть, что разработчики проекта, над которым мы сейчас проводим эксперимент, большие молодцы, и убрали возможность пользоваться приложением на десктопных устройствах. Поэтому для его запуска понадобится эмулятор Android.

Теперь определим основную логику работы бота:

  1. Он ищет совпадение с изображением полностью заполненной энергии.

  2. Если находит совпадение, ищет изображение монеты и кликает на неё энное количество раз.

  3. И всё это работает в бесконечном цикле.

Значит со скриншота приложения необходимо вырезать две области, которые помечены красным, и разместить их в отдельные файлы, конечно же.

Теперь напишем функцию для кликов по монетке. Она будет принимать путь к исходному изображению, а так же порог чувствительности для компьютерного зрения и интервал (таймаут) в секундах.

def click(template_path, threshold=0.8, interval=0.0001):

    template = cv2.imread(template_path, 0)
    w, h = template.shape[::-1]

    screenshot = pyautogui.screenshot()
    screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)

    # Переводим скриншот в оттенки серого.
    gray_screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)

    # Находим изображение на экране.
    result = cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED)
    loc = np.where(result >= threshold)

    # Кликаем по найденным координатам.
    for pt in zip(*loc[::-1]):
        center_x = pt[0] + w // 2
        center_y = pt[1] + h // 2
        for _ in range(260):
            pyautogui.doubleClick(center_x, center_y)
        break

Переменной template будет присвоено исходное изображение монетки, но в оттенках серого, так как мы указали в параметрах 0. Это необходимость, так как в оттенках серого компьютер зрит лучше. Сразу вычисляем высоту и ширину исходника, и присваиваем переменным. А далее по ходу исполнения кода он делает скриншот, сравнивает с исходником, получает координаты области с совпадением, и делает 260 даблкликов по ней. Координаты я ищу немного кривовато и в итоге loc содержит большой массив, из которого я использую лишь самые первые координаты, после чего цикл прерываю. Но лучше сделать не смог, извините.

А теперь напишем аналогичную функцию, но с задачей искать совпадение с картинкой полной энергии, после чего вызывать функцию click.

def find(template_path, threshold=0.9, interval=1):
    keyboard.add_hotkey('`', change)

    # Загружаем изображение, которое мы хотим найти на экране. 0- в градациях серого.
    template = cv2.imread(template_path, 0)
    w, h = template.shape[::-1]

    try:
        while True:
            if work:

                # Получаем скриншот экрана.
                screenshot = pyautogui.screenshot()
                screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)

                # Переводим скриншот в оттенки серого.
                gray_screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)

                # Находим изображение на экране.
                result = cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED)
                loc = np.where(result >= threshold)

                for _ in zip(*loc[::-1]):
                    click('coin.bmp')
                    break
                time.sleep(interval)
    
    except KeyboardInterrupt:
        print('\nВыход из программы')

В целом всё аналогично. Добавил лишь ожидание горячей клавиши, чтобы можно было остановить программу в любое время нажатием на тильду (Ё). Ну и для красоты заключил в try-except.

И это всё. Пишем последние строки и запускаем скрипт (не забыв нажать на Ё для запуска логики в цикле).

if __name__ == "__main__":
    find('energy.bmp')

По сути, этот код многофункционален, и его без труда, с минимальными изменениями, можно переделать под любые другие задачи. На всякий случай оставлю и полную версию кода:

import pyautogui
import keyboard
import cv2
import numpy as np
import time


def change():
    global work
    work = not work

work = False

def find(template_path, threshold=0.9, interval=1):
    keyboard.add_hotkey('`', change)

    # Загружаем изображение, которое мы хотим найти на экране. 0- в градациях серого.
    template = cv2.imread(template_path, 0)
    w, h = template.shape[::-1]

    try:
        while True:
            if work:

                # Получаем скриншот экрана.
                screenshot = pyautogui.screenshot()
                screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)

                # Переводим скриншот в оттенки серого.
                gray_screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)

                # Находим изображение на экране.
                result = cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED)
                loc = np.where(result >= threshold)

                for _ in zip(*loc[::-1]):
                    click('coin.bmp')
                    break
                time.sleep(interval)
    
    except KeyboardInterrupt:
        print('\nВыход из программы')


def click(template_path, threshold=0.8, interval=0.0001):

    template = cv2.imread(template_path, 0)
    w, h = template.shape[::-1]

    screenshot = pyautogui.screenshot()
    screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)

    # Переводим скриншот в оттенки серого.
    gray_screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)

    # Находим изображение на экране.
    result = cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED)
    loc = np.where(result >= threshold)

    # Кликаем по найденным координатам.
    for pt in zip(*loc[::-1]):
        center_x = pt[0] + w // 2
        center_y = pt[1] + h // 2
        for _ in range(260):
            pyautogui.doubleClick(center_x, center_y)
        break


if __name__ == "__main__":
    find('energy.bmp')

Не судите меня строго по этому скрипту, большую часть жизни я вообще бегал с пистолетиком, и пристрастился к разработке сравнительно недавно, поэтому всего лишь юный падаван в возрасте. Хотя могу писать и большие скучные штуки, но вот писать о них получится дольше, чем сам код. А если будут вопросы- добро пожаловать в телеграм. У меня там небольшой клуб по интересам.

Комментарии (21)


  1. monok8i
    03.06.2024 11:15

    В данный момент развития всех этих крипто ботов этот скрипт очень полезен, и у меня в голове была идея касательно написания подобного, только для Blum. Но никак не мог сообразить как захватить экран для просмотра, поэтому спасибо ;)


    1. temabed Автор
      03.06.2024 11:15

      Blum обсуждали как раз в телеге. Жава-скриптеры в этом больше преуспели. Заходи, пообщайся.


  1. Jury_78
    03.06.2024 11:15

    Можно спросить :) Что тут такое *loc -?


    1. wataru
      03.06.2024 11:15
      +1

      Это питоновская операция unpacking - список loc передается внутрь, как куча параметров. Список, видимо, двумерный, и вызов zip() на нем просто транспонирует матрицу.


    1. temabed Автор
      03.06.2024 11:15
      +1

      Как уже ответили выше, zip(*loc[::-1]) объединяет два массива координат (x и y) в один список пар координат (x, y). Оператор * распаковывает массивы перед передачей их в zip.


  1. SuperKozel
    03.06.2024 11:15
    +2

    кажется, после ноткоина всё это - лютая хренотень? я ноткоин потэпал, всем друзьям советовал тоже попробовать). Сейчас все будут лезть с ботами и клоны/форки никогда не несли никакой ценности.


    1. temabed Автор
      03.06.2024 11:15
      +2

      Ноткоин задал вектор, но будут и еще достойные проекты с такой системой вознаграждений. Я хотел на примере другого проекта (от снг-руководства бинанс) статью писать, но там бот отрабатывает слишком стыдно. А хомяк- это да, чистый клон, однако вероятность эйрдропа высока, так как он поймал лютый хайп.


  1. digtatordigtatorov
    03.06.2024 11:15

    С каких это подаванских блогов было вычитано, что компьют зрение шарит лучше в оттенках серого? По-моему это нифига не так, все зависит от задачи.


    1. temabed Автор
      03.06.2024 11:15

      Если конкретно, я вычитал, что метод поиска шаблонов работает лучше с изображениями в градациях серого. А как установить истину, я без понятия)


    1. fuckupyourface
      03.06.2024 11:15

      Интересно в каких задачах тебе выгоднее хранить 3 канала и повлияет ли это существенно на результат, прям оч интересно


      1. hexdrx
        03.06.2024 11:15

        Чуть поменьше язвительности..

        Делал cv бота для игры, нужно было различать обычные/редкие/эпические/легендарные шмотки, а отличаются они только цветом. Потому да, есть моменты когда это необходимо


  1. losander
    03.06.2024 11:15

    Сделал подобный на memefi, только он кликает по кд 60 секунд

    Единственный жирный минус в этом всём это то что эмуль жрёт ресурс, у меня лично даже 1080ti на ~30% грузило. Может есть способ снизить нагрузку?


    1. kuxwy
      03.06.2024 11:15

      Блин я не увидел слово эмуль в комментарии поэтому искал можно ли через pyautogui перемещать мышку по координатам, нашел, прочитал твой коммент, обосрался. Про эмуль могу сказать что, можно просто снизить производительность эмулятора


  1. Pirnazar
    03.06.2024 11:15

    Зачем всё усложняет ( использования компьютерного зрения) ?? Можно же просто time.sleep() использовать так никогда не будет кончаться монеты


    1. temabed Автор
      03.06.2024 11:15

      Да и без компьютерного зрения с автоматизацией хомяка можно спокойно обойтись. Но с ним, во-первых, интереснее, а во-вторых - это просто хороший пример с минимумом строк кода для демонстрации возможностей библиотеки cv2. Статья, соответственно, предназначена для энтузиастов и начинающих специалистов.


  1. Devastor87
    03.06.2024 11:15

    1. Какие суммы удалось/возможно "заработать"?

    2. Почему, если "всё так просто" и бота может написать любой (теперь ещё и скопипастить), это всё ещё будет работать?


    1. temabed Автор
      03.06.2024 11:15

      Статья не про заработок же, а про спорт) Но на самом деле интерес к таким проектам у меня проснулся после ноткоин. Мне их насыпали 20 000 за ничего неделание, т.е. я даже не играл толком. Актуальная цена чуть больше 2 центов за монету и растёт. Вот я и призадумался, надо было тогда писать скрипты, делать ферму и т.д.)))

      А доверия к этим проектам всё равно нет, поэтому из прочитавших статью повторит 0.01%. Так что никаких минусов для разработчиков. Больше проблем им приносят фермеры, но там есть способы их высислять.

      Но проектов таких будет всё больше, людей там будет всё больше, и вознагражления будут только расти, я считаю.


  1. Alkhonor
    03.06.2024 11:15

    Есть еще нюанс в том, что в Notcoin за кликеры по итогам срезали 99% нафармленного. Поэтому такая автоматизация может выйти выстрелом себе в ногу