|
|
|
Поиск числа с помощью Findimage, Готовый скрипт |
|
|
DarkMaster |
22.9.2017, 15:12
|
Модератор UOPilot
Сообщений: 9.460
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 27707
Пользователь №: 11.279
|
Цитата Лучше в отдельную тему, чтобы эту не засорять. 2 темы по двум аналогичным скриптам? Я понимаю, что это твой уголок и бессовестно вторгаться не буду, но как тогда это лучше сделать, чтобы не получился бардак с кучей тем? Цитата Если используется getimage, то в findimage указываются координаты 0, 0, ширина, высота. Где ширина и высота это размер изображения полученного getimage. Т. е. при crds={100,100,250,350}, getimage(100,100,250,350) , а findimage не (100,100,250,350), а (0, 0, 151, 251). спасибо Код for i=1, 10000, 1 do v = getimage(0, 0, 1920, 1080, workwindow) deleteimage(v) end Все исправно работает. Там чуть-чуть растет память, потом уменьшается. Это луа и его сборщик мусора. -- Удаляем изображение, если делали скриншот. if options.source == nil then deleteimage(screenshot) end тут была ошибка) поправил.
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
cirus |
22.9.2017, 15:16
|
Elder
Сообщений: 3.480
Регистрация: 18.8.2014 Группа: Пользователи Наличность: 26576
Пользователь №: 16.971
Возраст: 29
|
Передавая в findimage options.path .. symbolName .. options.ext загрузка картинок в память не имеет смысла. Передавать нужно адрес в памяти, а с учётом что картинок одного символа может быть несколько, то нужен ещё один цикл, для перебора всех адресов. код
Код for symbolName, imageAddress in pairs(images) do for _, j in pairs(imageAddress) do -- цикл, если для одного символа несколько картинок tmp = {} findResult = findimage( options.crds[1] .. " " .. options.crds[2] .. " " .. options.crds[3] .. " " .. options.crds[4] .. " " .. "(" .. j .. ") " .. -- передаём j - адрес в памяти "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) -- log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить.
if findResult ~= "0" and not string.find(findResult, "-") then -- Добавляем найденные значения в общий результат поисков. --table.show(tmp,"tmp") for i = 1, #tmp, 1 do -- Напрямую вернуть таблицу в функцию нельзя из-за синтаксиса. -- FIX. Нужен фикс функции findimage пилота (возвращает координаты стрингом) -- после фикса просто удалить "tonumber(parm)" оставив parm. table.insert(crdsRaw,{x=tonumber(tmp[i][1]),y=tonumber(tmp[i][2]),symbolName=symbolName}) end end end end Цитата 2 темы по двум аналогичным скриптам? Я понимаю, что это твой уголок и бессовестно вторгаться не буду, но как тогда это лучше сделать, чтобы не получился бардак с кучей тем? Имелось ввиду для обсуждения багов отдельная тема, которую потом можно и удалить. Растягивать эту тему постами, которые будут не актуальны после исправления багов смысла нет. Или придётся потом эту тему чистить. Когда скрипт будет доделан первый пост отредактируешь, останется мой скрипт на языке пилота и твой на луа.
|
|
|
|
cirus |
22.9.2017, 15:45
|
Elder
Сообщений: 3.480
Регистрация: 18.8.2014 Группа: Пользователи Наличность: 26576
Пользователь №: 16.971
Возраст: 29
|
Код symbols = { "0" = {"zero1", "zero2"}, "1" = {"1a", "1b"}, "2" = {"two", "second"} } Нужны квадратные скобки. Код symbols = { ["0"] = {"zero1", "zero2"}, ["1"] = {"1a", "1b"}, ["2"] = {"two", "second"} }
|
|
|
|
DarkMaster |
25.9.2017, 19:32
|
Модератор UOPilot
Сообщений: 9.460
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 27707
Пользователь №: 11.279
|
Кое-что пофиксил, добавил, переработал. В целом можно назвать релиз кандидатом. По функционалу есть вопрос: нужна ли возможность одновременно указать несколько источников изображений? Умолчательные, перечисленные, папку? Несколько папок (подпапки можно уже сейчас)? Lua распознавание текста
Код -- Баг: из-за особенностей костыля финдимиджа создается НЕ локальня переменная tmp. -- Фикс: изображение не добавлялось в буфер. -- Фикс: расчет пробела от конечной х координаты. -- Фикс: очистка буфера после захвата изображения. -- Фикс: область поиска при источнике из getimage должна быть с нуля. -- Фикс: искалось только одно изображение из-за недостающего вложенного цикла. -- Фикс: буфер теперь действительно буферезует. -- Переработно преобразование из упрощенного синтаксиса в полнеценный. Добавлена защита от дурка (типы данных). -- Добавлено: загрузка папки с изображениями. -- Добавлено: ожидание прогрузки изображений (options.secondFrame). -- Добавлено: чтение из буфера.
do -- Символы для поиска. -- Возможно указать в двух вариантах синтаксиса: упрощенном и полном. -- Упрощенный синтаксис: -- В упрощенном варианте синтаксиса допускается не указывать -- соответствие имен файлов и строке/символу, -- который они обозначают: считается, что они идентичны. -- Пример упрощенного синтаксиса: -- local symbols = {"0", "1", "2", "3", "a", "b", "c", "test"} -- Полный синтаксис: -- Полный синтаксис бывает необходим при использовании -- нескольких изображений соответсвующих одной и той же строке/символу. -- Допускаются переносы строк: -- local symbols = { -- ["0"] = {"zero1", "zero2"}, -- ["1"] = {"1a", "1b"}, -- ["2"] = {"two", "second"} -- } -- Оба варианта синтаксиса можно сочетать: -- local symbols = {"0", "1", ["2"] = {"two", "second"}, "3"}
local default = {} default.crds = {0, 0, 1920, 1080} -- Координаты поиска default.path = "c:\\image" -- Папка с картинками default.ext = ".bmp" -- Расширение картинок default.loadFolder = nil -- Путь по которому будут загружены все изображения с указанными расширением {path=путь, mask=маска, sub=1|0}(sub - подпапки). Имя файла будет соответсвовать имени символа. default.deltaY = 8 -- Расстояние между строками (можно указать высоту картинок) default.deltaSpace = 2 -- Допустимое расстояние между цифрами, иначе будет считаться что это не одно число default.accuracy = 95 -- Точность поиска для Findimage default.deviation = 3 -- Погрешность оттенка для Findimage default.wait = 2 -- Пауза между поиском картинок, если указать меньше искать будет быстрее, но нагрузит процессор default.timeProc = 2 -- Время в секундах (может быть не целым) для поиска картинок, если -1 не выйдет из процедуры пока не найдётся хотя бы 1 картинка default.repeatImage = 2 -- Допустимое смещение координат, если используется несколько видов одной картинки default.window = "workwindow" -- Метод|хендл_окна в котором происходит поиск (если указан источник изображения(source), то параметр будет проигнорирован) default.abs = 0 -- Использовать abs координаты. default.source = nil -- Изображение в котором производится поиск. Должен быть задан таблицей {адрес, ширина, высота}, nil вместо таблицы приведет к захвату изображения с экрана. default.bufferAddNew = 1 -- Добавлять изображения в буфер default.bufferIgnore = 0 -- Игнорировать изображения находящиеся в буфере default.bufferUpdate = 0 -- Обновить изображения содержащиеся в буфере. default.secondFrame = 0 -- Ожидание прогрузки значений. Изображение будет проанализировано только после secondFrame секунд с первой успешной попытки считать любое из избражений. -- набор стандартных символов default.symbols = {["0"]={"0"}, ["1"]={"1"}, ["2"]={"2"}, ["3"]={"3"}, ["4"]={"4"}, ["5"]={"5"}, ["6"]={"6"}, ["7"]={"7"}, ["8"]={"8"}, ["9"]={"9"}}
-- Буфер -- Буфер -- Буфер
local buffer = {} -- Массив с загруженными картинками. imageToStringBuffer = {} -- набор функций по управлению буфером. -- Полностью очищаем массив. function imageToStringBuffer.flush() for k,_ in pairs(buffer) do buffer[v] = nil end end -- Удаляем элемент из буфера function imageToStringBuffer.flush(element) buffer[element] = nil end -- Добавляем изображение в буфер function imageToStringBuffer.flush(element, val) buffer[element] = val end -- Читаем изображение из буфера function imageToStringBuffer.flush(element) return buffer[element] end
-- Поиск -- Поиск -- Поиск
function imageToString(options)
-- Проверяем переданные параметры. Если они отсутствуют - подставляем параметры по умолчанию. if options == nil then local options = {} end if options.crds == nil then options.crds = default.crds end if options.path == nil then options.path = default.path end if options.ext == nil then options.ext = default.ext end if options.loadFolder == nil then options.loadFolder = default.loadFolder end if options.deltaY == nil then options.deltaY = default.deltaY end if options.deltaSpace == nil then options.deltaSpace = default.deltaSpace end if options.accuracy == nil then options.accuracy = default.accuracy end if options.deviation == nil then options.deviation = default.deviation end if options.wait == nil then options.wait = default.wait end if options.timeProc == nil then options.timeProc = default.timeProc end if options.repeatImage == nil then options.repeatImage = default.repeatImage end if options.window == nil then options.window = default.window end if options.abs == nil then options.abs = default.abs end if options.source == nil then options.source = default.source end if options.bufferAddNew == nil then options.bufferAddNew = default.bufferAddNew end if options.bufferIgnore == nil then options.bufferIgnore = default.bufferIgnore end if options.bufferUpdate == nil then options.bufferUpdate = default.bufferUpdate end if options.secondFrame == nil then options.secondFrame = default.secondFrame end if options.symbols == nil then if options.loadFolder == nil then options.symbols = default.symbols else options.symbols = {} end end
--Добавляем при необходимости обратный слэш в путь. if string.sub(options.path, -1) ~= "\\" then options.path = options.path .. "\\" end
-- Папка для загрузки изображений не задана, загружаем обычным методом. if options.loadFolder.path == nil then
-- Преобразуем урощенный синтаксис в полноценный, преобразуем пути в полные. do local tmp = {} --Массив в который временно помещаются преобразованные данные. for symbolName, imageName in pairs(options.symbols) do -- Если занчение задано строкой/числом, приводим его к таблице, дописываем путь до полного. if type(options.symbols[symbolName]) == "number" then options.symbols[symbolName] = {options.path..tostring(imageName)..options.ext} elseif type(options.symbols[symbolName]) == "string" then options.symbols[symbolName] = {options.path..imageName..options.ext} -- Значение задано таблицей, преобразоываем числа в строки, дописываем путь до полного. elseif type(options.symbols[symbolName]) == "table" then for n=1, #options.symbols[symbolName] do if type(options.symbols[symbolName][n]) == "number" then options.symbols[symbolName][n] = options.path..tostring(options.symbols[symbolName][n])..options.ext elseif type(options.symbols[symbolName][n]) == "string" then options.symbols[symbolName][n] = options.path..options.symbols[symbolName][n]..options.ext else msg ("Ошибочный тип значения картинок символов в таблице. Остановка скрипта") stop_script() end end else msg ("Ошибочный тип значения картинок символов. Остановка скрипта") stop_script() end
-- Если ключ цифровой, преобразуем к строке if type(symbolName) == "number" then tmp[tostring(symbolName)] = options.symbols[symbolName] elseif type(symbolName) == "string" then tmp[symbolName] = options.symbols[symbolName] else msg ("Ошибочный тип ключа символов. Остановка скрипта") stop_script() end end options.symbols = tmp end else -- Загружаем папку с изображениями. -- Имя файла = имя символа. -- Допускается несколько одинаковых символов в различных подпапках. -- Приводим к понятному для пилота виду флаг чтение подпапок.
-- Прилепляем кавычки к пути чтобы пилот не путал путь и маску. options.loadFolder.path = '"'..options.loadFolder.path..'"' if options.loadFolder.sub ~= 0 then options.loadFolder.sub = "norecursion" else options.loadFolder.sub = nil end -- Приводим маску к надлежащему виду, если она не задана. if options.loadFolder.mask == nil then options.loadFolder.mask = "*" end
fileList = dir(options.loadFolder.path, options.loadFolder.mask, options.loadFolder.sub) for k, v in pairs (fileList) do -- символ уже существует (несколько вариантов изображения) if options.symbols[v[3]] ~= nil then table.insert(options.symbols[v[3]], v[1]) else options.symbols[v[3]] = {v[1]} end end end --table.show(options.symbols) --if 1 then return end
-- Приводим options.abs к виду пригодному для финдимиджа. if options.abs == 1 then options.abs = "abs" elseif options.abs == 0 then options.abs = "" end --table.show(options.symbols)
-- Загрузка картинок local images={} --Загружает в память изображения {имя символа, {адреса в памяти}} local loadError = 0 for symbolName, fileList in pairs(options.symbols) do images[symbolName] = {} for i=1, #fileList, 1 do -- Загружен ли файл в буфер, если нет, то подгружаем. local filePath = fileList[i] if options.bufferIgnore == 0 and options.bufferUpdate == 0 and buffer[filePath] ~= nil then images[symbolName][i] = buffer[filePath] else -- В буфере изображения нет, загружаем с диска. --log(filePath.."В буфере изображения нет, загружаем с диска.") images[symbolName][i] = loadimage(filePath) -- Обновляем загруженное в буфер изображение if buffer[filePath] ~= nil then deleteimage(buffer[filePath]) buffer[filePath] = images[symbolName][i] elseif options.bufferAddNew == 1 and options.bufferIgnore == 0 then -- Добавляем в буфер новое изображение. buffer[filePath] = images[symbolName][i] end end -- Поиск ошибок загрузки. if images[symbolName][i] < 0 then loadError = loadError + 1 log("Image loading fail. Error file: "..filePath..'.') end end end -- При загрузке изображений произошли ошибки. Останавливаем скрипт. if loadError > 0 then log("Error loading count: "..loadError..'.') stop_script() end --table.show(images)
local timeout = os.clock() + options.timeProc
-- log(options.secondFrame) -- Таймаут на прогрузку. Поиск для детекта изображений. if options.secondFrame > 0 then -- Создаем карман области видимости. -- Реузльататы блока не нужны для остального скрипта. do local catch = 0 -- Если вермя ожидания после детекта не уложится в общий -- таймаут, то выходим из цикла без дальшейших попыток найти изображение. secondFrameTimeout = timeout - options.secondFrame while true do -- выход внутри цикла timeout < os.clock() local screenshot, width, height = nil, nil, nil if options.source == nil then screenshot, width, height = getimage(options.crds[1],options.crds[2],options.crds[3],options.crds[4], options.window) else screenshot, width, height = options.source[1],options.source[2],options.source[3] end for symbolName, imageAddressArray in pairs(images) do for _, imageAddress in pairs(imageAddressArray) do local tmp = {} findResult = findimage( 0 .. " " .. 0 .. " " .. width .. " " .. height .. " " .. "(" .. imageAddress .. ") " .. "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) --log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить. if findResult ~= "0" and not string.find(findResult, "-") then catch = 1 --log("break") wait(math.floor(options.secondFrame * 1000)) break end -- Время на всю функцию истекло if timeout - options.secondFrame < os.clock() then return end end if catch == 1 then break end end if catch == 1 then break end end end end
-- Ищем изображения local crdsRaw={} -- Массив со всеми найденными изображениями, возможны дубли, не сортированный. repeat -- Повторяем пока что-то не найдем или не выйдет время на поиск (options.timeProc). -- Получаем изображение с экрана, если источник не указан. local screenshot, width, height = nil if options.source == nil then screenshot, width, height = getimage(options.crds[1],options.crds[2],options.crds[3],options.crds[4], options.window) else screenshot, width, height = options.source[1],options.source[2],options.source[3] end --log(screenshot) for symbolName, imageAddressArray in pairs(images) do for _, imageAddress in pairs(imageAddressArray) do tmp = {} findResult = findimage( 0 .. " " .. 0 .. " " .. width .. " " .. height .. " " .. "(" .. imageAddress .. ") " .. "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) --log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить. if findResult ~= "0" and not string.find(findResult, "-") then -- Добавляем найденные значения в общий результат поисков. table.show(tmp,"tmp") for i = 1, #tmp, 1 do -- Напрямую вернуть таблицу в функцию нельзя из-за синтаксиса. -- FIX. Нужен фикс функции findimage пилота (возвращает координаты стрингом) -- после фикса просто удалить "tonumber(parm)" оставив parm. table.insert(crdsRaw,{x=tonumber(tmp[i][1]),y=tonumber(tmp[i][2]),xEnd=tonumber(tmp[i][3]),symbolName=symbolName}) end end end end
-- Удаляем изображение, если делали скриншот. if options.source == nil then deleteimage(screenshot) end
--table.show(images, "images") --log (#crdsRaw, timeout, os.clock(), options.timeProc) log ("until") local clock = os.clock() until not ((#crdsRaw == 0) and (timeout > clock or options.timeProc == -1)) --table.show(crdsRaw, "crdsRaw")
-- Изображения не были найдены, выходим из поиска. if #crdsRaw < 1 then return nil end -- Удаляем дубли. local crdsClear={} -- Массив без дублей. for i=1, #crdsRaw, 1 do local catch = 0 -- Флаг найденного дубля. for n=i+1, #crdsRaw, 1 do --log( -- crdsRaw[i].symbolName.." == "..crdsRaw[n].symbolName.." and ".. -- math.abs(crdsRaw[i].x - crdsRaw[n].x).." <= "..options.repeatImage.." and ".. -- math.abs(crdsRaw[i].y - crdsRaw[n].y).." <= "..options.repeatImage --) if crdsRaw[i].symbolName == crdsRaw[n].symbolName and math.abs(crdsRaw[i].x - crdsRaw[n].x) <= options.repeatImage and math.abs(crdsRaw[i].y - crdsRaw[n].y) <= options.repeatImage then catch = 1 break end end --log(catch) if catch == 0 then -- не дубль, копируем значение в чистый массив. table.insert(crdsClear,crdsRaw[i]) end end
-- Сортируем элементы. -- Сортировка происходит, как по X координате, -- так и по Y учитывая возможность нескольких строк. -- Межстрочный интервал задается с помощью options.deltaY. -- Для уплотнения поиска options.deltaY может быть отрицательным. -- Отрицательный options.deltaY в первую очередь необходим, -- если изображения символов содержат сверху и снизу от символа фон. -- crdsClear был предварительно очищен от дублей, теперь сортируется.
--table.show(crdsClear,"crdsClear") --table.toInit(crdsClear) table.sort(crdsClear, function(a,b) if math.abs(a.y - b.y) <= options.deltaY then if a.x < b.x then return true else return false end else if a.y < b.y then return true else return false end end end ) --table.show(crdsClear,"crdsClear")
-- Собираем строку --log(#crdsClear) local result = {{crdsClear[1].symbolName}} local resultX, resultY = 1, 1 for i=2, #crdsClear, 1 do -- Добавляем перенос и символ, возрващем каретку. if crdsClear[i-1].y + options.deltaY < crdsClear[i].y then resultX = resultX + 1 resultY = 1 -- возврат картеки result[resultX]={crdsClear[i].symbolName} -- Добавляем пробел и символ elseif crdsClear[i-1].xEnd + options.deltaSpace < crdsClear[i].x then resultY = resultY + 1 result[resultX][resultY] = crdsClear[i].symbolName -- Добавляем символ else result[resultX][resultY] = result[resultX][resultY].. crdsClear[i].symbolName end --table.show(result,"result") end --table.show(result,"result") return result end end Погоняй, пожалуйста. Сообщение отредактировал DarkMaster - 25.9.2017, 23:38
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
cirus |
26.9.2017, 4:20
|
Elder
Сообщений: 3.480
Регистрация: 18.8.2014 Группа: Пользователи Наличность: 26576
Пользователь №: 16.971
Возраст: 29
|
Цитата if options.loadFolder.path == nil then Обращение к несуществующему элементу таблицы? Есть только options.path и options.loadFolder. Код log ("until") table.show(tmp,"tmp") Закомментировать. Код Лишнее. Код secondFrameTimeout = timeout - options.secondFrame Переменная глобальная и нигде не используется. Подозреваю что должна быть тут (если она вообще нужна): Код if timeout - options.secondFrame < os.clock() then Т. е. Код if secondFrameTimeout < os.clock() then При default.timeProc = -1 и default.secondFrame = 1 сразу выходит из функции. Цитата По функционалу есть вопрос: нужна ли возможность одновременно указать несколько источников изображений? Умолчательные, перечисленные, папку? Несколько папок (подпапки можно уже сейчас)? Если можно подпапки, то не вижу смысла. Если указать папку без картинок, то пилот закрывается. Хотя это наверное косяки 10 бетки, а не скрипта. Добавить возможность сохранить изображение, в котором производился поиск (screenshot).
|
|
|
|
DarkMaster |
26.9.2017, 12:05
|
Модератор UOPilot
Сообщений: 9.460
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 27707
Пользователь №: 11.279
|
Цитата Обращение к несуществующему элементу таблицы? Есть только options.path и options.loadFolder. Вообще в этом и был смысл, т.к. планировалось loadFolder по умолчанию задавать пустой таблицей, но потом я ушел от этого. При этом обращение к несуществующему элементу, если он загружен по умолчанию, но обязательно заданному, если loadFolder использовался при вызове, дало бы нужный результат. Поправил. Цитата Переменная глобальная и нигде не используется. Подозреваю что должна быть тут (если она вообще нужна): Все правильно понял, локал проставил. Цитата При default.timeProc = -1 и default.secondFrame = 1 сразу выходит из функции. Фиксанул.
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
DarkMaster |
26.9.2017, 12:43
|
Модератор UOPilot
Сообщений: 9.460
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 27707
Пользователь №: 11.279
|
Если замечаний нет, то можно в первый пост, да начну документацию писать. Распознавание текста Lua.
Код // Автор скрипта DarkMaster. -- Написано по мотивам скрипта Cirus. -- Тестирование Cirus. -- Вопросы, баги, предложения на форум -- в специальную тему по этому скрипту -- https://forum.uokit.com/index.php?showtopic=30000
-- Фикс: флаг чтения подпапок был инвертирован. -- Фикс: secondFrameTimeout больше не глобальная и используется по назначению. -- Фикс: При default.timeProc = -1 и default.secondFrame > 0 не выходит преждевременно из функции. -- Фикс: Почистил отладочные выводы в лог. -- Добавлено сохранение изображение в котором происходил поиск.
-- Баг: из-за особенностей костыля финдимиджа создается НЕ локальня переменная tmp. -- Фикс: изображение не добавлялось в буфер. -- Фикс: расчет пробела от конечной х координаты. -- Фикс: очистка буфера после захвата изображения. -- Фикс: область поиска при источнике из getimage должна быть с нуля. -- Фикс: искалось только одно изображение из-за недостающего вложенного цикла. -- Фикс: буфер теперь действительно буферезует. -- Переработно преобразование из упрощенного синтаксиса в полнеценный. Добавлена защита от дурка (типы данных). -- Добавлено: загрузка папки с изображениями. -- Добавлено: ожидание прогрузки изображений (options.secondFrame). -- Добавлено: чтение из буфера.
do
-- Раскомментировать, если в отладке будет использоват table.show. --[[do local tab = "" local deep = 0 function table.show(t, comment) -- Пишем в лог комментарий. deep = deep + 1 -- Уровень вложенности вызовов функции. --log(comment .. commentSended .. deep) if comment ~= nil and deep == 1 then log(comment) end
if type(t) == "nil" then log("table is nil") elseif type(t) == "string" then log('table is string: "'..t..'"') elseif type(t) == "number" then log('table is number: '..t) elseif type(t) == "table" then local elementsInTable = 0 for k,v in pairs(t) do if type (v) == "table" then if type(k) == "string" then log(tab..'table: "'..k..'"') else log(tab..'table: '..k) end tab = tab .. " " table.show(v) tab = string.sub(tab, 1, -5) elementsInTable = elementsInTable + 1 else elementsInTable = elementsInTable + 1 if type(v) == "string" then v = '"'..v..'"' end if type(k) == "string" then k = '"'..k..'"' end log(tab..""..k.." = "..v) end end if elementsInTable == 0 then log("table is empty") end else log('table is unknow data type') end -- Пишем в лог комментарий. deep = deep - 1 -- Уровень вложенности вызовов функции. end end ]]
-- Символы для поиска. -- Возможно указать в двух вариантах синтаксиса: упрощенном и полном. -- Упрощенный синтаксис: -- В упрощенном варианте синтаксиса допускается не указывать -- соответствие имен файлов и строке/символу, -- который они обозначают: считается, что они идентичны. -- Пример упрощенного синтаксиса: -- local symbols = {"0", "1", "2", "3", "a", "b", "c", "test"} -- Полный синтаксис: -- Полный синтаксис бывает необходим при использовании -- нескольких изображений соответсвующих одной и той же строке/символу. -- Допускаются переносы строк: -- local symbols = { -- ["0"] = {"zero1", "zero2"}, -- ["1"] = {"1a", "1b"}, -- ["2"] = {"two", "second"} -- } -- Оба варианта синтаксиса можно сочетать: -- local symbols = {"0", "1", ["2"] = {"two", "second"}, "3"}
local default = {} default.crds = {0, 0, 1920, 1080} -- Координаты поиска default.path = "c:\\image" -- Папка с картинками default.ext = ".bmp" -- Расширение картинок default.loadFolder = nil -- Путь по которому будут загружены все изображения с указанной маской {path=путь, mask=маска, sub=1|0}(sub - подпапки). Имя файла будет соответсвовать имени символа. default.deltaY = 8 -- Расстояние между строками (можно указать высоту картинок) default.deltaSpace = 2 -- Допустимое расстояние между цифрами, иначе будет считаться что это не одно число default.accuracy = 95 -- Точность поиска для Findimage default.deviation = 3 -- Погрешность оттенка для Findimage default.wait = 2 -- Пауза между поиском картинок, если указать меньше искать будет быстрее, но нагрузит процессор default.timeProc = 2 -- Время в секундах (может быть не целым) для поиска картинок, если -1 не выйдет из процедуры пока не найдётся хотя бы 1 картинка default.repeatImage = 2 -- Допустимое смещение координат, если используется несколько видов одной картинки default.window = "workwindow" -- Метод|хендл_окна в котором происходит поиск (если указан источник изображения(source), то параметр будет проигнорирован) default.abs = 0 -- Использовать abs координаты. default.source = nil -- Изображение в котором производится поиск. Должен быть задан таблицей {адрес, ширина, высота}, nil вместо таблицы приведет к захвату изображения с экрана. default.bufferAddNew = 1 -- Добавлять изображения в буфер default.bufferIgnore = 0 -- Игнорировать изображения находящиеся в буфере default.bufferUpdate = 0 -- Обновить изображения содержащиеся в буфере. default.secondFrame = 0 -- Ожидание прогрузки значений. Изображение будет проанализировано только после secondFrame секунд с первой успешной попытки считать любое из избражений. default.saveImage = nil -- Путь по которому будет сохранено изображение в котором происходит поиск. -- набор стандартных символов default.symbols = {["0"]={"0"}, ["1"]={"1"}, ["2"]={"2"}, ["3"]={"3"}, ["4"]={"4"}, ["5"]={"5"}, ["6"]={"6"}, ["7"]={"7"}, ["8"]={"8"}, ["9"]={"9"}}
-- Буфер -- Буфер -- Буфер
local buffer = {} -- Массив с загруженными картинками. imageToStringBuffer = {} -- набор функций по управлению буфером. -- Полностью очищаем массив. function imageToStringBuffer.flush() for k,_ in pairs(buffer) do buffer[v] = nil end end -- Удаляем элемент из буфера function imageToStringBuffer.flush(element) buffer[element] = nil end -- Добавляем изображение в буфер function imageToStringBuffer.flush(element, val) buffer[element] = val end -- Читаем изображение из буфера function imageToStringBuffer.flush(element) return buffer[element] end
-- Поиск -- Поиск -- Поиск
function imageToString(options)
-- Проверяем переданные параметры. Если они отсутствуют - подставляем параметры по умолчанию. if options == nil then local options = {} end if options.crds == nil then options.crds = default.crds end if options.path == nil then options.path = default.path end if options.ext == nil then options.ext = default.ext end if options.loadFolder == nil then options.loadFolder = default.loadFolder end if options.deltaY == nil then options.deltaY = default.deltaY end if options.deltaSpace == nil then options.deltaSpace = default.deltaSpace end if options.accuracy == nil then options.accuracy = default.accuracy end if options.deviation == nil then options.deviation = default.deviation end if options.wait == nil then options.wait = default.wait end if options.timeProc == nil then options.timeProc = default.timeProc end if options.repeatImage == nil then options.repeatImage = default.repeatImage end if options.window == nil then options.window = default.window end if options.abs == nil then options.abs = default.abs end if options.source == nil then options.source = default.source end if options.bufferAddNew == nil then options.bufferAddNew = default.bufferAddNew end if options.bufferIgnore == nil then options.bufferIgnore = default.bufferIgnore end if options.bufferUpdate == nil then options.bufferUpdate = default.bufferUpdate end if options.secondFrame == nil then options.secondFrame = default.secondFrame end if options.saveImage == nil then options.saveImage = default.saveImage end if options.symbols == nil then if options.loadFolder == nil then options.symbols = default.symbols else options.symbols = {} end end
--Добавляем при необходимости обратный слэш в путь. if string.sub(options.path, -1) ~= "\\" then options.path = options.path .. "\\" end
-- Папка для загрузки изображений не задана, загружаем обычным методом. if options.loadFolder == nil then -- Преобразуем урощенный синтаксис в полноценный, преобразуем пути в полные. do local tmp = {} --Массив в который временно помещаются преобразованные данные. for symbolName, imageName in pairs(options.symbols) do -- Если занчение задано строкой/числом, приводим его к таблице, дописываем путь до полного. if type(options.symbols[symbolName]) == "number" then options.symbols[symbolName] = {options.path..tostring(imageName)..options.ext} elseif type(options.symbols[symbolName]) == "string" then options.symbols[symbolName] = {options.path..imageName..options.ext} -- Значение задано таблицей, преобразоываем числа в строки, дописываем путь до полного. elseif type(options.symbols[symbolName]) == "table" then for n=1, #options.symbols[symbolName] do if type(options.symbols[symbolName][n]) == "number" then options.symbols[symbolName][n] = options.path..tostring(options.symbols[symbolName][n])..options.ext elseif type(options.symbols[symbolName][n]) == "string" then options.symbols[symbolName][n] = options.path..options.symbols[symbolName][n]..options.ext else msg ("Ошибочный тип значения картинок символов в таблице. Остановка скрипта") stop_script() end end else msg ("Ошибочный тип значения картинок символов. Остановка скрипта") stop_script() end
-- Если ключ цифровой, преобразуем к строке if type(symbolName) == "number" then tmp[tostring(symbolName)] = options.symbols[symbolName] elseif type(symbolName) == "string" then tmp[symbolName] = options.symbols[symbolName] else msg ("Ошибочный тип ключа символов. Остановка скрипта") stop_script() end end options.symbols = tmp end else -- Загружаем папку с изображениями. -- Имя файла = имя символа. -- Допускается несколько одинаковых символов в различных подпапках. -- Приводим к понятному для пилота виду флаг чтение подпапок.
-- Прилепляем кавычки к пути чтобы пилот не путал путь и маску. options.loadFolder.path = '"'..options.loadFolder.path..'"' if options.loadFolder.sub == 1 then options.loadFolder.sub = nil else options.loadFolder.sub = "norecursion" end -- Приводим маску к надлежащему виду, если она не задана. if options.loadFolder.mask == nil then options.loadFolder.mask = "*" end fileList = dir(options.loadFolder.path, options.loadFolder.mask, options.loadFolder.sub) --table.show(fileList, "fileList") for k, v in pairs (fileList) do -- символ уже существует (несколько вариантов изображения) if options.symbols[v[3]] ~= nil then table.insert(options.symbols[v[3]], v[1]) else options.symbols[v[3]] = {v[1]} end end end --table.show(options.symbols)
-- Приводим options.abs к виду пригодному для финдимиджа. if options.abs == 1 then options.abs = "abs" elseif options.abs == 0 then options.abs = "" end
-- Загрузка картинок local images={} --Загружает в память изображения {имя символа, {адреса в памяти}} local loadError = 0 for symbolName, fileList in pairs(options.symbols) do images[symbolName] = {} for i=1, #fileList, 1 do -- Загружен ли файл в буфер, если нет, то подгружаем. local filePath = fileList[i] if options.bufferIgnore == 0 and options.bufferUpdate == 0 and buffer[filePath] ~= nil then images[symbolName][i] = buffer[filePath] else -- В буфере изображения нет, загружаем с диска. --log(filePath.."В буфере изображения нет, загружаем с диска.") images[symbolName][i] = loadimage(filePath) -- Обновляем загруженное в буфер изображение if buffer[filePath] ~= nil then deleteimage(buffer[filePath]) buffer[filePath] = images[symbolName][i] elseif options.bufferAddNew == 1 and options.bufferIgnore == 0 then -- Добавляем в буфер новое изображение. buffer[filePath] = images[symbolName][i] end end -- Поиск ошибок загрузки. if images[symbolName][i] < 0 then loadError = loadError + 1 log("Image loading fail. Error file: "..filePath..'.') end end end -- При загрузке изображений произошли ошибки. Останавливаем скрипт. if loadError > 0 then log("Error loading count: "..loadError..'.') stop_script() end if images == nil then log("Файлы изображений не найдены. Скрипт остановлен.") stop_script() end --table.show(images,"images")
local timeout = os.clock() + options.timeProc
-- log(options.secondFrame) -- Таймаут на прогрузку. Поиск для детекта изображений. if options.secondFrame > 0 then -- Создаем карман области видимости. -- Реузльататы блока не нужны для остального скрипта. do local catch = 0 -- Если вермя ожидания после детекта не уложится в общий -- таймаут, то выходим из цикла без дальшейших попыток найти изображение. local secondFrameTimeout = timeout - options.secondFrame while true do -- выход внутри цикла timeout < os.clock() local screenshot, width, height = nil, nil, nil if options.source == nil then screenshot, width, height = getimage(options.crds[1],options.crds[2],options.crds[3],options.crds[4], options.window) else screenshot, width, height = options.source[1],options.source[2],options.source[3] end for symbolName, imageAddressArray in pairs(images) do for _, imageAddress in pairs(imageAddressArray) do local tmp = {} findResult = findimage( 0 .. " " .. 0 .. " " .. width .. " " .. height .. " " .. "(" .. imageAddress .. ") " .. "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) --log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить. if findResult ~= "0" and not string.find(findResult, "-") then catch = 1 --log("break") wait(math.floor(options.secondFrame * 1000)) break end -- Время на всю функцию истекло if secondFrameTimeout < os.clock() and options.timeProc ~= -1 then return end end if catch == 1 then break end end if catch == 1 then break end end end end
-- Ищем изображения local crdsRaw={} -- Массив со всеми найденными изображениями, возможны дубли, не сортированный. repeat -- Повторяем пока что-то не найдем или не выйдет время на поиск (options.timeProc). -- Получаем изображение с экрана, если источник не указан. local screenshot, width, height = nil if options.source == nil then screenshot, width, height = getimage(options.crds[1],options.crds[2],options.crds[3],options.crds[4], options.window) else screenshot, width, height = options.source[1],options.source[2],options.source[3] end --log(screenshot) for symbolName, imageAddressArray in pairs(images) do for _, imageAddress in pairs(imageAddressArray) do tmp = {} findResult = findimage( 0 .. " " .. 0 .. " " .. width .. " " .. height .. " " .. "(" .. imageAddress .. ") " .. "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) --log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить. if findResult ~= "0" and not string.find(findResult, "-") then -- Добавляем найденные значения в общий результат поисков. --table.show(tmp,"tmp") for i = 1, #tmp, 1 do -- Напрямую вернуть таблицу в функцию нельзя из-за синтаксиса. -- FIX. Нужен фикс функции findimage пилота (возвращает координаты стрингом) -- после фикса просто удалить "tonumber(parm)" оставив parm. table.insert(crdsRaw,{x=tonumber(tmp[i][1]),y=tonumber(tmp[i][2]),xEnd=tonumber(tmp[i][3]),symbolName=symbolName}) end end end end
-- Сохраняем изображение. if options.saveImage ~= nil then saveimage(screenshot, options.saveImage) end -- Удаляем изображение, если получали его из приложения. if options.source == nil then deleteimage(screenshot) end
--table.show(images, "images") --log (#crdsRaw, timeout, os.clock(), options.timeProc) --log ("until") local clock = os.clock() until not ((#crdsRaw == 0) and (timeout > clock or options.timeProc == -1)) --table.show(crdsRaw, "crdsRaw")
-- Изображения не были найдены, выходим из поиска. if #crdsRaw < 1 then return nil end -- Удаляем дубли. local crdsClear={} -- Массив без дублей. for i=1, #crdsRaw, 1 do local catch = 0 -- Флаг найденного дубля. for n=i+1, #crdsRaw, 1 do --log( -- crdsRaw[i].symbolName.." == "..crdsRaw[n].symbolName.." and ".. -- math.abs(crdsRaw[i].x - crdsRaw[n].x).." <= "..options.repeatImage.." and ".. -- math.abs(crdsRaw[i].y - crdsRaw[n].y).." <= "..options.repeatImage --) if crdsRaw[i].symbolName == crdsRaw[n].symbolName and math.abs(crdsRaw[i].x - crdsRaw[n].x) <= options.repeatImage and math.abs(crdsRaw[i].y - crdsRaw[n].y) <= options.repeatImage then catch = 1 break end end --log(catch) if catch == 0 then -- не дубль, копируем значение в чистый массив. table.insert(crdsClear,crdsRaw[i]) end end
-- Сортируем элементы. -- Сортировка происходит, как по X координате, -- так и по Y учитывая возможность нескольких строк. -- Межстрочный интервал задается с помощью options.deltaY. -- Для уплотнения поиска options.deltaY может быть отрицательным. -- Отрицательный options.deltaY в первую очередь необходим, -- если изображения символов содержат сверху и снизу от символа фон. -- crdsClear был предварительно очищен от дублей, теперь сортируется.
--table.show(crdsClear,"crdsClear") --table.toInit(crdsClear) table.sort(crdsClear, function(a,b) if math.abs(a.y - b.y) <= options.deltaY then if a.x < b.x then return true else return false end else if a.y < b.y then return true else return false end end end ) --table.show(crdsClear,"crdsClear")
-- Собираем строку --log(#crdsClear) local result = {{crdsClear[1].symbolName}} local resultX, resultY = 1, 1 for i=2, #crdsClear, 1 do -- Добавляем перенос и символ, возрващем каретку. if crdsClear[i-1].y + options.deltaY < crdsClear[i].y then resultX = resultX + 1 resultY = 1 -- возврат картеки result[resultX]={crdsClear[i].symbolName} -- Добавляем пробел и символ elseif crdsClear[i-1].xEnd + options.deltaSpace < crdsClear[i].x then resultY = resultY + 1 result[resultX][resultY] = crdsClear[i].symbolName -- Добавляем символ else result[resultX][resultY] = result[resultX][resultY].. crdsClear[i].symbolName end --table.show(result,"result") end --table.show(result,"result") return result end end Сообщение отредактировал DarkMaster - 26.9.2017, 12:45
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
DarkMaster |
26.9.2017, 16:27
|
Модератор UOPilot
Сообщений: 9.460
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 27707
Пользователь №: 11.279
|
Фишки луа, которые не учел. Тут же arr={} не таблица, а только ссылка на таблицу и копирование arr2=arr1 не проходит - данные не копируются. Распознавание текста Lua
Код --lua -- Автор скрипта DarkMaster. -- Написано по мотивам скрипта Cirus. -- Тестирование Cirus. -- Вопросы, баги, предложения на форум -- в специальную тему по этому скрипту -- https://forum.uokit.com/index.php?showtopic=30000
-- Фикс: символы по умолчанию больше не изменятся, сделано корректное копирование массива.
-- Фикс: флаг чтения подпапок был инвертирован. -- Фикс: secondFrameTimeout больше не глобальная и используется по назначению. -- Фикс: При default.timeProc = -1 и default.secondFrame > 0 не выходит преждевременно из функции. -- Фикс: Почистил отладочные выводы в лог. -- Добавлено сохранение изображение в котором происходил поиск.
-- Баг: из-за особенностей костыля финдимиджа создается НЕ локальня переменная tmp. -- Фикс: изображение не добавлялось в буфер. -- Фикс: расчет пробела от конечной х координаты. -- Фикс: очистка буфера после захвата изображения. -- Фикс: область поиска при источнике из getimage должна быть с нуля. -- Фикс: искалось только одно изображение из-за недостающего вложенного цикла. -- Фикс: буфер теперь действительно буферезует. -- Переработно преобразование из упрощенного синтаксиса в полнеценный. Добавлена защита от дурка (типы данных). -- Добавлено: загрузка папки с изображениями. -- Добавлено: ожидание прогрузки изображений (options.secondFrame). -- Добавлено: чтение из буфера.
do
-- Раскомментировать, если в отладке будет использоват table.show. --[[do local tab = "" local deep = 0 function table.show(t, comment) -- Пишем в лог комментарий. deep = deep + 1 -- Уровень вложенности вызовов функции. --log(comment .. commentSended .. deep) if comment ~= nil and deep == 1 then log(comment) end
if type(t) == "nil" then log("table is nil") elseif type(t) == "string" then log('table is string: "'..t..'"') elseif type(t) == "number" then log('table is number: '..t) elseif type(t) == "table" then local elementsInTable = 0 for k,v in pairs(t) do if type (v) == "table" then if type(k) == "string" then log(tab..'table: "'..k..'"') else log(tab..'table: '..k) end tab = tab .. " " table.show(v) tab = string.sub(tab, 1, -5) elementsInTable = elementsInTable + 1 else elementsInTable = elementsInTable + 1 if type(v) == "string" then v = '"'..v..'"' end if type(k) == "string" then k = '"'..k..'"' end log(tab..""..k.." = "..v) end end if elementsInTable == 0 then log("table is empty") end else log('table is unknow data type') end -- Пишем в лог комментарий. deep = deep - 1 -- Уровень вложенности вызовов функции. end end ]]
local function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, deepcopy(getmetatable(orig))) else -- number, string, boolean, etc copy = orig end return copy end
-- Символы для поиска. -- Возможно указать в двух вариантах синтаксиса: упрощенном и полном. -- Упрощенный синтаксис: -- В упрощенном варианте синтаксиса допускается не указывать -- соответствие имен файлов и строке/символу, -- который они обозначают: считается, что они идентичны. -- Пример упрощенного синтаксиса: -- local symbols = {"0", "1", "2", "3", "a", "b", "c", "test"} -- Полный синтаксис: -- Полный синтаксис бывает необходим при использовании -- нескольких изображений соответсвующих одной и той же строке/символу. -- Допускаются переносы строк: -- local symbols = { -- ["0"] = {"zero1", "zero2"}, -- ["1"] = {"1a", "1b"}, -- ["2"] = {"two", "second"} -- } -- Оба варианта синтаксиса можно сочетать: -- local symbols = {"0", "1", ["2"] = {"two", "second"}, "3"}
local default = {} default.crds = {0, 0, 1920, 1080} -- Координаты поиска default.path = "c:\\image" -- Папка с картинками default.ext = ".bmp" -- Расширение картинок default.loadFolder = nil -- Путь по которому будут загружены все изображения с указанной маской {path=путь, mask=маска, sub=1|0}(sub - подпапки). Имя файла будет соответсвовать имени символа. default.deltaY = 8 -- Расстояние между строками (можно указать высоту картинок) default.deltaSpace = 2 -- Допустимое расстояние между цифрами, иначе будет считаться что это не одно число default.accuracy = 95 -- Точность поиска для Findimage default.deviation = 3 -- Погрешность оттенка для Findimage default.wait = 2 -- Пауза между поиском картинок, если указать меньше искать будет быстрее, но нагрузит процессор default.timeProc = 2 -- Время в секундах (может быть не целым) для поиска картинок, если -1 не выйдет из процедуры пока не найдётся хотя бы 1 картинка default.repeatImage = 2 -- Допустимое смещение координат, если используется несколько видов одной картинки default.window = "workwindow" -- Метод|хендл_окна в котором происходит поиск (если указан источник изображения(source), то параметр будет проигнорирован) default.abs = 0 -- Использовать abs координаты. default.source = nil -- Изображение в котором производится поиск. Должен быть задан таблицей {адрес, ширина, высота}, nil вместо таблицы приведет к захвату изображения с экрана. default.bufferAddNew = 1 -- Добавлять изображения в буфер default.bufferIgnore = 0 -- Игнорировать изображения находящиеся в буфере default.bufferUpdate = 0 -- Обновить изображения содержащиеся в буфере. default.secondFrame = 0 -- Ожидание прогрузки значений. Изображение будет проанализировано только после secondFrame секунд с первой успешной попытки считать любое из избражений. default.saveImage = nil -- Путь по которому будет сохранено изображение в котором происходит поиск. -- набор стандартных символов default.symbols = {["0"]={"0"}, ["1"]={"1"}, ["2"]={"2"}, ["3"]={"3"}, ["4"]={"4"}, ["5"]={"5"}, ["6"]={"6"}, ["7"]={"7"}, ["8"]={"8"}, ["9"]={"9"}}
-- Буфер -- Буфер -- Буфер
local buffer = {} -- Массив с загруженными картинками. imageToStringBuffer = {} -- набор функций по управлению буфером. -- Полностью очищаем массив. function imageToStringBuffer.flush() for k,_ in pairs(buffer) do buffer[v] = nil end end -- Удаляем элемент из буфера function imageToStringBuffer.flush(element) buffer[element] = nil end -- Добавляем изображение в буфер function imageToStringBuffer.flush(element, val) buffer[element] = val end -- Читаем изображение из буфера function imageToStringBuffer.flush(element) return buffer[element] end
-- Поиск -- Поиск -- Поиск
function imageToString(options)
-- Проверяем переданные параметры. Если они отсутствуют - подставляем параметры по умолчанию. if options == nil then local options = {} end if options.crds == nil then options.crds = default.crds end if options.path == nil then options.path = default.path end if options.ext == nil then options.ext = default.ext end if options.loadFolder == nil then options.loadFolder = default.loadFolder end if options.deltaY == nil then options.deltaY = default.deltaY end if options.deltaSpace == nil then options.deltaSpace = default.deltaSpace end if options.accuracy == nil then options.accuracy = default.accuracy end if options.deviation == nil then options.deviation = default.deviation end if options.wait == nil then options.wait = default.wait end if options.timeProc == nil then options.timeProc = default.timeProc end if options.repeatImage == nil then options.repeatImage = default.repeatImage end if options.window == nil then options.window = default.window end if options.abs == nil then options.abs = default.abs end if options.source == nil then options.source = default.source end if options.bufferAddNew == nil then options.bufferAddNew = default.bufferAddNew end if options.bufferIgnore == nil then options.bufferIgnore = default.bufferIgnore end if options.bufferUpdate == nil then options.bufferUpdate = default.bufferUpdate end if options.secondFrame == nil then options.secondFrame = default.secondFrame end if options.saveImage == nil then options.saveImage = default.saveImage end if options.symbols == nil then if options.loadFolder == nil then options.symbols = deepcopy(default.symbols) else options.symbols = {} end end
--Добавляем при необходимости обратный слэш в путь. if string.sub(options.path, -1) ~= "\\" then options.path = options.path .. "\\" end
-- Папка для загрузки изображений не задана, загружаем обычным методом. if options.loadFolder == nil then -- Преобразуем урощенный синтаксис в полноценный, преобразуем пути в полные. do local tmp = {} --Массив в который временно помещаются преобразованные данные. for symbolName, imageName in pairs(options.symbols) do -- Если занчение задано строкой/числом, приводим его к таблице, дописываем путь до полного. if type(options.symbols[symbolName]) == "number" then options.symbols[symbolName] = {options.path..tostring(imageName)..options.ext} elseif type(options.symbols[symbolName]) == "string" then options.symbols[symbolName] = {options.path..imageName..options.ext} -- Значение задано таблицей, преобразоываем числа в строки, дописываем путь до полного. elseif type(options.symbols[symbolName]) == "table" then for n=1, #options.symbols[symbolName] do if type(options.symbols[symbolName][n]) == "number" then options.symbols[symbolName][n] = options.path..tostring(options.symbols[symbolName][n])..options.ext elseif type(options.symbols[symbolName][n]) == "string" then options.symbols[symbolName][n] = options.path..options.symbols[symbolName][n]..options.ext else msg ("Ошибочный тип значения картинок символов в таблице. Остановка скрипта") stop_script() end end else msg ("Ошибочный тип значения картинок символов. Остановка скрипта") stop_script() end
-- Если ключ цифровой, преобразуем к строке if type(symbolName) == "number" then tmp[tostring(symbolName)] = options.symbols[symbolName] elseif type(symbolName) == "string" then tmp[symbolName] = options.symbols[symbolName] else msg ("Ошибочный тип ключа символов. Остановка скрипта") stop_script() end end options.symbols = tmp end else -- Загружаем папку с изображениями. -- Имя файла = имя символа. -- Допускается несколько одинаковых символов в различных подпапках. -- Приводим к понятному для пилота виду флаг чтение подпапок.
-- Прилепляем кавычки к пути чтобы пилот не путал путь и маску. options.loadFolder.path = '"'..options.loadFolder.path..'"' if options.loadFolder.sub == 1 then options.loadFolder.sub = nil else options.loadFolder.sub = "norecursion" end -- Приводим маску к надлежащему виду, если она не задана. if options.loadFolder.mask == nil then options.loadFolder.mask = "*" end fileList = dir(options.loadFolder.path, options.loadFolder.mask, options.loadFolder.sub) --table.show(fileList, "fileList") for k, v in pairs (fileList) do -- символ уже существует (несколько вариантов изображения) if options.symbols[v[3]] ~= nil then table.insert(options.symbols[v[3]], v[1]) else options.symbols[v[3]] = {v[1]} end end end --table.show(options.symbols)
-- Приводим options.abs к виду пригодному для финдимиджа. if options.abs == 1 then options.abs = "abs" elseif options.abs == 0 then options.abs = "" end
-- Загрузка картинок local images={} --Загружает в память изображения {имя символа, {адреса в памяти}} local loadError = 0 for symbolName, fileList in pairs(options.symbols) do images[symbolName] = {} for i=1, #fileList, 1 do -- Загружен ли файл в буфер, если нет, то подгружаем. local filePath = fileList[i] if options.bufferIgnore == 0 and options.bufferUpdate == 0 and buffer[filePath] ~= nil then images[symbolName][i] = buffer[filePath] else -- В буфере изображения нет, загружаем с диска. --log(filePath.."В буфере изображения нет, загружаем с диска.") images[symbolName][i] = loadimage(filePath) -- Обновляем загруженное в буфер изображение if buffer[filePath] ~= nil then deleteimage(buffer[filePath]) buffer[filePath] = images[symbolName][i] elseif options.bufferAddNew == 1 and options.bufferIgnore == 0 then -- Добавляем в буфер новое изображение. buffer[filePath] = images[symbolName][i] end end -- Поиск ошибок загрузки. if images[symbolName][i] < 0 then loadError = loadError + 1 log("Image loading fail. Error file: "..filePath..'.') end end end -- При загрузке изображений произошли ошибки. Останавливаем скрипт. if loadError > 0 then log("Error loading count: "..loadError..'.') stop_script() end if images == nil then log("Файлы изображений не найдены. Скрипт остановлен.") stop_script() end --table.show(images,"images")
local timeout = os.clock() + options.timeProc
-- log(options.secondFrame) -- Таймаут на прогрузку. Поиск для детекта изображений. if options.secondFrame > 0 then -- Создаем карман области видимости. -- Реузльататы блока не нужны для остального скрипта. do local catch = 0 -- Если вермя ожидания после детекта не уложится в общий -- таймаут, то выходим из цикла без дальшейших попыток найти изображение. local secondFrameTimeout = timeout - options.secondFrame while true do -- выход внутри цикла timeout < os.clock() local screenshot, width, height = nil, nil, nil if options.source == nil then screenshot, width, height = getimage(options.crds[1],options.crds[2],options.crds[3],options.crds[4], options.window) else screenshot, width, height = options.source[1],options.source[2],options.source[3] end for symbolName, imageAddressArray in pairs(images) do for _, imageAddress in pairs(imageAddressArray) do local tmp = {} findResult = findimage( 0 .. " " .. 0 .. " " .. width .. " " .. height .. " " .. "(" .. imageAddress .. ") " .. "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) --log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить. if findResult ~= "0" and not string.find(findResult, "-") then catch = 1 --log("break") wait(math.floor(options.secondFrame * 1000)) break end -- Время на всю функцию истекло if secondFrameTimeout < os.clock() and options.timeProc ~= -1 then return end end if catch == 1 then break end end if catch == 1 then break end end end end
-- Ищем изображения local crdsRaw={} -- Массив со всеми найденными изображениями, возможны дубли, не сортированный. repeat -- Повторяем пока что-то не найдем или не выйдет время на поиск (options.timeProc). -- Получаем изображение с экрана, если источник не указан. local screenshot, width, height = nil if options.source == nil then screenshot, width, height = getimage(options.crds[1],options.crds[2],options.crds[3],options.crds[4], options.window) else screenshot, width, height = options.source[1],options.source[2],options.source[3] end --log(screenshot) for symbolName, imageAddressArray in pairs(images) do for _, imageAddress in pairs(imageAddressArray) do tmp = {} findResult = findimage( 0 .. " " .. 0 .. " " .. width .. " " .. height .. " " .. "(" .. imageAddress .. ") " .. "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) --log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить. if findResult ~= "0" and not string.find(findResult, "-") then -- Добавляем найденные значения в общий результат поисков. --table.show(tmp,"tmp") for i = 1, #tmp, 1 do -- Напрямую вернуть таблицу в функцию нельзя из-за синтаксиса. -- FIX. Нужен фикс функции findimage пилота (возвращает координаты стрингом) -- после фикса просто удалить "tonumber(parm)" оставив parm. table.insert(crdsRaw,{x=tonumber(tmp[i][1]),y=tonumber(tmp[i][2]),xEnd=tonumber(tmp[i][3]),symbolName=symbolName}) end end end end
-- Сохраняем изображение. if options.saveImage ~= nil then saveimage(screenshot, options.saveImage) end -- Удаляем изображение, если получали его из приложения. if options.source == nil then deleteimage(screenshot) end
--table.show(images, "images") --log (#crdsRaw, timeout, os.clock(), options.timeProc) --log ("until") local clock = os.clock() until not ((#crdsRaw == 0) and (timeout > clock or options.timeProc == -1)) --table.show(crdsRaw, "crdsRaw")
-- Изображения не были найдены, выходим из поиска. if #crdsRaw < 1 then return nil end -- Удаляем дубли. local crdsClear={} -- Массив без дублей. for i=1, #crdsRaw, 1 do local catch = 0 -- Флаг найденного дубля. for n=i+1, #crdsRaw, 1 do --log( -- crdsRaw[i].symbolName.." == "..crdsRaw[n].symbolName.." and ".. -- math.abs(crdsRaw[i].x - crdsRaw[n].x).." <= "..options.repeatImage.." and ".. -- math.abs(crdsRaw[i].y - crdsRaw[n].y).." <= "..options.repeatImage --) if crdsRaw[i].symbolName == crdsRaw[n].symbolName and math.abs(crdsRaw[i].x - crdsRaw[n].x) <= options.repeatImage and math.abs(crdsRaw[i].y - crdsRaw[n].y) <= options.repeatImage then catch = 1 break end end --log(catch) if catch == 0 then -- не дубль, копируем значение в чистый массив. table.insert(crdsClear,crdsRaw[i]) end end
-- Сортируем элементы. -- Сортировка происходит, как по X координате, -- так и по Y учитывая возможность нескольких строк. -- Межстрочный интервал задается с помощью options.deltaY. -- Для уплотнения поиска options.deltaY может быть отрицательным. -- Отрицательный options.deltaY в первую очередь необходим, -- если изображения символов содержат сверху и снизу от символа фон. -- crdsClear был предварительно очищен от дублей, теперь сортируется.
--table.show(crdsClear,"crdsClear") --table.toInit(crdsClear) table.sort(crdsClear, function(a,b) if math.abs(a.y - b.y) <= options.deltaY then if a.x < b.x then return true else return false end else if a.y < b.y then return true else return false end end end ) --table.show(crdsClear,"crdsClear")
-- Собираем строку --log(#crdsClear) local result = {{crdsClear[1].symbolName}} local resultX, resultY = 1, 1 for i=2, #crdsClear, 1 do -- Добавляем перенос и символ, возрващем каретку. if crdsClear[i-1].y + options.deltaY < crdsClear[i].y then resultX = resultX + 1 resultY = 1 -- возврат картеки result[resultX]={crdsClear[i].symbolName} -- Добавляем пробел и символ elseif crdsClear[i-1].xEnd + options.deltaSpace < crdsClear[i].x then resultY = resultY + 1 result[resultX][resultY] = crdsClear[i].symbolName -- Добавляем символ else result[resultX][resultY] = result[resultX][resultY].. crdsClear[i].symbolName end --table.show(result,"result") end --table.show(result,"result") return result end end
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
DarkMaster |
27.9.2017, 13:13
|
Модератор UOPilot
Сообщений: 9.460
Регистрация: 2.12.2008 Группа: Супермодераторы Наличность: 27707
Пользователь №: 11.279
|
Цитата Для default.loadFolder тоже ведь надо. Эмм... там же nil вроде как, что исключает вообще какое-либо копирование. Ну сейчас на всех массивах проставлю. Распознавание текста Lua
Код -- Автор скрипта DarkMaster. -- Написано по мотивам скрипта Cirus. -- Тестирование Cirus. -- Вопросы, баги, предложения на форум -- в специальную тему по этому скрипту -- https://forum.uokit.com/index.php?showtopic=30000
-- Фикс: символы по умолчанию больше не переписываются, сделано корректное копирование массива.
-- Фикс: флаг чтения подпапок был инвертирован. -- Фикс: secondFrameTimeout больше не глобальная и используется по назначению. -- Фикс: При default.timeProc = -1 и default.secondFrame > 0 не выходит преждевременно из функции. -- Фикс: Почистил отладочные выводы в лог. -- Добавлено сохранение изображение в котором происходил поиск.
-- Баг: из-за особенностей костыля финдимиджа создается НЕ локальня переменная tmp. -- Фикс: изображение не добавлялось в буфер. -- Фикс: расчет пробела от конечной х координаты. -- Фикс: очистка буфера после захвата изображения. -- Фикс: область поиска при источнике из getimage должна быть с нуля. -- Фикс: искалось только одно изображение из-за недостающего вложенного цикла. -- Фикс: буфер теперь действительно буферезует. -- Переработно преобразование из упрощенного синтаксиса в полнеценный. Добавлена защита от дурка (типы данных). -- Добавлено: загрузка папки с изображениями. -- Добавлено: ожидание прогрузки изображений (options.secondFrame). -- Добавлено: чтение из буфера.
do
-- Раскомментировать, если в отладке будет использоват table.show. --[[do local tab = "" local deep = 0 function table.show(t, comment) -- Пишем в лог комментарий. deep = deep + 1 -- Уровень вложенности вызовов функции. --log(comment .. commentSended .. deep) if comment ~= nil and deep == 1 then log(comment) end
if type(t) == "nil" then log("table is nil") elseif type(t) == "string" then log('table is string: "'..t..'"') elseif type(t) == "number" then log('table is number: '..t) elseif type(t) == "table" then local elementsInTable = 0 for k,v in pairs(t) do if type (v) == "table" then if type(k) == "string" then log(tab..'table: "'..k..'"') else log(tab..'table: '..k) end tab = tab .. " " table.show(v) tab = string.sub(tab, 1, -5) elementsInTable = elementsInTable + 1 else elementsInTable = elementsInTable + 1 if type(v) == "string" then v = '"'..v..'"' end if type(k) == "string" then k = '"'..k..'"' end log(tab..""..k.." = "..v) end end if elementsInTable == 0 then log("table is empty") end else log('table is unknow data type') end -- Пишем в лог комментарий. deep = deep - 1 -- Уровень вложенности вызовов функции. end end ]]
function dc(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[dc(orig_key)] = dc(orig_value) end setmetatable(copy, dc(getmetatable(orig))) else -- number, string, boolean, etc copy = orig end return copy end
-- Символы для поиска. -- Возможно указать в двух вариантах синтаксиса: упрощенном и полном. -- Упрощенный синтаксис: -- В упрощенном варианте синтаксиса допускается не указывать -- соответствие имен файлов и строке/символу, -- который они обозначают: считается, что они идентичны. -- Пример упрощенного синтаксиса: -- local symbols = {"0", "1", "2", "3", "a", "b", "c", "test"} -- Полный синтаксис: -- Полный синтаксис бывает необходим при использовании -- нескольких изображений соответсвующих одной и той же строке/символу. -- Допускаются переносы строк: -- local symbols = { -- ["0"] = {"zero1", "zero2"}, -- ["1"] = {"1a", "1b"}, -- ["2"] = {"two", "second"} -- } -- Оба варианта синтаксиса можно сочетать: -- local symbols = {"0", "1", ["2"] = {"two", "second"}, "3"}
local default = {} default.crds = {0, 0, 1920, 1080} -- Координаты поиска default.path = "c:\\image" -- Папка с картинками default.ext = ".bmp" -- Расширение картинок default.loadFolder = nil -- Путь по которому будут загружены все изображения с указанной маской {path=путь, mask=маска, sub=1|0}(sub - подпапки). Имя файла будет соответсвовать имени символа. default.deltaY = 8 -- Расстояние между строками (можно указать высоту картинок) default.deltaSpace = 2 -- Допустимое расстояние между цифрами, иначе будет считаться что это не одно число default.accuracy = 95 -- Точность поиска для Findimage default.deviation = 3 -- Погрешность оттенка для Findimage default.wait = 2 -- Пауза между поиском картинок, если указать меньше искать будет быстрее, но нагрузит процессор default.timeProc = 2 -- Время в секундах (может быть не целым) для поиска картинок, если -1 не выйдет из процедуры пока не найдётся хотя бы 1 картинка default.repeatImage = 2 -- Допустимое смещение координат, если используется несколько видов одной картинки default.window = "workwindow" -- Метод|хендл_окна в котором происходит поиск (если указан источник изображения(source), то параметр будет проигнорирован) default.abs = 0 -- Использовать abs координаты. default.source = nil -- Изображение в котором производится поиск. Должен быть задан таблицей {адрес, ширина, высота}, nil вместо таблицы приведет к захвату изображения с экрана. default.bufferAddNew = 1 -- Добавлять изображения в буфер default.bufferIgnore = 0 -- Игнорировать изображения находящиеся в буфере default.bufferUpdate = 0 -- Обновить изображения содержащиеся в буфере. default.secondFrame = 0 -- Ожидание прогрузки значений. Изображение будет проанализировано только после secondFrame секунд с первой успешной попытки считать любое из избражений. default.saveImage = nil -- Путь по которому будет сохранено изображение в котором происходит поиск. -- набор стандартных символов default.symbols = {["0"]={"0"}, ["1"]={"1"}, ["2"]={"2"}, ["3"]={"3"}, ["4"]={"4"}, ["5"]={"5"}, ["6"]={"6"}, ["7"]={"7"}, ["8"]={"8"}, ["9"]={"9"}}
-- Буфер -- Буфер -- Буфер
local buffer = {} -- Массив с загруженными картинками. imageToStringBuffer = {} -- набор функций по управлению буфером. -- Полностью очищаем массив. function imageToStringBuffer.flush() for k,_ in pairs(buffer) do buffer[v] = nil end end -- Удаляем элемент из буфера function imageToStringBuffer.flush(element) buffer[element] = nil end -- Добавляем изображение в буфер function imageToStringBuffer.flush(element, val) buffer[element] = val end -- Читаем изображение из буфера function imageToStringBuffer.flush(element) return buffer[element] end
-- Поиск -- Поиск -- Поиск
function imageToString(options)
-- Проверяем переданные параметры. Если они отсутствуют - подставляем параметры по умолчанию. if options == nil then local options = {} end if options.crds == nil then options.crds = default.crds end if options.path == nil then options.path = default.path end if options.ext == nil then options.ext = default.ext end if options.loadFolder == nil then options.loadFolder = dc(default.loadFolder) end if options.deltaY == nil then options.deltaY = default.deltaY end if options.deltaSpace == nil then options.deltaSpace = default.deltaSpace end if options.accuracy == nil then options.accuracy = default.accuracy end if options.deviation == nil then options.deviation = default.deviation end if options.wait == nil then options.wait = default.wait end if options.timeProc == nil then options.timeProc = default.timeProc end if options.repeatImage == nil then options.repeatImage = default.repeatImage end if options.window == nil then options.window = default.window end if options.abs == nil then options.abs = default.abs end if options.source == nil then options.source = dc(default.source) end if options.bufferAddNew == nil then options.bufferAddNew = default.bufferAddNew end if options.bufferIgnore == nil then options.bufferIgnore = default.bufferIgnore end if options.bufferUpdate == nil then options.bufferUpdate = default.bufferUpdate end if options.secondFrame == nil then options.secondFrame = default.secondFrame end if options.saveImage == nil then options.saveImage = default.saveImage end if options.symbols == nil then if options.loadFolder == nil then options.symbols = dc(default.symbols) else options.symbols = {} end end
--Добавляем при необходимости обратный слэш в путь. if string.sub(options.path, -1) ~= "\\" then options.path = options.path .. "\\" end
-- Папка для загрузки изображений не задана, загружаем обычным методом. if options.loadFolder == nil then -- Преобразуем урощенный синтаксис в полноценный, преобразуем пути в полные. do local tmp = {} --Массив в который временно помещаются преобразованные данные. for symbolName, imageName in pairs(options.symbols) do -- Если занчение задано строкой/числом, приводим его к таблице, дописываем путь до полного. if type(options.symbols[symbolName]) == "number" then options.symbols[symbolName] = {options.path..tostring(imageName)..options.ext} elseif type(options.symbols[symbolName]) == "string" then options.symbols[symbolName] = {options.path..imageName..options.ext} -- Значение задано таблицей, преобразоываем числа в строки, дописываем путь до полного. elseif type(options.symbols[symbolName]) == "table" then for n=1, #options.symbols[symbolName] do if type(options.symbols[symbolName][n]) == "number" then options.symbols[symbolName][n] = options.path..tostring(options.symbols[symbolName][n])..options.ext elseif type(options.symbols[symbolName][n]) == "string" then options.symbols[symbolName][n] = options.path..options.symbols[symbolName][n]..options.ext else msg ("Ошибочный тип значения картинок символов в таблице. Остановка скрипта") stop_script() end end else msg ("Ошибочный тип значения картинок символов. Остановка скрипта") stop_script() end
-- Если ключ цифровой, преобразуем к строке if type(symbolName) == "number" then tmp[tostring(symbolName)] = options.symbols[symbolName] elseif type(symbolName) == "string" then tmp[symbolName] = options.symbols[symbolName] else msg ("Ошибочный тип ключа символов. Остановка скрипта") stop_script() end end options.symbols = tmp end else -- Загружаем папку с изображениями. -- Имя файла = имя символа. -- Допускается несколько одинаковых символов в различных подпапках. -- Приводим к понятному для пилота виду флаг чтение подпапок.
-- Прилепляем кавычки к пути чтобы пилот не путал путь и маску. options.loadFolder.path = '"'..options.loadFolder.path..'"' if options.loadFolder.sub == 1 then options.loadFolder.sub = nil else options.loadFolder.sub = "norecursion" end -- Приводим маску к надлежащему виду, если она не задана. if options.loadFolder.mask == nil then options.loadFolder.mask = "*" end fileList = dir(options.loadFolder.path, options.loadFolder.mask, options.loadFolder.sub) --table.show(fileList, "fileList") for k, v in pairs (fileList) do -- символ уже существует (несколько вариантов изображения) if options.symbols[v[3]] ~= nil then table.insert(options.symbols[v[3]], v[1]) else options.symbols[v[3]] = {v[1]} end end end --table.show(options.symbols)
-- Приводим options.abs к виду пригодному для финдимиджа. if options.abs == 1 then options.abs = "abs" elseif options.abs == 0 then options.abs = "" end
-- Загрузка картинок local images={} --Загружает в память изображения {имя символа, {адреса в памяти}} local loadError = 0 for symbolName, fileList in pairs(options.symbols) do images[symbolName] = {} for i=1, #fileList, 1 do -- Загружен ли файл в буфер, если нет, то подгружаем. local filePath = fileList[i] if options.bufferIgnore == 0 and options.bufferUpdate == 0 and buffer[filePath] ~= nil then images[symbolName][i] = buffer[filePath] else -- В буфере изображения нет, загружаем с диска. --log(filePath.."В буфере изображения нет, загружаем с диска.") images[symbolName][i] = loadimage(filePath) -- Обновляем загруженное в буфер изображение if buffer[filePath] ~= nil then deleteimage(buffer[filePath]) buffer[filePath] = images[symbolName][i] elseif options.bufferAddNew == 1 and options.bufferIgnore == 0 then -- Добавляем в буфер новое изображение. buffer[filePath] = images[symbolName][i] end end -- Поиск ошибок загрузки. if images[symbolName][i] < 0 then loadError = loadError + 1 log("Image loading fail. Error file: "..filePath..'.') end end end -- При загрузке изображений произошли ошибки. Останавливаем скрипт. if loadError > 0 then log("Error loading count: "..loadError..'.') stop_script() end if images == nil then log("Файлы изображений не найдены. Скрипт остановлен.") stop_script() end --table.show(images,"images")
local timeout = os.clock() + options.timeProc
-- log(options.secondFrame) -- Таймаут на прогрузку. Поиск для детекта изображений. if options.secondFrame > 0 then -- Создаем карман области видимости. -- Реузльататы блока не нужны для остального скрипта. do local catch = 0 -- Если вермя ожидания после детекта не уложится в общий -- таймаут, то выходим из цикла без дальшейших попыток найти изображение. local secondFrameTimeout = timeout - options.secondFrame while true do -- выход внутри цикла timeout < os.clock() local screenshot, width, height = nil, nil, nil if options.source == nil then screenshot, width, height = getimage(options.crds[1],options.crds[2],options.crds[3],options.crds[4], options.window) else screenshot, width, height = options.source[1],options.source[2],options.source[3] end for symbolName, imageAddressArray in pairs(images) do for _, imageAddress in pairs(imageAddressArray) do local tmp = {} findResult = findimage( 0 .. " " .. 0 .. " " .. width .. " " .. height .. " " .. "(" .. imageAddress .. ") " .. "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) --log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить. if findResult ~= "0" and not string.find(findResult, "-") then catch = 1 --log("break") wait(math.floor(options.secondFrame * 1000)) break end -- Время на всю функцию истекло if secondFrameTimeout < os.clock() and options.timeProc ~= -1 then return end end if catch == 1 then break end end if catch == 1 then break end end end end
-- Ищем изображения local crdsRaw={} -- Массив со всеми найденными изображениями, возможны дубли, не сортированный. repeat -- Повторяем пока что-то не найдем или не выйдет время на поиск (options.timeProc). -- Получаем изображение с экрана, если источник не указан. local screenshot, width, height = nil if options.source == nil then screenshot, width, height = getimage(options.crds[1],options.crds[2],options.crds[3],options.crds[4], options.window) else screenshot, width, height = options.source[1],options.source[2],options.source[3] end --log(screenshot) for symbolName, imageAddressArray in pairs(images) do for _, imageAddress in pairs(imageAddressArray) do tmp = {} findResult = findimage( 0 .. " " .. 0 .. " " .. width .. " " .. height .. " " .. "(" .. imageAddress .. ") " .. "%tmp " .. screenshot .. " " .. options.accuracy .. " -1 " .. options.deviation .. " " .. options.abs) --log("symoblName: ".. symbolName .. " findResult: " .. findResult) -- проверяем на возрват нуля или ошбики, со стрингом нормально не сравнить. if findResult ~= "0" and not string.find(findResult, "-") then -- Добавляем найденные значения в общий результат поисков. --table.show(tmp,"tmp") for i = 1, #tmp, 1 do -- Напрямую вернуть таблицу в функцию нельзя из-за синтаксиса. -- FIX. Нужен фикс функции findimage пилота (возвращает координаты стрингом) -- после фикса просто удалить "tonumber(parm)" оставив parm. table.insert(crdsRaw,{x=tonumber(tmp[i][1]),y=tonumber(tmp[i][2]),xEnd=tonumber(tmp[i][3]),symbolName=symbolName}) end end end end
-- Сохраняем изображение. if options.saveImage ~= nil then saveimage(screenshot, options.saveImage) end -- Удаляем изображение, если получали его из приложения. if options.source == nil then deleteimage(screenshot) end
--table.show(images, "images") --log (#crdsRaw, timeout, os.clock(), options.timeProc) --log ("until") local clock = os.clock() until not ((#crdsRaw == 0) and (timeout > clock or options.timeProc == -1)) --table.show(crdsRaw, "crdsRaw")
-- Изображения не были найдены, выходим из поиска. if #crdsRaw < 1 then return nil end -- Удаляем дубли. local crdsClear={} -- Массив без дублей. for i=1, #crdsRaw, 1 do local catch = 0 -- Флаг найденного дубля. for n=i+1, #crdsRaw, 1 do --log( -- crdsRaw[i].symbolName.." == "..crdsRaw[n].symbolName.." and ".. -- math.abs(crdsRaw[i].x - crdsRaw[n].x).." <= "..options.repeatImage.." and ".. -- math.abs(crdsRaw[i].y - crdsRaw[n].y).." <= "..options.repeatImage --) if crdsRaw[i].symbolName == crdsRaw[n].symbolName and math.abs(crdsRaw[i].x - crdsRaw[n].x) <= options.repeatImage and math.abs(crdsRaw[i].y - crdsRaw[n].y) <= options.repeatImage then catch = 1 break end end --log(catch) if catch == 0 then -- не дубль, копируем значение в чистый массив. table.insert(crdsClear,crdsRaw[i]) end end
-- Сортируем элементы. -- Сортировка происходит, как по X координате, -- так и по Y учитывая возможность нескольких строк. -- Межстрочный интервал задается с помощью options.deltaY. -- Для уплотнения поиска options.deltaY может быть отрицательным. -- Отрицательный options.deltaY в первую очередь необходим, -- если изображения символов содержат сверху и снизу от символа фон. -- crdsClear был предварительно очищен от дублей, теперь сортируется.
--table.show(crdsClear,"crdsClear") --table.toInit(crdsClear) table.sort(crdsClear, function(a,b) if math.abs(a.y - b.y) <= options.deltaY then if a.x < b.x then return true else return false end else if a.y < b.y then return true else return false end end end ) --table.show(crdsClear,"crdsClear")
-- Собираем строку --log(#crdsClear) local result = {{crdsClear[1].symbolName}} local resultX, resultY = 1, 1 for i=2, #crdsClear, 1 do -- Добавляем перенос и символ, возрващем каретку. if crdsClear[i-1].y + options.deltaY < crdsClear[i].y then resultX = resultX + 1 resultY = 1 -- возврат картеки result[resultX]={crdsClear[i].symbolName} -- Добавляем пробел и символ elseif crdsClear[i-1].xEnd + options.deltaSpace < crdsClear[i].x then resultY = resultY + 1 result[resultX][resultY] = crdsClear[i].symbolName -- Добавляем символ else result[resultX][resultY] = result[resultX][resultY].. crdsClear[i].symbolName end --table.show(result,"result") end --table.show(result,"result") return result end end
Сообщение отредактировал DarkMaster - 27.9.2017, 22:30
--------------------
Скрипты UOPilot под заказ. Консультации по UOpilot 15$/час. Услуги Lua разработчика (не пилот, проекты, постоянка) Disсоrd: Kov____
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|