|
Разработка findcolor, findimage, Pure lua |
|
|
sutra |
25.3.2021, 16:34
|
Adept
Сообщений: 923
Регистрация: 10.8.2018 Группа: Пользователи Наличность: 0
Пользователь №: 19.007
|
Я в теме. Я давно отказался от передачи массивов. Делаю сразу глобальный массив (достаточно большой) через ffi , который использует и финдколор и все кому надо, и никаких тормозов. Если данные требуются позже (что крайне редко) ничто не мешает запомнить их отдельно. Понятно что это не эстетично, но совершенно нет потерь времени, необходимое при выделении памяти на массивы. По факту, при адекватных зонах поиска, время поиска - НУЛЬ.
Мне очень удобно. Грубо говоря вызываю if findcolor(... и данные поиска уже лежат в глобальном массиве и ими пользуешься напрямую в любых следующих действиях .
Сейчас буду пробовать твой вариант, если получится, то проблема будет решена для всех случаев жизни - спасибо!
Кстати, вот ещё замечание. От мощности видюхи зависит скорость доступа к данным, остальное от камня. Я успел до кризиса поменять на RTX 2070 - как чувствовал, что подорожают. Небольшой прирост в скорости всё-таки получил.
|
|
|
|
DarkMaster |
25.3.2021, 17:12
|
Модератор UOPilot
Сообщений: 9.596
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28801
Пользователь №: 11.279
|
Цитата Я в теме. Ловлю на слове. Пока хочу допилить, то, что есть, чтобы понять, как оно вообще работает, на чем сыпит скорость и т.д. У меня на данный момент финдколор на фул хд отрабатывает за 0.02 секунды, ирония в том что из этого 0.015 занимает парсинг параметров. Нужно допиливать. Код уже переписан раз на 10. Цитата Что-то у меня не получилось, выдаёт три нуля. Адрес присваивал шестнадцатиричное число из первого скрипта. Можно в коде увидеть?
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd: Kov____ Писать в личку.
|
|
|
|
sutra |
25.3.2021, 17:42
|
Adept
Сообщений: 923
Регистрация: 10.8.2018 Группа: Пользователи Наличность: 0
Пользователь №: 19.007
|
Да я понял, но у меня в основном нагрузка на файндимидж. Поиск конечно идёт по локальным позициям, а не по всему экрану. Ищутся все кнопки, все цифры, все наименования. Один getimage и потом мгновенно всё распознаётся. Ищу как и говорил ранее, не картинки а силуэты!! Например силуэты цифр состоят из 2-х ... 5-ти пикселей, которые и анализируются. Сначала создаются готовые наборы таких силуэтов, от 3-х, до 6-ти на каждый символ. И этого хватает для однозначного поиска. Главное ручками (и головой) правильно создать эти силуэты. Я делаю для себя. А ты ставишь суперзадачу. Сделать алгоритм, работающий за тупого юзера. Будет время потестю, поделюсь результатами.
Конечно всё зависит от конкретной задачи, главное правильно определять где фон (его надо игнорировать) и где значимые пиксели (вот их и надо искать).
|
|
|
|
DarkMaster |
26.3.2021, 0:34
|
Модератор UOPilot
Сообщений: 9.596
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28801
Пользователь №: 11.279
|
Из забавного. Речь пойдет о чтении из памяти данных, которые уже существуют, их размер известен. Т.е. сознательно двигаются указатели, в т.ч. происходит выход за пределы массива (мы уверены, что за пределами массива все так же находятся данные). При тестах инициализация массивов, присвоение начальных адресов были вынесены за пределы бенчмарка. Т.е. непосредственно время обращения в if'ов.
local p = ffi.new("unsigned char[3]") - тормоз. Гораздо эфективнее использовать конструкцию: local p = ffi.new("unsigned char[1]") двигая указатель на массив.
еще шустрее использовать: ffi.cast("unsigned char*",address) при этом если объявить: local rmem = ffi.cast rmem("unsigned char*",address) то дополнительно выиграем в скорости.
rmem ("unsigned char*",i)[0],rmem ("unsigned char*",i+1)[0],rmem ("unsigned char*",i+2)[0] проигрывает в скорости: rmem ("unsigned char*",i)[0],rmem ("unsigned char*",i)[1],rmem ("unsigned char*",i)[2] при этом вполне очевидно, что полей [1], [2] не существует, но все прекрасно работает - проверок на выходы за пределы массивов в ffi нет.
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd: Kov____ Писать в личку.
|
|
|
|
DarkMaster |
26.3.2021, 16:49
|
Модератор UOPilot
Сообщений: 9.596
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28801
Пользователь №: 11.279
|
ну вообще типа да, но типа нет. Поуму нужно делать потоки. Пока не берусь. Хотя бы потому, что не очень хорошо представляю сам для себя, как все это должно собираться. На данный момент есть четкое правило - все найденные результаты упорядочены слева-направо и сверху вниз, так же есть ограничение на количество найденных результатов. При разбиении на части может получиться путаница, если делать сортировку, то нужно дожидаться окончания обработки до некоторой позиции N в которой собрано необходимое количество изображений и т.д. Пока я для себя в голове не решил, как это будет выглядеть правильно и какое поведение будет наиболее востребовано и наиболее нативно ожидаемо для пользователя. // Cirus подогнал getimage нормальный для работы через хендл.
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd: Kov____ Писать в личку.
|
|
|
|
DarkMaster |
26.3.2021, 17:31
|
Модератор UOPilot
Сообщений: 9.596
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28801
Пользователь №: 11.279
|
Автор Cirus code
Код --lua local ffi = require("ffi") local SRCCOPY = 0x00CC0020 local DIB_RGB_COLORS = 0 local BI_RGB = 0 ffi.cdef[[ typedef long LONG; typedef unsigned short WORD; typedef unsigned long DWORD; typedef unsigned char BYTE; typedef void *LPVOID; typedef struct {DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant;} BITMAPINFOHEADER; typedef struct {BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved;} RGBQUAD; typedef struct {BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1];} BITMAPINFO; int GetDC(int hWnd); int ReleaseDC(int hWnd, int hDC); int SelectObject(int hdc, int h); int CreateCompatibleDC(int hdc); int CreateCompatibleBitmap(int hdc, int cx, int cy); bool DeleteObject(int ho); bool BitBlt(int hdc, int x, int y, int cx, int cy, int hdcSrc, int x1, int y1, unsigned long rop); int GetDIBits(int hdc, int hbm, unsigned int start, unsigned int cLines, LPVOID lpvBits, BITMAPINFO* lpbmi, unsigned int usage); ]]
function Find(x, y, x2, y2, handle) local C = ffi.C local hdcWindow = C.GetDC(handle or 0) -- если хендл не указан, то получим скрин с экрана local hdcMemDC = C.CreateCompatibleDC(hdcWindow) local hbmScreen = C.CreateCompatibleBitmap(hdcWindow, x2-x, y2-y) C.SelectObject(hdcMemDC,hbmScreen) C.BitBlt(hdcMemDC, 0, 0, x2-x, y2-y, hdcWindow, x, y, SRCCOPY) -- сохранить в памяти скрин с окна или экрана
local bi = ffi.new('BITMAPINFO', { {ffi.sizeof('BITMAPINFOHEADER'), x2-x, y2-y, 1, 32, BI_RGB,0,0,0,0,0} }) C.GetDIBits(hdcWindow, hbmScreen, 0, y2-y, nil, bi, DIB_RGB_COLORS) -- узнать какого размера нужен массив
local bits = ffi.new('unsigned char[?]', bi.bmiHeader.biSizeImage) -- выделить память под битовый массив local result = C.GetDIBits(hdcWindow, hbmScreen, 0, y2-y, bits, bi, DIB_RGB_COLORS) -- получить битовый массив -- log (result) -- если функция выполнена успешно, то вернёт высоту изображения иначе 0 -- log('Размер массива: ' .. tostring(bi.bmiHeader.biSizeImage) .. ' байт')
-- вывод в лог --------------- -- local s = '' -- local len = 0 -- local arr = {} -- for i=0, bi.bmiHeader.biSizeImage-1, 4 do -- тут поиск нужных пикселей -- local R, G, B = bits[i+2], bits[i+1], bits[i] -- s = s .. tostring(R + G * 256 + B * 65536) .. ' ' -- len = len + 1 -- if len == x2 - x then -- table.insert(arr, 1, {s}) -- s = '' -- len=0 -- end -- end -- -- for i = 1, #arr do -- log (table.concat(arr[i], ' ')) -- end -------------------
-- удаление ресурсов C.ReleaseDC(handle or 0, hdcWindow) C.DeleteObject(hdcMemDC) C.DeleteObject(hbmScreen) end
log 'clear' log 'mode compact' local t = os.clock() Find(200, 100, 210, 115, workwindow()) -- координаты области 200, 100, 210, 115, последний параметр хендл окна(можно не указывать) log('Время получения битового массива: ' .. tostring(os.clock()-t))
Сообщение отредактировал DarkMaster - 27.3.2021, 13:36
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd: Kov____ Писать в личку.
|
|
|
|
DarkMaster |
27.3.2021, 13:42
|
Модератор UOPilot
Сообщений: 9.596
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28801
Пользователь №: 11.279
|
Собственно то, как вот оно есть. findcolor manual
Код -- findcolor -- Функция поиска цвета либо нескольких цветов, -- с возможностью задать некоторые отклонения в оттенке. -- Синтаксис: -- result = findcolor(<x_start, y_start, x_end, y_end | table_crds>, -- <color> [,method [,count [,deviaton [,deviation_type [,abs_flag]]]]) -- -- <x_start, y_start, x_end, y_end | table_crds> -- Координтаы задаются в виде прямоугольной области -- с указанием координаты левого верхнего угла -- и правого нижнего угла. -- Координаты могут быть заданы четырмя переменными: -- x_start, y_start, x_end, y_end -- либо массивом с аналогичной структурой данных: -- {x_start, y_start, x_end, y_end} -- Отсчет координат начинатся с 0, а не 1. -- Т.е. для FullHD область поиска будет -- 0, 0, 1919, 1079. -- -- <color> -- Цвета, которые непосредственно ищются. -- Синтаксис списка цветов: -- <color | {color_1 [,color_2 [,... [,color_N]]]}> -- Допустимые форматы цвета: -- < dec_hex_color | dec_hex_color_1-dec_hex_color_2 | -- {[r=val_1] [,g=val_2] [,b=val_3]} | [{r=val_1-val_2] [,g=val_3-val_4] [,b=val_5-val_6}] > -- Форматы цветов можно кобинировать в рамках списка. Например: -- 133972, 0x5060DD-0x5170DD, {r=10, g=0xFF, b=12-18} -- -- [method] -- Метод поиска. Значение по умолчанию: 2 -- 0/не задан - Быстрый метод. Получить изображение всего экрана. -- 1 - устаревший метод, используется для совместимости. Очень медленный. -- Для получения изображения всего экрана, а не окна используйте abs_flag. -- 2 - надежный метод. Средняя скорость. -- Для получения изображения всего экрана, а не окна используйте abs_flag. -- хендла_окна - очень быстрый метод. Работает с перекрытыми окнами. -- Предпочтительно использовать именно его. Не работает с некоторыми приложениями. -- Для корректной работы может потребоваться задать хендл родительского окна. -- адрес_картинки - Адрес изображения в формате bmp 24 бита. -- "my_image.bmp" - изображение рядом с exe пилота. -- "folder\\my_image.bmp" - изображение в папке folder рядом с exe пилота -- "\\my_image.bmp" - изображение в корне диска, на котором лежит пилот. -- [[d:\uopilot\images\my_image.bmp]] - абсолютный путь. -- Учтите, что при задании адресов в lua символ '\' необходимо удваивать, -- либо заменять на '/', либо брать весь адрес в двойные квадртные скобки. -- адрес_памяти, - Поиск в ранее полученном изображении по средством функции getimage() -- высота_изобр, Указывается адрес битовой маски, высота изображения, ширина и количество -- ширина_изобр, байт на каждую строку. Из-за выравнивания размер строки может быть -- длина. не кратным битности изображения. Данный параметр так же используется -- для определения формата битовой маски (24 бита либо 24 бита цвет + 8 резерв). -- -- [count] -- Количество искомых изображений. 0 | -1 - найти все. -- -- [deviation] -- Допустимые отклонения цвета. -- Синтаксис: -- deviation_general | {blue, green, red} | -- {blue_bottom, green_bottom, red_bottom, blue_upper, green_upper, red_upper} -- Отклонения цвета может быть задано одним числом на все каналы в + и в -, -- либо на каждый канал отдельно, -- либо на каждый канал отдельно и отдельно нижняя и верхняя граница канала. -- -- [deviation_type] -- Тип расчета допустимого отклонения цвета. Значение по умолчанию "r". -- Возможные значения: -- "a" - absolute. Абсолютное отклонение канала. -- Например, при цвете 50 100 200 и абсолютном отклонении 10, -- допустимый диапазон цветов будет равен 40-60, 90-110, 190-210 -- "r" - relative. Относительное отклонение, задается в процентах. -- Например, при цвете 50 100 200 и относительном отклонении 10, -- допустимый диапазон цветов будет равен 45-55 90-110 180-220. -- Округление происход в сторону расширения диапазона. -- Например, при значении канала 101 и допустимом отклонении 10%, -- допустимыми значениями канала будут 101-11=90 101+11=112, т.е. 90-112. -- "s" - shadow. Затемнение/осветление. Рассчитывается соотношение каналов, задается в процентах. -- Данный метод может быть полезен, например, при смене суток в игре. -- В рамках данного метода цвет 50 100 200 и цвет 25 50 100 - будут полностью идентичны. -- Для указанных цветов: 200/50=4 50/100=0.5 100/200=0.5 -- 100/25=4 25/50=0.5 50/100=0.5 -- При допустимом отклонении в 10, будут считаться допустимыми соотношения каналов: -- 3.6-4.4 0.45-0.55 0.45-0.55 -- -- [abs_flag] -- Флаг указывающий на то, что изображение должно быть получено не относительно с окна -- к которому произведена привязка пилота через Ctrl+A или workwindow, -- а относительно левого верхнего угла экрана. -- Актуально для method 1, 2. Мной сознательно проигнорированы shift_x shift_y из стандартного финдколора, которые вроде как были призваны снизить нагрузку. Они реально нужны? Я просто их не использовал никогда ввиду того, что смысла в них не видел, скорости относительно хватало, а вот пропустить что-нибудь важное можно. Если надо - вкручу. Идеи/предложения/замечания? Сообщение отредактировал DarkMaster - 27.3.2021, 14:51
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd: Kov____ Писать в личку.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|