|
|
|
Разработка findcolor, findimage, Pure lua |
|
|
DarkMaster |
30.3.2021, 17:38
|
Модератор UOPilot
Сообщений: 9.569
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28532
Пользователь №: 11.279
|
Значит так. Версия из активной разработки. Дальше функции нужно обязательно развернуть в тело финдколора - это существенно ускоряет работу. Но при этом вполне очевидно получается дикий свинарник, особенно если учесть необходимость дублирования циклов под каждый из типов поиска. Поэтому я прошу потестить именно в таком виде. В идеале было-бы что-нибудь типа теста, как я делал под color_deviation_тип_сравнения. образец теста
Код --log(ext.color_deviation_a(3302856, 56 *256*256 + 101 *256 + 200, 5) and "true test: fail" or "false test: passed") --log(ext.color_deviation_a(3302856, 44 *256*256 + 101 *256 + 200, 5) and "true test: fail" or "false test: passed") --log(ext.color_deviation_a(3302856, 45 *256*256 + 101 *256 + 200, 5) and "true test: passed" or "false test: fail") --log(ext.color_deviation_a(3302856, 55 *256*256 + 101 *256 + 200, 5) and "true test: passed" or "false test: fail") --log() --log(ext.color_deviation_a(3302856, 50 *256*256 + 107 *256 + 200, 5) and "true test: fail" or "false test: passed") --log(ext.color_deviation_a(3302856, 50 *256*256 + 95 *256 + 200, 5) and "true test: fail" or "false test: passed") --log(ext.color_deviation_a(3302856, 50 *256*256 + 106 *256 + 200, 5) and "true test: passed" or "false test: fail") --log(ext.color_deviation_a(3302856, 50 *256*256 + 96 *256 + 200, 5) and "true test: passed" or "false test: fail") --log() --log(ext.color_deviation_a(3302856, 50 *256*256 + 101 *256 + 206, 5) and "true test: fail" or "false test: passed") --log(ext.color_deviation_a(3302856, 50 *256*256 + 101 *256 + 194, 5) and "true test: fail" or "false test: passed") --log(ext.color_deviation_a(3302856, 50 *256*256 + 101 *256 + 205, 5) and "true test: passed" or "false test: fail") --log(ext.color_deviation_a(3302856, 50 *256*256 + 101 *256 + 195, 5) and "true test: passed" or "false test: fail") --log() --log(ext.color_deviation_a(3302856, 50 *256*256 + 101 *256 + 200, 5) and "true test: passed" or "false test: fail") --log() --log() --log() --log() -- --log(ext.color_deviation_r(3302856, 56 *256*256 + 101 *256 + 200, 10) and "true test: fail" or "false test: passed") --log(ext.color_deviation_r(3302856, 44 *256*256 + 101 *256 + 200, 10) and "true test: fail" or "false test: passed") --log(ext.color_deviation_r(3302856, 45 *256*256 + 101 *256 + 200, 10) and "true test: passed" or "false test: fail") --log(ext.color_deviation_r(3302856, 55 *256*256 + 101 *256 + 200, 10) and "true test: passed" or "false test: fail") --log() --log(ext.color_deviation_r(3302856, 50 *256*256 + 113 *256 + 200, 10) and "true test: fail" or "false test: passed") --log(ext.color_deviation_r(3302856, 50 *256*256 + 89 *256 + 200, 10) and "true test: fail" or "false test: passed") --log(ext.color_deviation_r(3302856, 50 *256*256 + 112 *256 + 200, 10) and "true test: passed" or "false test: fail") --log(ext.color_deviation_r(3302856, 50 *256*256 + 90 *256 + 200, 10) and "true test: passed" or "false test: fail") --log() --log(ext.color_deviation_r(3302856, 50 *256*256 + 101 *256 + 221, 10) and "true test: fail" or "false test: passed") --log(ext.color_deviation_r(3302856, 50 *256*256 + 101 *256 + 179, 10) and "true test: fail" or "false test: passed") --log(ext.color_deviation_r(3302856, 50 *256*256 + 101 *256 + 180, 10) and "true test: passed" or "false test: fail") --log(ext.color_deviation_r(3302856, 50 *256*256 + 101 *256 + 220, 10) and "true test: passed" or "false test: fail") --log() --log(ext.color_deviation_r(3302856, 50 *256*256 + 101 *256 + 200, 10) and "true test: passed" or "false test: fail") --log() --log() --log() --log()
Ну т.е. оно тупо видно, если где-то сфейлило. По части производительности однозначно стоит покопать internal.color_deviation_*, т.к. часть правок вроде бы ушла, но какая именно еще бы знать. На данный момент код работает только с обязательным указанием deviation. Метод поиска 1 вообще не тестил. Очень слабо представляю, как кто-то будет через get pix собирать картинку и ждать полчаса. Раньше были проблемы с ульимой и методом 2 - приходилось через get pix фигачить, но более этой проблемы в ультиме не наблюдаю, приложений которым нужен get pix я более не знаю. По коду - все, что в ext массиве подразумевает импорт в пилот ну и соответственно работоспособность. Список с кратким описанием: color_to_rgb - разделение на каналы color_to_bgr - разделение на каналы rgb_to_color - сбор каналов в код цвета bgr_to_color - сбор каналов в код цвета color_deviation_a - проверка точки на соотвествие цвета с абсолютным смещением оттенка color_deviation_r - проверка точки на соотвествие цвета с отностиельным смещением оттенка color_deviation_s - проверка точки на соотвествие цвета с затенением цвета findcolor - поиск цвета // небольшой оффтоп и почему получилось так, как оно получилось. Собственно решил сделать что-то вроде пилотовского сравнение на дипазон цветовой. color_deviation_* это собственно то, что делалось (и отдаленно думалось про финдколр), когда появился sutra. Ну собственно отсюда и вся структура кода. Сообщение отредактировал DarkMaster - 30.3.2021, 17:40
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
DarkMaster |
30.3.2021, 17:46
|
Модератор UOPilot
Сообщений: 9.569
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28532
Пользователь №: 11.279
|
собственно код
Код --lua
local ffi=require "ffi" local rmem=ffi.cast local C=ffi.C
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);
void free(void *ptr); void *malloc(size_t size); ]]
local ext = {} local internal = {} local images = {}
ext.wait = {} -- блок дейстивий по ожиданию цвета/изображений/кликов/окон. ext.wait.log = 1 -- включить ввывод description в лог. ext.wait.log_level = 2 -- уровень логирования для description. ext.lg_level = 1 -- уровень логирования. Для вывода сообщения должен быть больше или равен -- заданному при вызове функции. -- Если при вызове функции уровень не задан, то он считается равным 0.
function ext.lg(data, comment, level) if (not level and ext.lg_level < 0) or (level and level < ext.lg_level) then return end if comment ~= nil then log(comment) end
local tab = "" local deep = 0
local function show(data) -- Пишем в лог комментарий. deep = deep + 1 -- Уровень вложенности вызовов функции.
if type(data) == "table" then local element_counter = 0 for k,v in pairs(data) do element_counter = element_counter + 1 if type (v) == "table" then log(tab..'table: '..tostring(k)) tab = tab .. " " show(v) tab = string.sub(tab, 1, -5) else if type(v) == "nil" then v = "nil" elseif type(v) == "string" then v = '"' .. v .. '"' elseif type(v) == "number" then v = tostring(v) elseif type(v) == "function" then v = tostring(v) elseif type(v) == "thread" then v = tostring(v) elseif type(v) == "userdata" then v = "userdata" elseif type(v) == "boolean" then v = tostring(v) elseif type(v) == "table" then log(tab..""..k.." = "..v or "nil") else v = "uknown data type" end log(tab..""..k.." = " .. v) end end log(tab.."".."Elements in table: " .. element_counter) else log('table is "' .. type(data) .. '" data type. Value: ' .. tostring(data)) end --tab = "" --deep = 0 end show(data) end
ext.getimage = function(x1, y1, x2, y2, handle, abs_flag) if handle > 2 or handle == 0 then local a, w, h, l w = x2-x1 + 1 h = y2-y1 + 1 local hdcWindow = C.GetDC(handle or 0) -- если хендл не указан, то получим скрин с экрана local hdcMemDC = C.CreateCompatibleDC(hdcWindow) local hbmScreen = C.CreateCompatibleBitmap(hdcWindow, w, h) C.SelectObject(hdcMemDC,hbmScreen) C.BitBlt(hdcMemDC, 0, 0, w, h, hdcWindow, x1, y1, SRCCOPY) -- сохранить в памяти скрин с окна или экрана
local bi = ffi.new('BITMAPINFO', { {ffi.sizeof('BITMAPINFOHEADER'), w, -h, 1, 24, BI_RGB,0,0,0,0,0} }) C.GetDIBits(hdcWindow, hbmScreen, 0, h, nil, bi, DIB_RGB_COLORS) -- узнать какого размера нужен массив
local bitmap_address = ffi.gc(C.malloc(bi.bmiHeader.biSizeImage), C.free) local h_copied = C.GetDIBits(hdcWindow, hbmScreen, 0, h, bitmap_address, bi, DIB_RGB_COLORS) -- получить битовый массив
--return h_copied and ffi.cast("int", bitmap_address) or nil, w, h_copied, math.floor(w*3/4+0.75)*4 if h_copied > 0 then a = tonumber(ffi.cast("int", bitmap_address)) images[a] = {} images[a].handle = handle images[a].hdcWindow = hdcWindow images[a].hdcMemDC = hdcMemDC images[a].hbmScreen = hbmScreen images[a].bitmap_address = bitmap_address
return a, w, h_copied, math.floor(w*3/4+0.75)*4 else return nil end else return internal.getimage_orig(x1, y1, x2, y2, handle, abs_flag) end end
internal.deleteimage_orig = deleteimage ext.deleteimage = function(address) if images[address] then C.ReleaseDC(images[address].handle, images[address].hdcWindow) C.DeleteObject(images[address].hdcMemDC) C.DeleteObject(images[address].hbmScreen) ffi.C.free(ffi.gc(images[address].bitmap_address, nil)) -- Manually free the memory images[address] = nil else deleteimage_orig(address) end end
-- Раскладывает код цвета на отдельные каналы. ext.color_to_rgb = function(c) local r,g,b b = math.floor(c/65536) g = math.floor(c/256-b*256) r = c-b*256*256-g*256 return r, g ,b end
ext.color_to_bgr = function(c) local r,g,b b = math.floor(c/65536) g = math.floor(c/256-b*256) r = c-b*256*256-g*256 return b, g, r end
ext.rgb_to_color = function(r, g, b) return b*256*256 + g*256 + r end
ext.bgr_to_color = function(b, g, r) return b*256*256 + g*256 + r end
-- ВНИМАНИЕ ФИКС СТАНДАРТНОЙ ФУНКИИ -- ОРИГИНАЛЬНАЯ ФУНКЦИЯ ПОЛНОСТЬЮ ЗАМЕНЕНА colortorgb = ext.color_to_rgb
internal.color_deviation_parse = function(b1, g1, r1, b2, g2, r2) if type(b1) == "table" then else end
if not g1 then g1 = b1 r1 = b1 b2 = b1 g2 = b1 r2 = b1 elseif not b2 then b2 = b1 g2 = g1 r2 = r1 else -- Ставим минимальные значения вначале, максимальные вконце. b1, g1, r1, b2, g2, r2 = b2, g2, r2, b1, g1, r1 end return b1, g1, r1, b2, g2, r2 end
--[[== internal.color_deviation_parse = function(c1, c2, b1, g1, r1, b2, g2, r2) if type(b1) == "table" then if type(g1) == "table" then b2 = g1[1] g2 = g1[2] r2 = g1[3] else r2 = b2 g2 = r1 b2 = g1 end r1 = b1[3] g1 = b1[2] b1 = b1[1] elseif type(b2) == "table" then r2 = b2[3] g2 = b2[2] b2 = b2[1] elseif not g1 and not r1 and not b2 and not g2 and not r2 then g1 = b1 r1 = b1 b2 = b1 g2 = b1 r2 = b1 end
if not b2 and not g2 and not r2 then r2 = r1 g2 = g1 b2 = b1 end local c1r, c1g, c1b c1b = math.floor(c1/65536) c1g = math.floor(c1/256-c1b*256) c1r = c1-c1b*256*256-c1g*256 local c2r, c2g, c2b c2b = math.floor(c2/65536) c2g = math.floor(c2/256-c2b*256) c2r = c2-c2b*256*256-c2g*256 return b1, g1, r1, b2, g2, r2, c1r, c1g, c1b, c2r, c2g, c2b end ]]
internal.color_deviation_a = function(c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r, b1, g1, r1, b2, g2, r2) if c1r1 - b1 <= c2r and c1g1 - g1 <= c2g and c1b1 - r1 <= c2b and c1r2 + b2 >= c2r and c1g2 + g2 >= c2g and c1b2 + r2 >= c2b then return true else return false end end
internal.color_deviation_r = function(c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r, b1, g1, r1, b2, g2, r2) local r1d = math.ceil(c1r1 * r1 * 0.01) local g1d = math.ceil(c1g1 * g1 * 0.01) local b1d = math.ceil(c1b1 * b1 * 0.01) local r2d = math.ceil(c1r2 * r2 * 0.01) local g2d = math.ceil(c1g2 * g2 * 0.01) local b2d = math.ceil(c1b2 * b2 * 0.01)
if c1r1 - r1d <= c2r and c1g1 - g1d <= c2g and c1b1 - b1d <= c2b and c1r2 + r2d >= c2r and c1g2 + g2d >= c2g and c1b2 + b2d >= c2b then return true else return false end end
internal.color_deviation_s = function(c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r, br1, rg1, gb1, br2, rg2, gb2) c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r = c1b1+1, c1g1+1, c1r1+1, c1b2+1, c1g2+1, c1r2+1, c2b+1, c2g+1, c2r+1
local c1br1 = c1b1/c1r1 local c1rg1 = c1r1/c1g1 local c1gb1 = c1g1/c1b1 local c1br2 = c1b2/c1r2 local c1rg2 = c1r2/c1g2 local c1gb2 = c1g2/c1b2 local br_d1 = c1br1 * br1 * 0.01 local rg_d1 = c1rg1 * rg1 * 0.01 local gb_d1 = c1gb1 * gb1 * 0.01 local br_d2 = c1br2 * br2 * 0.01 local rg_d2 = c1rg2 * rg2 * 0.01 local gb_d2 = c1gb2 * gb2 * 0.01 local c2br = c2b/c2r local c2rg = c2r/c2g local c2gb = c2g/c2b --[[ log( "", c1b1, c1g1, c1r1, "\r\n", c1b2, c1g2, c1r2, "\r\n", c2b, c2g, c2r ) log( "", c1br1, c1rg1, c1gb1, "\r\n", c1br2, c1rg2, c1gb2, "\r\n", c2br, c2rg, c2gb ) log( "", c1br1 , br_d1 , c2br , c1rg1 , rg_d1 , c2rg , c1gb1 , gb_d1 , c2gb , "\r\n", c1br2 , br_d2 , c2br , c1rg2 , rg_d2 , c2rg , c1gb2 , gb_d2 , c2gb ) log( "", tostring(c1br1 - br_d1 <= c2br) , tostring(c1rg1 - rg_d1 <= c2rg) , tostring(c1gb1 - gb_d1 <= c2gb) , "\r\n", tostring(c1br2 + br_d2 >= c2br) , tostring(c1rg2 + rg_d2 >= c2rg) , tostring(c1gb2 + gb_d2 >= c2gb) ) log( "", c1br1 - br_d1 ,"<=", c2br , c1rg1 - rg_d1 ,"<=", c2rg , c1gb1 - gb_d1 ,"<=", c2gb , "\r\n", c1br2 + br_d2 ,">=", c2br , c1rg2 + rg_d2 ,">=", c2rg , c1gb2 + gb_d2 ,">=", c2gb ) ]]
if c1br1 - br_d1 <= c2br and c1rg1 - rg_d1 <= c2rg and c1gb1 - gb_d1 <= c2gb and c1br2 + br_d2 >= c2br and c1rg2 + rg_d2 >= c2rg and c1gb2 + gb_d2 >= c2gb then return true else return false end end
internal.color_deviation = function(compare_func, c1, c2, b1, g1, r1, b2, g2, r2) local b1, g1, r1, b2, g2, r2 = internal.color_deviation_parse(b1, g1, r1, b2, g2, r2) local c1b1, c1g1, c1r1 = ext.color_to_bgr(c1) local c1b2 = c1b1 local c1g2 = c1g1 local c1r2 = c1r1 local c2b, c2g, c2r = ext.color_to_bgr(c2) --log(c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r, b1, g1, r1, b2, g2, r2) return compare_func(c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r, b1, g1, r1, b2, g2, r2) end
--[==[ color_deviation_a -- Возвращает true, если результат -- входит в допустимое отклонение цвета, -- иначе вернет false. -- Все цвета задаются в формате bgr, не rgb. -- Пилот так же предоставляет цвета в формате bgr. -- b, g, r в любом варианте могут быть заданы таблицей. -- Допустимый синтаксис: -- <цвет1>, <цвет2>, <value> -- Значения допустимого отклонения -- ситаются допустимыми +/- b, g, r. -- <цвет1>, <цвет2>, <b, g, r> -- Значения допустимого отклонения -- ситаются допустимыми +/- b, g, r. -- <цвет>, <цвет2>, <b1, g1, r1>, <b2[, g2[, r2]]> -- Значения b1, g1, r1 считаются допустимыми в плюс. -- Значения b2, g2, r2 считаются допустимыми в минус. -- Минус не пишется.]==]
ext.color_deviation_a = function(c1, c2, b1, g1, r1, b2, g2, r2) return internal.color_deviation(internal.color_deviation_a, c1, c2, b1, g1, r1, b2, g2, r2) end
--[==[ color_deviation_r -- Возвращает true, если результат -- входит в допустимое отклонение цвета, -- иначе вернет false. -- Все цвета задаются в формате bgr, не rgb. -- Пилот так же предоставляет цвета в формате bgr. -- b, g, r в любом варианте могут быть заданы таблицей. -- Погрешность задется в -- ПРОЦЕНТАХ от текущего значения канала, -- с округлением в бОльшую сторону. -- Например при цвете точки: 50 101 200 и погрешности -- равной 10% допустимая погрешность составит: -- 50*10%=5, 101*10%=10.1=11, 200*10%=20 -- 50 101 200 исходный цвет -- 45 90 180 минимально допустимый -- 55 112 220 максимально допустимый -- Допустимый синтаксис: -- <цвет1>, <цвет2>, <value> -- Значения допустимого отклонения -- ситаются допустимыми +/- b, g, r. -- <цвет1>, <цвет2>, <b, g, r> -- Значения допустимого отклонения -- ситаются допустимыми +/- b, g, r. -- <цвет>, <цвет2>, <b1, g1, r1>, <b2[, g2[, r2]]> -- Значения b1, g1, r1 считаются допустимыми в плюс. -- Значения b2, g2, r2 считаются допустимыми в минус. -- Минус не пишется.]==]
ext.color_deviation_r = function(c1, c2, b1, g1, r1, b2, g2, r2) return internal.color_deviation(internal.color_deviation_r, c1, c2, b1, g1, r1, b2, g2, r2) end
--[==[ color_deviation_s -- Возвращает true, если результат -- входит в допустимое отклонение цвета, -- иначе вернет false. -- Все цвета задаются в формате bgr, не rgb. -- Пилот так же предоставляет цвета в формате bgr. -- b, g, r в любом варианте могут быть заданы таблицей. -- Погрешность задется в -- ПРОЦЕНТАХ от ОТНОШЕНИЯ каналов друг к другу, -- с округлением в бОльшую сторону. -- Например при цвете точки: 50 101 200 и погрешности -- равной 10% допустимая погрешность составит: -- 50*10%=5, 101*10%=10.1=11, 200*10%=20 -- 50 101 200 исходный цвет -- 45 90 180 минимально допустимый -- 55 112 220 максимально допустимый -- Допустимый синтаксис: -- <цвет1>, <цвет2>, <value> -- Значения допустимого отклонения -- ситаются допустимыми +/- br, rg, gb. -- <цвет1>, <цвет2>, <br, rg, gb> -- Значения допустимого отклонения -- ситаются допустимыми +/- br, rg, gb. -- <цвет>, <цвет2>, <br1, rg1, gb1>, <br2[, rg2[, gb2]]> -- Значения br1, rg1, gb1 считаются допустимыми в плюс. -- Значения br2, rg2, gb2 считаются допустимыми в минус. -- Минус не пишется.]==]
ext.color_deviation_s = function(c1, c2, br1, rg1, gb1, br2, rg2, bg2) return internal.color_deviation(internal.color_deviation_s, c1, c2, br1, rg1, gb1, br2, rg2, bg2) end
internal.parse_channel_to_min_max = function(v) local min, max if v then min, max = string.match (v, "([0-9x]+)-*([0-9x]*)") min = tonumber(min) max = tonumber(max) if not max then max = min end else min, max = 0, 255 end return min, max end
internal.parse_split_color_to_min_max_bgr = function(c) c = type(c) == "table" and c or {c} if c.r or c.g or c.b then c = {c} end local cc = ffi.new("uint8_t["..#c.."][6]") --log(type(c,#c)) for i = 1, #c do if type(c[i]) == "table" then cc[i][0],cc[i][3] = internal.parse_channel_to_min_max(c[i].b) cc[i][1],cc[i][4] = internal.parse_channel_to_min_max(c[i].g) cc[i][2],cc[i][5] = internal.parse_channel_to_min_max(c[i].r) else local c1, c2 = string.match (c[i], "([0-9x]+)-*([0-9x]*)") c1 = tonumber(c1) c2 = tonumber(c2) cc[i][0] = math.floor(c1/65536) cc[i][1] = math.floor(c1/256-cc[i][0]*256) cc[i][2] = c1-cc[i][0]*256*256-cc[i][1]*256 if c2 then cc[i][3] = math.floor(c2/65536) cc[i][4] = math.floor(c2/256-cc[i][3]*256) cc[i][5] = c2-cc[i][3]*256*256-cc[i][4]*256 else cc[i][3],cc[i][4],cc[i][5] = cc[i][0],cc[i][1],cc[i][2] end end end
return cc end
internal.findcolor_deviation_parse = function(v) if type(v) == "number" then if v > 0 then v = {v, v, v, v, v, v} else v = nil -- вырубаем обработку отклонений. end elseif type(v) == "table" then vv[i][0],vv[i][3] = internal.parse_channel_to_min_max(c[i].b) vv[i][1],vv[i][4] = internal.parse_channel_to_min_max(c[i].g) vv[i][2],vv[i][5] = internal.parse_channel_to_min_max(c[i].r) end return v[1], v[2], v[3], v[4], v[5], v[6] end
--[====[ 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.]====]
ext.findcolor = function(x1, y1, x2, y2, c, method, count, deviation, deviation_type, abs_crds) local t = os.clock() if type(x1) == "table" then abs_crds = count deviation_type = method deviation = c count = y2 method = x2 c = y1 end --log(1, os.clock() - t) c = type(c) == "table" and c or {c} method = method or workwindow() deviation = internal.findcolor_deviation_parse(deviation) deviation_type = deviation_type or "r" --log(2, os.clock() - t) local compare_func if deviation_type == "r" then compare_func = internal.color_deviation_r elseif deviation_type == "a" then compare_func = internal.color_deviation_a elseif deviation_type == "s" then compare_func = internal.color_deviation_s end --log(3, os.clock() - t)
local offset_x1, offset_y1, offset_y1, offset_y2 = 0, 0, 0, 0 local a, w, h, l if type(method) == "table" then a, w, h, l = method[1], method[2], method[3], method[4] elseif type(method) == "number" then a, w, h, l = getimage (x1, y1, x2, y2, method, abs_crds) -- getimage игнорирует x2, y2 offset_x2 = w - math.min(x2+1, w) -- getimage игнорирует x2, y2 offset_y2 = h - math.min(y2+1, h) -- getimage игнорирует x2, y2 saveimage(a,"image\\check.bmp") elseif type(method) == "string" then a, w, h, l = loadimage (method) offset_x1 = math.min(x1, w) offset_y1 = math.min(y1, h) offset_x2 = w - math.min(x2+1, w) offset_y2 = h - math.min(y2+1, h) end --log(4, os.clock() - t) if not a then log("capture failed") stop_script() end log(a, w, h, l) local cc = internal.parse_split_color_to_min_max_bgr(c)
local d = ffi.new("uint8_t[6]") d[0], d[1], d[2], d[3], d[4], d[5] = internal.findcolor_deviation_parse(deviation, d)
local t = os.clock() log(a + offset_y1*l, a+(h-offset_y2)*l-1, l) local r = {} if deviation then for i = a + offset_y1*l, a+(h-offset_y2)*l-1, l do local y = i --p = zp + pa[0] + i / 3 --log(222, tostring(p)) --stop_script() for i = i+offset_x1*3, i+l-offset_x2*3-1, 3 do for j = 1, #c do --log(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], rmem("unsigned char*",i)[0],rmem("unsigned char*",i+1)[0],rmem("unsigned char*",i+2)[0], d[0], d[1], d[2], d[3], d[4], d[5])
--if cc[j][0] - d[0] <= rmem("unsigned char*",i)[0] and cc[j][1] - d[1] <= rmem("unsigned char*",i)[1] and cc[j][2] - d[2] <= rmem("unsigned char*",i)[2] and -- cc[j][3] + d[3] >= rmem("unsigned char*",i)[0] and cc[j][4] + d[4] >= rmem("unsigned char*",i)[1] and cc[j][5] + d[5] >= rmem("unsigned char*",i)[2] then --log((i-y)/3 + 1, (y-a)/l/3 + 1) if compare_func(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], rmem("unsigned char*",i)[0],rmem("unsigned char*",i)[1],rmem("unsigned char*",i)[2], d[0], d[1], d[2], d[3], d[4], d[5]) then r[#r+1] = {} r[#r][1] = (i-y)/3 r[#r][2] = math.floor((y-a)/l) r[#r][3] = cc[j][1]*256*256 + cc[j][2]*256 + cc[j][3] r[#r][4] = cc[j][4]*256*256 + cc[j][5]*256 + cc[j][6] --log(r[#r][1],r[#r][2]) if count == #r then return r end end end --p = p + 1 end end else for y = 1, w do for x = 1, h do for i = 1, #deviation do if deviation_func() then end end end end end
--[[ local pa = ffi.new("unsigned int[1]",a) --local zp = ffi.new("unsigned char *") local p = ffi.new("unsigned char[3]")
local p = ffi.new("unsigned char *") p = p+pa[0]
--log(a) --log(222, tostring(p)) --stop_script() --log(333, #c) --log(7, os.clock() - t)
--ext.lg(d) --end_script() --log(333, #c)
--log(8, os.clock() - t) local t = os.clock() --log(l) local r = {} if deviation then for i = 0, h*l-1, l do local y = i --p = zp + pa[0] + i / 3 --log(222, tostring(p)) --stop_script() for i = i, i+w*3-1, 3 do for j = 1, #c do --log(i) --log(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], p[0], p[1], p[2], d[1], d[2], d[3], d[4], d[5], d[6]) --if compare_func(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], p[0], p[1], p[2], d[1], d[2], d[3], d[4], d[5], d[6]) then --log(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], p[i], p[i+1], p[i+2], d[1], d[2], d[3], d[4], d[5], d[6]) if compare_func(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], p[i], p[i+1], p[i+2], d[1], d[2], d[3], d[4], d[5], d[6]) then r[#r+1] = {} r[#r][1] = (i-y)/3 + 1 r[#r][2] = (y)/l + 1 r[#r][3] = cc[j][1]*256*256 + cc[j][2]*256 + cc[j][3] r[#r][4] = cc[j][4]*256*256 + cc[j][5]*256 + cc[j][6] --log(r[#r][1],r[#r][2]) end end --p = p + 1 end end else for y = 1, w do for x = 1, h do for i = 1, #deviation do if deviation_func() then end end end end end ]] deleteimage = internal.deleteimage speed = speed + os.clock() - t catch = #r return r end
return ext Прежде чем писать багрепорты на color_deviation_s и соотвественно метод 's' рекомендую сначала взять калькулятор и посчитать допустимые смещения) не все там так нативно.
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
sutra |
30.3.2021, 18:34
|
Adept
Сообщений: 923
Регистрация: 10.8.2018 Группа: Пользователи Наличность: 0
Пользователь №: 19.007
|
Может не доглядел (тогда ткни меня носом), но не нашёл поиска по RED-BLUE, RED-GREEN. Поиск по разности каналов куда как важнее deviation. Могу привести просто кучу примеров, когда это необходимо. Очень грубый пример, просто для понимания. Ну вот навёл прицел на мишень - прицел стал другим (обычно ярче) и, как правило, он легко ищется в обоих состояниях именно по разности между каналами.
Да и color не нужен. Тот же винд. А для совместимости проще сделать финд-олд.
У меня реализация именно такая, могу вызывать или как if findcolor (если нужно просто проверить) или b,k=findcolor (если нужно получить конкретные результаты)
Опять же сугубо лично моё субъективное мнение. Чем проще и элегантнее, тем лучше. Появились новые технологии - отказывайся от старых. Извозчиков оставим для туристов. А тащить за собой весь хлам совместимости - только ошибки и коллизии плодить.
|
|
|
|
DarkMaster |
30.3.2021, 18:41
|
Модератор UOPilot
Сообщений: 9.569
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28532
Пользователь №: 11.279
|
По разности каналов не делал. В достаточно большой мере метод 'r' подразумевает эту разность, равно, как и 's' в сочетании с некоторым диапазоном. Цитата Да и color не нужен. Задач достаточно много. В частности я задолбался писать пачку ифов на диапазоны и переводить dec/hex, чтобы задать их. Ну и начал собственно этот момент фиксить. И тут остапа понесло) Цитата Появились новые технологии - отказывайся от старых. попробуй использовать 'r'. Мне понарвилось =) Не знаю, как именно для твоих целей, но у меня очень хорошо отрабатывает. Ну и для меня это как раз во многом новая технология: вбил цвет, написал 5, 'r' и не паришься. Это проще, чем задавать каждый канал, а эффективность меня очень порадовала. На данный момент струтура такова, что добавить любой метод сравнения очень просто - для этого и есть набор функций сравнения. Загоням туда уже распарсенный диапазон, девиэйшн, делаем любую мамтематику, получаем результат. При этом так же не нужно обращать внимание на какие-либо размеры изображений, методы забора и т.д. Весь смысл в том, что в функцию сравнения прилетают уже коретные данные, обо всем остальном уже позаботились. Битовая маска перебирается только в рамках указанных координат(привет багам старого getimage и потеряным единичкам).
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
DarkMaster |
30.3.2021, 18:54
|
Модератор UOPilot
Сообщений: 9.569
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 28532
Пользователь №: 11.279
|
поправлен парсиг color_deviation_*
Код --lua
local ffi=require "ffi" local rmem=ffi.cast local C=ffi.C
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);
void free(void *ptr); void *malloc(size_t size); ]]
local ext = {} local internal = {} local images = {}
ext.wait = {} -- блок дейстивий по ожиданию цвета/изображений/кликов/окон. ext.wait.log = 1 -- включить ввывод description в лог. ext.wait.log_level = 2 -- уровень логирования для description. ext.lg_level = 1 -- уровень логирования. Для вывода сообщения должен быть больше или равен -- заданному при вызове функции. -- Если при вызове функции уровень не задан, то он считается равным 0.
function ext.lg(data, comment, level) if (not level and ext.lg_level < 0) or (level and level < ext.lg_level) then return end if comment ~= nil then log(comment) end
local tab = "" local deep = 0
local function show(data) -- Пишем в лог комментарий. deep = deep + 1 -- Уровень вложенности вызовов функции.
if type(data) == "table" then local element_counter = 0 for k,v in pairs(data) do element_counter = element_counter + 1 if type (v) == "table" then log(tab..'table: '..tostring(k)) tab = tab .. " " show(v) tab = string.sub(tab, 1, -5) else if type(v) == "nil" then v = "nil" elseif type(v) == "string" then v = '"' .. v .. '"' elseif type(v) == "number" then v = tostring(v) elseif type(v) == "function" then v = tostring(v) elseif type(v) == "thread" then v = tostring(v) elseif type(v) == "userdata" then v = "userdata" elseif type(v) == "boolean" then v = tostring(v) elseif type(v) == "table" then log(tab..""..k.." = "..v or "nil") else v = "uknown data type" end log(tab..""..k.." = " .. v) end end log(tab.."".."Elements in table: " .. element_counter) else log('table is "' .. type(data) .. '" data type. Value: ' .. tostring(data)) end --tab = "" --deep = 0 end show(data) end
ext.getimage = function(x1, y1, x2, y2, handle, abs_flag) if handle > 2 or handle == 0 then local a, w, h, l w = x2-x1 + 1 h = y2-y1 + 1 local hdcWindow = C.GetDC(handle or 0) -- если хендл не указан, то получим скрин с экрана local hdcMemDC = C.CreateCompatibleDC(hdcWindow) local hbmScreen = C.CreateCompatibleBitmap(hdcWindow, w, h) C.SelectObject(hdcMemDC,hbmScreen) C.BitBlt(hdcMemDC, 0, 0, w, h, hdcWindow, x1, y1, SRCCOPY) -- сохранить в памяти скрин с окна или экрана
local bi = ffi.new('BITMAPINFO', { {ffi.sizeof('BITMAPINFOHEADER'), w, -h, 1, 24, BI_RGB,0,0,0,0,0} }) C.GetDIBits(hdcWindow, hbmScreen, 0, h, nil, bi, DIB_RGB_COLORS) -- узнать какого размера нужен массив
local bitmap_address = ffi.gc(C.malloc(bi.bmiHeader.biSizeImage), C.free) local h_copied = C.GetDIBits(hdcWindow, hbmScreen, 0, h, bitmap_address, bi, DIB_RGB_COLORS) -- получить битовый массив
--return h_copied and ffi.cast("int", bitmap_address) or nil, w, h_copied, math.floor(w*3/4+0.75)*4 if h_copied > 0 then a = tonumber(ffi.cast("int", bitmap_address)) images[a] = {} images[a].handle = handle images[a].hdcWindow = hdcWindow images[a].hdcMemDC = hdcMemDC images[a].hbmScreen = hbmScreen images[a].bitmap_address = bitmap_address
return a, w, h_copied, math.floor(w*3/4+0.75)*4 else return nil end else return internal.getimage_orig(x1, y1, x2, y2, handle, abs_flag) end end
internal.deleteimage_orig = deleteimage ext.deleteimage = function(address) if images[address] then C.ReleaseDC(images[address].handle, images[address].hdcWindow) C.DeleteObject(images[address].hdcMemDC) C.DeleteObject(images[address].hbmScreen) ffi.C.free(ffi.gc(images[address].bitmap_address, nil)) -- Manually free the memory images[address] = nil else deleteimage_orig(address) end end
-- Раскладывает код цвета на отдельные каналы. ext.color_to_rgb = function(c) local r,g,b b = math.floor(c/65536) g = math.floor(c/256-b*256) r = c-b*256*256-g*256 return r, g ,b end
ext.color_to_bgr = function(c) local r,g,b b = math.floor(c/65536) g = math.floor(c/256-b*256) r = c-b*256*256-g*256 return b, g, r end
ext.rgb_to_color = function(r, g, b) return b*256*256 + g*256 + r end
ext.bgr_to_color = function(b, g, r) return b*256*256 + g*256 + r end
-- ВНИМАНИЕ ФИКС СТАНДАРТНОЙ ФУНКИИ -- ОРИГИНАЛЬНАЯ ФУНКЦИЯ ПОЛНОСТЬЮ ЗАМЕНЕНА colortorgb = ext.color_to_rgb
internal.color_deviation_parse = function(b1, g1, r1, b2, g2, r2) if type(b1) == "table" then else end
if not g1 then g1 = b1 r1 = b1 b2 = b1 g2 = b1 r2 = b1 elseif not b2 then b2 = b1 g2 = g1 r2 = r1 else -- Ставим минимальные значения вначале, максимальные вконце. b1, g1, r1, b2, g2, r2 = b2, g2, r2, b1, g1, r1 end return b1, g1, r1, b2, g2, r2 end
--[[== internal.color_deviation_parse = function(c1, c2, b1, g1, r1, b2, g2, r2) if type(b1) == "table" then if type(g1) == "table" then b2 = g1[1] g2 = g1[2] r2 = g1[3] else r2 = b2 g2 = r1 b2 = g1 end r1 = b1[3] g1 = b1[2] b1 = b1[1] elseif type(b2) == "table" then r2 = b2[3] g2 = b2[2] b2 = b2[1] elseif not g1 and not r1 and not b2 and not g2 and not r2 then g1 = b1 r1 = b1 b2 = b1 g2 = b1 r2 = b1 end
if not b2 and not g2 and not r2 then r2 = r1 g2 = g1 b2 = b1 end local c1r, c1g, c1b c1b = math.floor(c1/65536) c1g = math.floor(c1/256-c1b*256) c1r = c1-c1b*256*256-c1g*256 local c2r, c2g, c2b c2b = math.floor(c2/65536) c2g = math.floor(c2/256-c2b*256) c2r = c2-c2b*256*256-c2g*256 return b1, g1, r1, b2, g2, r2, c1r, c1g, c1b, c2r, c2g, c2b end ]]
internal.color_deviation_a = function(c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r, b1, g1, r1, b2, g2, r2) if c1r1 - b1 <= c2r and c1g1 - g1 <= c2g and c1b1 - r1 <= c2b and c1r2 + b2 >= c2r and c1g2 + g2 >= c2g and c1b2 + r2 >= c2b then return true else return false end end
internal.color_deviation_r = function(c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r, b1, g1, r1, b2, g2, r2) local r1d = math.ceil(c1r1 * r1 * 0.01) local g1d = math.ceil(c1g1 * g1 * 0.01) local b1d = math.ceil(c1b1 * b1 * 0.01) local r2d = math.ceil(c1r2 * r2 * 0.01) local g2d = math.ceil(c1g2 * g2 * 0.01) local b2d = math.ceil(c1b2 * b2 * 0.01)
if c1r1 - r1d <= c2r and c1g1 - g1d <= c2g and c1b1 - b1d <= c2b and c1r2 + r2d >= c2r and c1g2 + g2d >= c2g and c1b2 + b2d >= c2b then return true else return false end end
internal.color_deviation_s = function(c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r, br1, rg1, gb1, br2, rg2, gb2) c1b1, c1g1, c1r1, c1b2, c1g2, c1r2, c2b, c2g, c2r = c1b1+1, c1g1+1, c1r1+1, c1b2+1, c1g2+1, c1r2+1, c2b+1, c2g+1, c2r+1
local c1br1 = c1b1/c1r1 local c1rg1 = c1r1/c1g1 local c1gb1 = c1g1/c1b1 local c1br2 = c1b2/c1r2 local c1rg2 = c1r2/c1g2 local c1gb2 = c1g2/c1b2 local br_d1 = c1br1 * br1 * 0.01 local rg_d1 = c1rg1 * rg1 * 0.01 local gb_d1 = c1gb1 * gb1 * 0.01 local br_d2 = c1br2 * br2 * 0.01 local rg_d2 = c1rg2 * rg2 * 0.01 local gb_d2 = c1gb2 * gb2 * 0.01 local c2br = c2b/c2r local c2rg = c2r/c2g local c2gb = c2g/c2b --[[ log( "", c1b1, c1g1, c1r1, "\r\n", c1b2, c1g2, c1r2, "\r\n", c2b, c2g, c2r ) log( "", c1br1, c1rg1, c1gb1, "\r\n", c1br2, c1rg2, c1gb2, "\r\n", c2br, c2rg, c2gb ) log( "", c1br1 , br_d1 , c2br , c1rg1 , rg_d1 , c2rg , c1gb1 , gb_d1 , c2gb , "\r\n", c1br2 , br_d2 , c2br , c1rg2 , rg_d2 , c2rg , c1gb2 , gb_d2 , c2gb ) log( "", tostring(c1br1 - br_d1 <= c2br) , tostring(c1rg1 - rg_d1 <= c2rg) , tostring(c1gb1 - gb_d1 <= c2gb) , "\r\n", tostring(c1br2 + br_d2 >= c2br) , tostring(c1rg2 + rg_d2 >= c2rg) , tostring(c1gb2 + gb_d2 >= c2gb) ) log( "", c1br1 - br_d1 ,"<=", c2br , c1rg1 - rg_d1 ,"<=", c2rg , c1gb1 - gb_d1 ,"<=", c2gb , "\r\n", c1br2 + br_d2 ,">=", c2br , c1rg2 + rg_d2 ,">=", c2rg , c1gb2 + gb_d2 ,">=", c2gb ) ]]
if c1br1 - br_d1 <= c2br and c1rg1 - rg_d1 <= c2rg and c1gb1 - gb_d1 <= c2gb and c1br2 + br_d2 >= c2br and c1rg2 + rg_d2 >= c2rg and c1gb2 + gb_d2 >= c2gb then return true else return false end end
internal.color_deviation = function(compare_func, c1, c2, b1, g1, r1, b2, g2, r2) local b1, g1, r1, b2, g2, r2 = internal.color_deviation_parse(b1, g1, r1, b2, g2, r2) local c2b, c2g, c2r = ext.color_to_bgr(c2) local cc = internal.parse_split_color_to_min_max_bgr(c1)
return compare_func(cc[1][0], cc[1][1], cc[1][2], cc[1][3], cc[1][4], cc[1][5], c2b, c2g, c2r, b1, g1, r1, b2, g2, r2) end
--[==[ color_deviation_a -- Возвращает true, если результат -- входит в допустимое отклонение цвета, -- иначе вернет false. -- Все цвета задаются в формате bgr, не rgb. -- Пилот так же предоставляет цвета в формате bgr. -- b, g, r в любом варианте могут быть заданы таблицей. -- Допустимый синтаксис: -- <цвет1>, <цвет2>, <value> -- Значения допустимого отклонения -- ситаются допустимыми +/- b, g, r. -- <цвет1>, <цвет2>, <b, g, r> -- Значения допустимого отклонения -- ситаются допустимыми +/- b, g, r. -- <цвет>, <цвет2>, <b1, g1, r1>, <b2[, g2[, r2]]> -- Значения b1, g1, r1 считаются допустимыми в плюс. -- Значения b2, g2, r2 считаются допустимыми в минус. -- Минус не пишется.]==]
ext.color_deviation_a = function(c1, c2, b1, g1, r1, b2, g2, r2) return internal.color_deviation(internal.color_deviation_a, c1, c2, b1, g1, r1, b2, g2, r2) end
--[==[ color_deviation_r -- Возвращает true, если результат -- входит в допустимое отклонение цвета, -- иначе вернет false. -- Все цвета задаются в формате bgr, не rgb. -- Пилот так же предоставляет цвета в формате bgr. -- b, g, r в любом варианте могут быть заданы таблицей. -- Погрешность задется в -- ПРОЦЕНТАХ от текущего значения канала, -- с округлением в бОльшую сторону. -- Например при цвете точки: 50 101 200 и погрешности -- равной 10% допустимая погрешность составит: -- 50*10%=5, 101*10%=10.1=11, 200*10%=20 -- 50 101 200 исходный цвет -- 45 90 180 минимально допустимый -- 55 112 220 максимально допустимый -- Допустимый синтаксис: -- <цвет1>, <цвет2>, <value> -- Значения допустимого отклонения -- ситаются допустимыми +/- b, g, r. -- <цвет1>, <цвет2>, <b, g, r> -- Значения допустимого отклонения -- ситаются допустимыми +/- b, g, r. -- <цвет>, <цвет2>, <b1, g1, r1>, <b2[, g2[, r2]]> -- Значения b1, g1, r1 считаются допустимыми в плюс. -- Значения b2, g2, r2 считаются допустимыми в минус. -- Минус не пишется.]==]
ext.color_deviation_r = function(c1, c2, b1, g1, r1, b2, g2, r2) return internal.color_deviation(internal.color_deviation_r, c1, c2, b1, g1, r1, b2, g2, r2) end
--[==[ color_deviation_s -- Возвращает true, если результат -- входит в допустимое отклонение цвета, -- иначе вернет false. -- Все цвета задаются в формате bgr, не rgb. -- Пилот так же предоставляет цвета в формате bgr. -- b, g, r в любом варианте могут быть заданы таблицей. -- Погрешность задется в -- ПРОЦЕНТАХ от ОТНОШЕНИЯ каналов друг к другу, -- с округлением в бОльшую сторону. -- Например при цвете точки: 50 101 200 и погрешности -- равной 10% допустимая погрешность составит: -- 50*10%=5, 101*10%=10.1=11, 200*10%=20 -- 50 101 200 исходный цвет -- 45 90 180 минимально допустимый -- 55 112 220 максимально допустимый -- Допустимый синтаксис: -- <цвет1>, <цвет2>, <value> -- Значения допустимого отклонения -- ситаются допустимыми +/- br, rg, gb. -- <цвет1>, <цвет2>, <br, rg, gb> -- Значения допустимого отклонения -- ситаются допустимыми +/- br, rg, gb. -- <цвет>, <цвет2>, <br1, rg1, gb1>, <br2[, rg2[, gb2]]> -- Значения br1, rg1, gb1 считаются допустимыми в плюс. -- Значения br2, rg2, gb2 считаются допустимыми в минус. -- Минус не пишется.]==]
ext.color_deviation_s = function(c1, c2, br1, rg1, gb1, br2, rg2, bg2) return internal.color_deviation(internal.color_deviation_s, c1, c2, br1, rg1, gb1, br2, rg2, bg2) end
internal.parse_channel_to_min_max = function(v) local min, max if v then min, max = string.match (v, "([0-9x]+)-*([0-9x]*)") min = tonumber(min) max = tonumber(max) if not max then max = min end else min, max = 0, 255 end return min, max end
internal.parse_split_color_to_min_max_bgr = function(c) c = type(c) == "table" and c or {c} if c.r or c.g or c.b then c = {c} end local cc = ffi.new("uint8_t["..#c.."][6]") --log(type(c,#c)) for i = 1, #c do if type(c[i]) == "table" then cc[i][0],cc[i][3] = internal.parse_channel_to_min_max(c[i].b) cc[i][1],cc[i][4] = internal.parse_channel_to_min_max(c[i].g) cc[i][2],cc[i][5] = internal.parse_channel_to_min_max(c[i].r) else local c1, c2 = string.match (c[i], "([0-9x]+)-*([0-9x]*)") c1 = tonumber(c1) c2 = tonumber(c2) cc[i][0] = math.floor(c1/65536) cc[i][1] = math.floor(c1/256-cc[i][0]*256) cc[i][2] = c1-cc[i][0]*256*256-cc[i][1]*256 if c2 then cc[i][3] = math.floor(c2/65536) cc[i][4] = math.floor(c2/256-cc[i][3]*256) cc[i][5] = c2-cc[i][3]*256*256-cc[i][4]*256 else cc[i][3],cc[i][4],cc[i][5] = cc[i][0],cc[i][1],cc[i][2] end end end
return cc end
internal.findcolor_deviation_parse = function(v) if type(v) == "number" then if v > 0 then v = {v, v, v, v, v, v} else v = nil -- вырубаем обработку отклонений. end elseif type(v) == "table" then vv[i][0],vv[i][3] = internal.parse_channel_to_min_max(c[i].b) vv[i][1],vv[i][4] = internal.parse_channel_to_min_max(c[i].g) vv[i][2],vv[i][5] = internal.parse_channel_to_min_max(c[i].r) end return v[1], v[2], v[3], v[4], v[5], v[6] end
--[====[ 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.]====]
ext.findcolor = function(x1, y1, x2, y2, c, method, count, deviation, deviation_type, abs_crds) local t = os.clock() if type(x1) == "table" then abs_crds = count deviation_type = method deviation = c count = y2 method = x2 c = y1 end --log(1, os.clock() - t) c = type(c) == "table" and c or {c} method = method or workwindow() deviation = internal.findcolor_deviation_parse(deviation) deviation_type = deviation_type or "r" --log(2, os.clock() - t) local compare_func if deviation_type == "r" then compare_func = internal.color_deviation_r elseif deviation_type == "a" then compare_func = internal.color_deviation_a elseif deviation_type == "s" then compare_func = internal.color_deviation_s end --log(3, os.clock() - t)
local offset_x1, offset_y1, offset_y1, offset_y2 = 0, 0, 0, 0 local a, w, h, l if type(method) == "table" then a, w, h, l = method[1], method[2], method[3], method[4] elseif type(method) == "number" then a, w, h, l = getimage (x1, y1, x2, y2, method, abs_crds) -- getimage игнорирует x2, y2 offset_x2 = w - math.min(x2+1, w) -- getimage игнорирует x2, y2 offset_y2 = h - math.min(y2+1, h) -- getimage игнорирует x2, y2 saveimage(a,"image\\check.bmp") elseif type(method) == "string" then a, w, h, l = loadimage (method) offset_x1 = math.min(x1, w) offset_y1 = math.min(y1, h) offset_x2 = w - math.min(x2+1, w) offset_y2 = h - math.min(y2+1, h) end --log(4, os.clock() - t) if not a then log("capture failed") stop_script() end log(a, w, h, l) local cc = internal.parse_split_color_to_min_max_bgr(c)
local d = ffi.new("uint8_t[6]") d[0], d[1], d[2], d[3], d[4], d[5] = internal.findcolor_deviation_parse(deviation, d)
local t = os.clock() log(a + offset_y1*l, a+(h-offset_y2)*l-1, l) local r = {} if deviation then for i = a + offset_y1*l, a+(h-offset_y2)*l-1, l do local y = i --p = zp + pa[0] + i / 3 --log(222, tostring(p)) --stop_script() for i = i+offset_x1*3, i+l-offset_x2*3-1, 3 do for j = 1, #c do --log(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], rmem("unsigned char*",i)[0],rmem("unsigned char*",i+1)[0],rmem("unsigned char*",i+2)[0], d[0], d[1], d[2], d[3], d[4], d[5])
--if cc[j][0] - d[0] <= rmem("unsigned char*",i)[0] and cc[j][1] - d[1] <= rmem("unsigned char*",i)[1] and cc[j][2] - d[2] <= rmem("unsigned char*",i)[2] and -- cc[j][3] + d[3] >= rmem("unsigned char*",i)[0] and cc[j][4] + d[4] >= rmem("unsigned char*",i)[1] and cc[j][5] + d[5] >= rmem("unsigned char*",i)[2] then --log((i-y)/3 + 1, (y-a)/l/3 + 1) if compare_func(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], rmem("unsigned char*",i)[0],rmem("unsigned char*",i)[1],rmem("unsigned char*",i)[2], d[0], d[1], d[2], d[3], d[4], d[5]) then r[#r+1] = {} r[#r][1] = (i-y)/3 r[#r][2] = math.floor((y-a)/l) r[#r][3] = cc[j][1]*256*256 + cc[j][2]*256 + cc[j][3] r[#r][4] = cc[j][4]*256*256 + cc[j][5]*256 + cc[j][6] --log(r[#r][1],r[#r][2]) if count == #r then return r end end end --p = p + 1 end end else for y = 1, w do for x = 1, h do for i = 1, #deviation do if deviation_func() then end end end end end
--[[ local pa = ffi.new("unsigned int[1]",a) --local zp = ffi.new("unsigned char *") local p = ffi.new("unsigned char[3]")
local p = ffi.new("unsigned char *") p = p+pa[0]
--log(a) --log(222, tostring(p)) --stop_script() --log(333, #c) --log(7, os.clock() - t)
--ext.lg(d) --end_script() --log(333, #c)
--log(8, os.clock() - t) local t = os.clock() --log(l) local r = {} if deviation then for i = 0, h*l-1, l do local y = i --p = zp + pa[0] + i / 3 --log(222, tostring(p)) --stop_script() for i = i, i+w*3-1, 3 do for j = 1, #c do --log(i) --log(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], p[0], p[1], p[2], d[1], d[2], d[3], d[4], d[5], d[6]) --if compare_func(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], p[0], p[1], p[2], d[1], d[2], d[3], d[4], d[5], d[6]) then --log(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], p[i], p[i+1], p[i+2], d[1], d[2], d[3], d[4], d[5], d[6]) if compare_func(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], p[i], p[i+1], p[i+2], d[1], d[2], d[3], d[4], d[5], d[6]) then r[#r+1] = {} r[#r][1] = (i-y)/3 + 1 r[#r][2] = (y)/l + 1 r[#r][3] = cc[j][1]*256*256 + cc[j][2]*256 + cc[j][3] r[#r][4] = cc[j][4]*256*256 + cc[j][5]*256 + cc[j][6] --log(r[#r][1],r[#r][2]) end end --p = p + 1 end end else for y = 1, w do for x = 1, h do for i = 1, #deviation do if deviation_func() then end end end end end ]] deleteimage = internal.deleteimage speed = speed + os.clock() - t catch = #r return r end
return ext Цитата Да, кстати. Что-то у меня не получилось сохранить картинку твоим имиджем. Что не так делаю? Кинь конкретный примерчик. Дык я их и не сохранял =) Там где-то в отладке под старый getimage был saveimage. Скринилку пока не трогал. Я тупо поставил в пеинте точки по углам и смотрел находит или нет (ну и в центре пару). Если надо для отладки, то можно расскоментировать строку --log(cc[j][0], cc[j][1], cc[j][2], cc[j][3], cc[j][4], cc[j][5], rmem("unsigned char*",i)[0],rmem("unsigned char*",i+1)[0],rmem("unsigned char*",i+2)[0], d[0], d[1], d[2], d[3], d[4], d[5]) Там покажет какие цвета передаются по каналам, какой цвет сравнивается, значения deviation. Ну и можно еще расскоментить --log(r[#r][1],r[#r][2]) будет при нахождении сразу показвать точки, но я для этого ext.lg обычно использовал. ext.lg - в лог пишет весь массив.
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
sutra |
30.3.2021, 20:15
|
Adept
Сообщений: 923
Регистрация: 10.8.2018 Группа: Пользователи Наличность: 0
Пользователь №: 19.007
|
Вот объясните мне почему так? Просто хочу понять, чтобы быть в теме.
Дарк, у тебя отрицательное значение высоты:
local bi = ffi.new('BITMAPINFO', { {ffi.sizeof('BITMAPINFOHEADER'), w, -h, 1, 24, BI_RGB,0,0,0,0,0} })
А у первоисточника положительное:
local bi = ffi.new('BITMAPINFO', { {ffi.sizeof('BITMAPINFOHEADER'), x2-x, y2-y, 1, 32, BI_RGB,0,0,0,0,0} })
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|