Поиск цвета на изображении, на примере поиска HP персонажа

 

При создании ботов для онлайн игр часто возникает необходимость выяснить, сколько хитпоинтов осталось у вашего персонажа или у NPC на данный момент. Как правило этот вопрос решается с использованием программ типа CheatEngine, ArtMoney  с помощью которых можно найти адрес по которому хранятся интересующие нас данные.  А затем в процессе выполнения программы-бота с помощью WinAPI функций OpenProcess,ReadProcessMemory, WriteProcessMemory можно читать значения в полученных адресах. Как правило это позволяет просто, надежно и без проблем получать те данные которые вам нужны. Если конечно в приложении не предусмотрена защита от таких действий.

Мы же не ищем легких путей, и будем пытаться вычислять количество HP персонажа анализируя графическую информацию в окне игры. Для создания такого приложения мы будем использовать возможности программы NOMAD  в ней также есть возможность объявить выше описанные WinAPI функции и сделать все по феншую, но мы этого делать не станем. Вместо этого мы будем использовать инструменты анализа изображений, которые есть в этой программе.

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

Рассмотрим ситуацию в целом. Ниже приведен скриншот игры в котором мы должны найти количество HP нашего персонажа, в красную рамку выделен прямоугольник в котором нам предстоит искать HP:

l2winSel

Казалось бы все просто, для того чтобы вычислить количество HP, нам необходимо вычислить длину ярко-красной полоски и длину темно-красной полоски,это будет 100%, далее вычисляем длину только ярко-красной полоски  и вычисляем процент оставшихся хп по формуле  ((длина яркой части) /(длина темной части + длина яркой части))*100.

Но рассмотрев полоски HP поближе:

fullhpt

emptyHP

 

Мы видим, что на самом деле  данная полоска представляет из себя целый винегрет цветов, причем как по горизонтали, так и по вертикали. А темная полоска еще к тому же и прозрачная, а значит изменения фона видно сквозь эту полоску, т.е. она меняет оттенки при движении персонажа. К счастью «найти» длину яркой части полоски оказалось делом не сложным, а вот вычислить длину только темной полоски мне так и не удалось, но все же мне удалось вычислить длину обоих полосок вместе, что меня вполне устроило.

В программе NOMAD существует механизм позволяющий работать с диапазонами цветов как с одним цветом, этим механизмом то нам и предстоит воспользоваться. В этой статье я не буду описывать все этапы работы с программой с нуля, о них можно узнать например по этой ссылке, или из документации к программе. 

Для использования функции поиска цвета по диапазону цветов, нам сначала необходимо создать как минимум 2 диапазона цветов. Один диапазон соответствующий яркой части полоски HP, и второй соответствующий темной части полоски.

Сначала нажав кнопку «ScreenShot» сделаем снимок экрана с окном игры. Все окно нам не понадобится, поэтому с помощью кнопки «Cut» можно вырезать только участок с полоской HP и нажав кнопку «Magnifire» увеличить его до удобного размера.

Безымянный

Чтобы создать диапазон цветов  в программе NOMAD, необходимо добавить новый элемент в раздел Colors в дереве объектов:

OIFullTree

Для этого на пункте Colors нажмем правой кнопкой мыши и выберем пункт «добавить».

Исследуя изображение курсором мыши анализируем цифры в низу экрана в разделе RGB

rgb

 

Исходя из проанализированных данных мы должны заполнить форму появившуюся после того как мы добавили новый Color в дерево объектов. Вот что получилось у меня для ярко-красного цвета:

ColFull

 

Слева мы указываем диапазоны цветов по трем компонентам R G и B которые входят в искомый диапазон цветов. Если мы заметили, что какая то компонента, например R  всегда больше  G, то поставим соответствующую галочку справа, для того чтобы уточнить условие отбора цветов. Также если 2 компоненты всегда примерно равны, то ставим одну из верхних правых галочек. Almost Equal delta указывает разницу между двумя компонентами цвета при которой они будут считаться равными. При этом стоит иметь ввиду, что если эту галочку мы не поставим, то автоматически будет применен обратный фильтр т.е.  цвета должны быть обязательно не равны (в пределах дельты).

В Result color мы в формате RGB указываем цвет к которому будет преобразован диапазон цветов. В нашем случае это красный. (Red-255 остальные компоненты 0). Нажав кнопку Save мы сохраним в базу данных введенные данные. Нажав кнопку Refresh TV мы увидим скриншот в преобразованном к итоговому цвету виде.

ColFullFiltered

Вот что вышло у меня. По длине вся яркая полоска прошла фильтр, а темная в наш фильтр не попала. Т.е. мы можем выяснить длину полоски с оставшимся HP.

То же самое делаем для темной части полоски.

Emptylhpt

emptyHPFiltered

Идеальной темной полоски у меня не вышло, но т.к. мы используем темную полоску только для вычисления общей длины всей полоски HP то нас это устраивает.

Далее, т.к. в NOMAD цвет искать можно только внутри какого нибудь шаблона, да и по-другому у нас едва ли вышло что нибудь хорошее, то необходимо найти табличку, внутри которой находится полоска с HP.

hpTab

 Если мы найдем данную форму, то поиск цвета будет вестись только внутри нее, что явно существенно уменьшит наши шансы найти чего нибудь «лишнее».

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

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

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

Приступим, сначала создаем шаблон окна игры Lineage 2. Нажав кнопку ScreenShot сделаем снимок экрана, затем нажмем кнопку fixBorders, скриншот будет переведен в монохромный вид. На этом изображении мы должны подготовить данные для будущего шаблона. С помощью кнопки Delete rect убираем все лишнее, в шаблоне должны остаться только статичные части изображения, недопустимо включать в шаблон детали которые в процессе работы приложения исчезнут или существенно изменят свой вид, т.к. в таком случае наш шаблон просто не будет найден. Итоговый результат должен выглядеть примерно следующим образом:

la2tempPrep2

У нас осталось 4 фрагмента, которые мы и занесем в шаблон, важно понимать, что фрагменты TL и TR должны быть равны друг другу по высоте (допускается небольшая разница), также как и DL и DR. Это связанно с тем что TR будет искаться напротив TL, следовательно, если он будет больше размером, чем TL он просто не будет найден. По похожим причинам TL и DL, должны быть равны друг другу по ширине, такое же правило должно соблюдаться для TR и DR. Этого легко достичь если использовать удаление лишних точек в режиме Delete Rect. Поиск начинается с фрагмента TL и идет по часовой стрелке, если TL не найден, то не найдено все изображение, если не найден один из последующих фрагментов, то программа пытается искать остальные фрагменты против часовой стрелки. При нахождении 3х фрагментов изображение считается найденным.

Итак теперь нам необходимо внести подготовленные фрагменты в базу данных шаблонов, для этого нажимаем кнопку Select, и выделяем например фрагмент TL, внутри пунктирного квадрата щелкаем правой кнопкой мыши, появляется окно, которое необходимо заполнить следующим образом:

la2TL

Тут L2 это имя шаблона по которому мы будем обращаться к нему из кода программы и под которым будут объединены все фрагменты. Item name — тут мы заполняем имя фрагмента.  Родителя у данного шаблона не будет. Эту операцию необходимо повторить для оставшихся трех фрагментов, каждый раз указывая в Item name имя фрагмента, согласно тому что было нарисовано на картинке выше. Имя шаблона мы всегда пишем L2 и соглашаемся, с вопросом о том, что такой шаблон уже существует и его нужно перезаписать.

Далее, т.к. программа не может сама понять, какой из этих фрагментов где находится (слева сверху, слева снизу и т.д.), то мы должны это указать сами в явном виде. Выбирая в дереве объектов каждый из фрагментов, нам необходимо заполнить свойство disposition

OI1

Для TL так как это левый верхний фрагмент заполняем TopLeft, TR — TopRight, DR — BottomRight, DL — BottomLeft.

На картинке также выделен параметр k — это коэффициент совпадения, по умолчанию он равен 0.9. Для настройки указанной на картинке, при поиске фрагмента, он будет считаться найденным если совпадет хотя бы на 80%.

Далее нажав на пункт L2 в дереве объектов, нам необходимо в его свойствах

l2OI3

Выставить свойство FourSearch в значение TRUE.

На этом мы закончили создание шаблона окна игры и можем использовать его для поиска. Далее нам необходимо создать подчиненный шаблон рамки внутри которой и нарисована линия HP. Этот шаблон мы будем создавать аналогично тому как мы делали это для окна игры, с той лишь разницей, что он будет создаваться в режиме ColMap (одноименная кнопка на форме активирует его). Этот режим фильтрует изображение по диапазону цветов, стало быть, нам как и в случае с поиском цвета сначала необходимо создать «цвета» в которых мы будем искать эту рамку.

В результате своих изысканий я сошелся на том, что нам хватит 3 цвета. Один на левую часть рамки и 2 на правую. Поясню, что я имею ввиду. Итак для левой части рамки я создал цвет LeftSide со следующими настройками:

LeftSide

Этот диапазон цветов позволяет нам увидеть искомую нами рамку

hpTab

в режиме ColMap, по цвету LeftSide вот в таком виде:

hpTabLeftSide2

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

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

Итак полученное изображение позволяет нам создать шаблоны фрагментов TL и DL

hpTabLeftSide3

Для правой стороны у меня получилось решить вопрос только двумя цветами, один для верхней части, один для нижней.

RB

RT

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

la2TL

Необходимо кликнуть в дереве объектов, на объект L2, и тогда напротив надписи Parent появится надпись L2. Общий шаблон я назвал MyHPTab, это имя необходимо указывать в поле Object Name. Для режима ColMap в поле MainColor должен быть выбран цвет в котором этот шаблон будет искаться, т.е. например LeftSide, но если вы все делаете правильно, то при появлении окна он уже будет выбран автоматически. В остальном повторяем все действия которые мы делали для шаблона окна игры.

Вот наконец, самое страшное позади, все шаблоны созданы и можно приступить к программированию.  Для этого нажмем кнопку Form Designer. В появившейся форме на закладке Code можно программировать. Функция поиска HP будет выглядеть следующим образом:

 Данная функция возвращает количество оставшегося у персонажа HP. В коде все подробно прокомментировано. Но поясню еще некоторые моменты. Я обещал, что L2 есть имя шаблона по которому мы будем обращаться к нему из кода программы, но в коде программы мы его не видим совсем. Это происходит так потому, что MyHPTab является подчиненным L2 и поэтому когда мы вызываем поиск MyHPTab, то L2 будет искаться автоматически и если L2 найден не будет, то не будет найден и MyHPTab.

В коде мы вызываем одну единственную функцию MyHPTab.FindColor(‘FullHP|EmptyHP’, 3) — собственно она и ищет участок изображения с нужным цветом. При этом в качестве аргументов функции указаны сразу 2 цвета разделенные знаком «|», что означает «или», т.е. функция в случае успеха вернет координаты где сосредоточены искомые цвета, при этом искаться будет и цвет FullHP и EmptyHP и если даже однин из этих цветов на изображении не найден   то, функция вернет координаты второго цвета и будет завершена успешно. Если же аргумент указать как ‘FullHP,EmptyHP’, то  здесь «,» означает «И», т.е. если хотя бы 1 из цветов не будет найден, то функция вернет ложь, и будет считаться что поиск прошел неудачно. В этом аргументе вы можете указывать любое количество цветов разделенных И или ИЛИ. Второй аргумент функции указывает чувствительность, или иными словами количество пикселей, которые должны следовать подряд, чтобы функция посчитала что в данной области есть искомый цвет. Т.е. если мы указываем 3, то встретив одиночный пиксель нужного цвета функция его проигнорирует, но встретив группу из трех пикселей будет считать это место началом области, где расположен искомый цвет. Причем разрывы между областями с искомыми цветами игнорируются. Нажав кнопку Debug List можно просмотреть снимки экрана с выделенными на них успешно найденными областями цветов. Если программа запускалась в отладочном режиме.

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

Чтобы использовать нашу функцию и проверить что получилось, добавим на форму кнопку и текст Label1. И в событие кнопки «OnClick» поместим следующий код:

 

 У меня получилась следующая форма:

form

Как создавать форму и добавлять события подробно было описано тут.

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

Вот и все, программу можно запускать и смотреть сколько  у вас осталось HP :-)

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

Исходник программы можно скачать тут.

 

LineageHpSearch
LineageHpSearch
NBase.noc
59.4 KiB
606 Downloads
Детали

Поиск цвета на изображении, на примере поиска HP персонажа: 1 комментарий

  1. Комментарии запрещены в связи с нежеланием администрации бороться со спамерами. Все вопросы, пожелания и замечания просьба оставлять на форуме. Обратная связь с пользователями очень важна для нас.

Комментарии запрещены.

Bot Development Engine