Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

UoKit.com Форумы _ UO Pilot _ Помогите освоить LUA

Автор: sutra 24.10.2018, 18:09

Начал осваивать LUA, помогите пожалуйста, в справке нет многих операторов.
Сразу возник вопрос, как загрузить массив из файла (аналог load_array), наверняка ответ на форуме есть, но я не нашёл. В обычном скрипте код такой.

load_array %cfg $ConfigFile

Ну и сохранить соответственно тоже не знаю как.

Автор: cirus 25.10.2018, 1:58

чтение/запись файла
Код
--lua
log "clear"  log "mode compact"
local f = io.open([[C:\111.txt]], "r")  -- открыть файл для чтения

if f then    -- если файл открылся
    local cfg = {}    -- объявили массив
    for v in f:lines() do       -- читаем файл 111.txt по строкам
        cfg[#cfg+1]=v           -- добавляем в массив
    end
    f:close();   -- закрыть файл
    log(table.concat(cfg, " "))    -- вывести массив в лог

    for i=1, #cfg do         -- для всех элементов массива
        cfg[i]=tostring(i) .. " " .. cfg[i]  -- вначале строки добавим номер строки
    end

    f = io.open([[C:\222.txt]], "w")  -- открыть файл для записи
    if f then
        for i=1, #cfg do         -- для всех элементов массива
            f:write(cfg[i] .. "\r\n")  -- запись в файл
        end
        f:close();   -- закрыть файл
    end
end

Автор: DarkMaster 25.10.2018, 8:43

Поскольку lua весь на деревьях и размеры массивов могут быть различными даже в части вложенности элементов (они не прямоугольные в lua), то лучше использовать что-то более серьезное, хотя в базовом виде работать бесспроно будет.
Например есть вот такое творение:
http://lua-users.org/wiki/TablePersistence

оригинал

Код
local write, writeIndent, writers, refCount;

persistence =
{
    store = function (path, ...)
        local file, e = io.open(path, "w");
        if not file then
            return error(e);
        end
        local n = select("#", ...);
        -- Count references
        local objRefCount = {}; -- Stores reference that will be exported
        for i = 1, n do
            refCount(objRefCount, (select(i,...)));
        end;
        -- Export Objects with more than one ref and assign name
        -- First, create empty tables for each
        local objRefNames = {};
        local objRefIdx = 0;
        file:write("-- Persistent Data\n");
        file:write("local multiRefObjects = {\n");
        for obj, count in pairs(objRefCount) do
            if count > 1 then
                objRefIdx = objRefIdx + 1;
                objRefNames[obj] = objRefIdx;
                file:write("{};"); -- table objRefIdx
            end;
        end;
        file:write("\n} -- multiRefObjects\n");
        -- Then fill them (this requires all empty multiRefObjects to exist)
        for obj, idx in pairs(objRefNames) do
            for k, v in pairs(obj) do
                file:write("multiRefObjects["..idx.."][");
                write(file, k, 0, objRefNames);
                file:write("] = ");
                write(file, v, 0, objRefNames);
                file:write(";\n");
            end;
        end;
        -- Create the remaining objects
        for i = 1, n do
            file:write("local ".."obj"..i.." = ");
            write(file, (select(i,...)), 0, objRefNames);
            file:write("\n");
        end
        -- Return them
        if n > 0 then
            file:write("return obj1");
            for i = 2, n do
                file:write(" ,obj"..i);
            end;
            file:write("\n");
        else
            file:write("return\n");
        end;
        if type(path) == "string" then
            file:close();
        end;
    end;

    load = function (path)
        local f, e;
        if type(path) == "string" then
            f, e = loadfile(path);
        else
            f, e = path:read('*a')
        end
        if f then
            return f();
        else
            return nil, e;
        end;
    end;
}

-- Private methods

-- write thing (dispatcher)
write = function (file, item, level, objRefNames)
    writers[type(item)](file, item, level, objRefNames);
end;

-- write indent
writeIndent = function (file, level)
    for i = 1, level do
        file:write("\t");
    end;
end;

-- recursively count references
refCount = function (objRefCount, item)
    -- only count reference types (tables)
    if type(item) == "table" then
        -- Increase ref count
        if objRefCount[item] then
            objRefCount[item] = objRefCount[item] + 1;
        else
            objRefCount[item] = 1;
            -- If first encounter, traverse
            for k, v in pairs(item) do
                refCount(objRefCount, k);
                refCount(objRefCount, v);
            end;
        end;
    end;
end;

-- Format items for the purpose of restoring
writers = {
    ["nil"] = function (file, item)
            file:write("nil");
        end;
    ["number"] = function (file, item)
            file:write(tostring(item));
        end;
    ["string"] = function (file, item)
            file:write(string.format("%q", item));
        end;
    ["boolean"] = function (file, item)
            if item then
                file:write("true");
            else
                file:write("false");
            end
        end;
    ["table"] = function (file, item, level, objRefNames)
            local refIdx = objRefNames[item];
            if refIdx then
                -- Table with multiple references
                file:write("multiRefObjects["..refIdx.."]");
            else
                -- Single use table
                file:write("{\n");
                for k, v in pairs(item) do
                    writeIndent(file, level+1);
                    file:write("[");
                    write(file, k, level+1, objRefNames);
                    file:write("] = ");
                    write(file, v, level+1, objRefNames);
                    file:write(";\n");
                end
                writeIndent(file, level);
                file:write("}");
            end;
        end;
    ["function"] = function (file, item)
            -- Does only work for "normal" functions, not those
            -- with upvalues or c functions
            local dInfo = debug.getinfo(item, "uS");
            if dInfo.nups > 0 then
                file:write("nil --[[functions with upvalue not supported]]");
            elseif dInfo.what ~= "Lua" then
                file:write("nil --[[non-lua function not supported]]");
            else
                local r, s = pcall(string.dump,item);
                if r then
                    file:write(string.format("loadstring(%q)", s));
                else
                    file:write("nil --[[function could not be dumped]]");
                end
            end
        end;
    ["thread"] = function (file, item)
            file:write("nil --[[thread]]\n");
        end;
    ["userdata"] = function (file, item)
            file:write("nil --[[userdata]]\n");
        end;
}

Пример использования:
Код
t_original = {1, 2, ["a"] = "string", b = "test", {"subtable", [4] = 2}};
persistence.store("storage.lua", t_original);
t_restored = persistence.load("storage.lua");

Это позволит сохранят таблицы с любой структурой при этом сохраненный файл является полностью валидным lua кодом и может быть загружен через loadstring (что на самом деле и делает функция persistence.load). Вид при этом читабельный, никаких дурных проблем с зарезервированными символами и т.д.

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

local write, writeIndent, writers, refCount;

local persistence =
{
    save = function (path, ...)
        local file, e = io.open(path, "w");
        if not file then
            return error(e);
        end
        local n = select("#", ...);
        -- Count references
        local objRefCount = {}; -- Stores reference that will be exported
        for i = 1, n do
            refCount(objRefCount, (select(i,...)));
        end;
        -- Export Objects with more than one ref and assign name
        -- First, create empty tables for each
        local objRefNames = {};
        local objRefIdx = 0;
        file:write("-- Persistent Data\n");
        file:write("local multiRefObjects = {\n");
        for obj, count in pairs(objRefCount) do
            if count > 1 then
                objRefIdx = objRefIdx + 1;
                objRefNames[obj] = objRefIdx;
                file:write("{};"); -- table objRefIdx
            end;
        end;
        file:write("\n} -- multiRefObjects\n");
        -- Then fill them (this requires all empty multiRefObjects to exist)
        for obj, idx in pairs(objRefNames) do
            for k, v in pairs(obj) do
                file:write("multiRefObjects["..idx.."][");
                write(file, k, 0, objRefNames);
                file:write("] = ");
                write(file, v, 0, objRefNames);
                file:write(";\n");
            end;
        end;
        -- Create the remaining objects
        for i = 1, n do
            file:write("local ".."obj"..i.." = ");
            write(file, (select(i,...)), 0, objRefNames);
            file:write("\n");
        end
        -- Return them
        if n > 0 then
            file:write("return obj1");
            for i = 2, n do
                file:write(" ,obj"..i);
            end;
            file:write("\n");
        else
            file:write("return\n");
        end;
        if type(path) == "string" then
            file:close();
        end;
    end;

    load = function (path)
        local f, e;
        if type(path) == "string" then
            f, e = loadfile(path);
        else
            f, e = path:read('*a')
        end
        if f then
            return f();
        else
            return nil, e;
        end;
    end;
}

-- Private methods

-- write thing (dispatcher)
write = function (file, item, level, objRefNames)
    writers[type(item)](file, item, level, objRefNames);
end;

-- write indent
writeIndent = function (file, level)
    for i = 1, level do
        file:write("\t");
    end;
end;

-- recursively count references
refCount = function (objRefCount, item)
    -- only count reference types (tables)
    if type(item) == "table" then
        -- Increase ref count
        if objRefCount[item] then
            objRefCount[item] = objRefCount[item] + 1;
        else
            objRefCount[item] = 1;
            -- If first encounter, traverse
            for k, v in pairs(item) do
                refCount(objRefCount, k);
                refCount(objRefCount, v);
            end;
        end;
    end;
end;

-- Format items for the purpose of restoring
writers = {
    ["nil"] = function (file, item)
            file:write("nil");
        end;
    ["number"] = function (file, item)
            file:write(tostring(item));
        end;
    ["string"] = function (file, item)
            file:write(string.format("%q", item));
        end;
    ["boolean"] = function (file, item)
            if item then
                file:write("true");
            else
                file:write("false");
            end
        end;
    ["table"] = function (file, item, level, objRefNames)
            local refIdx = objRefNames[item];
            if refIdx then
                -- Table with multiple references
                file:write("multiRefObjects["..refIdx.."]");
            else
                -- Single use table
                file:write("{\n");
                for k, v in pairs(item) do
                    writeIndent(file, level+1);
                    file:write("[");
                    write(file, k, level+1, objRefNames);
                    file:write("] = ");
                    write(file, v, level+1, objRefNames);
                    file:write(";\n");
                end
                writeIndent(file, level);
                file:write("}");
            end;
        end;
    ["function"] = function (file, item)
            -- Does only work for "normal" functions, not those
            -- with upvalues or c functions
            local dInfo = debug.getinfo(item, "uS");
            if dInfo.nups > 0 then
                file:write("nil --[[functions with upvalue not supported]]");
            elseif dInfo.what ~= "Lua" then
                file:write("nil --[[non-lua function not supported]]");
            else
                local r, s = pcall(string.dump,item);
                if r then
                    file:write(string.format("loadstring(%q)", s));
                else
                    file:write("nil --[[function could not be dumped]]");
                end
            end
        end;
    ["thread"] = function (file, item)
            file:write("nil --[[thread]]\n");
        end;
    ["userdata"] = function (file, item)
            file:write("nil --[[userdata]]\n");
        end;
}

return persistence

Пример использования:
Код
local tableToFile = require[[luaPlugins\tableToFile]] -- объявляется один раз в начале скрипта.
-- Объявляем массив
local arr = {10,9,8,7,6,5,4,3,{21,22,23,"'}\"\t\'",{}},1,0}
-- Сохраняем массив
tableToFile.save("1.txt",arr)
-- Закгружаем массив
arr2=tableToFile.load("1.txt")

Изменения оригинального кода - минимальные. Просто теперь можно спокойно подгрузить одной строкой, а не таскать весь код каждый раз за собой. Ну и store нам save поменял.

Автор: DarkMaster 25.10.2018, 8:54

Предчувствуя следующий вопрос:

Отобразить содержимое таблицы
Код
local function lg(data, comment)
    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: '..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("Elements in table: " .. element_counter)
        else
            log('table is "' .. type(data) .. '" data type. Value: ' .. tostring(data))
        end
        -- Пишем в лог комментарий.
        deep = deep - 1 -- Уровень вложенности вызовов функции.
    end
    
    show(data)
end

Выдернуто куском из кода, там чуть лишнего есть. Использование:
lg(table, "комментарий")
Комментарий можно не писать.

Автор: sutra 25.10.2018, 23:06

Спасибо большое парни! Оба здорово помогли мне. Сделал средний вариант, не так сложно как у Дарка, но с поддержкой двумерных строково-числовых массивов. И на будущее ещё много чего понял. Ещё раз спасибо.

Автор: DarkMaster 26.10.2018, 0:36

Цитата
Сделал средний вариант, не так сложно как у Дарка

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

Автор: sutra 26.10.2018, 12:28

Дарк, а есть такая возможность получить некий результат в виде переменной из скрипта Lua в обычный скрипт? Или только через файл. Замечание я принял, спасибо. Но я всё люблю попробовать сам и понять как это работает, так сказать на всякий случай, в целях самообразования. Просто читаешь иногда посты, там говорят что мол это невозможно, а начинаешь пробовать и всё получается. Вот не помню уж где-то видел, что нельзя анализировать звук, а я анализирую без проблем.

Автор: DarkMaster 26.10.2018, 14:25

Цитата
Дарк, а есть такая возможность получить некий результат в виде переменной из скрипта Lua в обычный скрипт?

Нет. И подозреваю, что даже между запущенными на луа скриптами будет определенная проблема передать данные. Изначально там была глобальная область видимости для глобальных переменных, т.е.
local a = 10 -- видно в пределах вкладки
a = 10 -- видно из любой. Но т.к. это приводило к катастрофам - все было разделено.
Так что только файликами. В луа думаю можно поискать дллки чтобы с ком портами работать, но в стандартном синтаксисе это только плагин писать либо какими-то невероятным костылями со сторонними exe, и может буфером.

Про звук поделиться не хотите?

Автор: WKnight 26.10.2018, 14:35

Цитата
а есть такая возможность получить некий результат в виде переменной из скрипта Lua в обычный скрипт?

Теоретически есть. А смысл?

Автор: sutra 26.10.2018, 15:53

Смысла нет, просто скрипт огромный, хотел частями попробовать, так что проехали.

А про звук ... Ну программер из меня хреновый, а вот придумывать я мастак. Сначала хотел всё делать "по уму", но как я уже сказал, программер из меня... Поэтому сделал просто. Вывожу микшер куда мне надо (засунул на второй монитор в самый низ). А потом всё тем же Файндом просто контролирую шкалу громкости. Как минимум длительность звука и его пиковые пороги контролировать элементарно. Теоретически можно и синусоиду контролировать, тогда нужно чтобы постоянно висела какая-нибудь программулина, но это уж точно изврат.

Файнды - ЭТО СИЛА. Думаю в Lua всё будет "летать" и я никаких проблем и ограничений для себя не вижу. Ещё раз спасибо Кнайту. Несмотряна то, что я нищий, если заведу себе яндекс деньги, то отблагодарю.

С одним монитором в полноэкранном режиме естественно не прокатит. А меня вполне устраивает. А по уму надо как я понимаю плагин прикручивать. Только как вытащить туда звуки системы я не знаю, но теоретически однозначно можно. Микшер то вытаскивает ...

Автор: sutra 26.10.2018, 16:49

В башке "месиво" сплошное от всех этих языков, тяжко продвигается. То set поставлю, то вместо "==" одиночное "=", то then забуду. Залез тут как-то в Делфи, про begin-ы и точки с запятыми забываю, ну там быстро напоминают, ещё до компиляции. Никаких стандартов, каждый норовит своё придумать, ладно хоть Escape у всех одинаково работает, а вот уже с Enter-ом проблемы встречаются. По уму должны перевод строки приклеивать, но это не факт.

Автор: olduo.com 27.10.2018, 0:51

Цитата(sutra @ 26.10.2018, 16:49) *

В башке "месиво" сплошное от всех этих языков, тяжко продвигается. То set поставлю, то вместо "==" одиночное "=", то then забуду. Залез тут как-то в Делфи, про begin-ы и точки с запятыми забываю, ну там быстро напоминают, ещё до компиляции.

проблема в том, что твое месиво в башке ты не знаешь углубленно =)
не забывай ставить ; в луа, это удобно если не знаешь на чем будешь кодить завтра =) из личного опыта)
а так луа это школьный язык, его там нужно вместо паскаля и бесика преподавать)

Автор: DarkMaster 27.10.2018, 1:59

Цитата
а так луа это школьный язык, его там нужно вместо паскаля и бесика преподавать)

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

Автор: Cockney 27.10.2018, 12:44

Цитата
считаю использование классов нежеланием переучиваться плюсовиков.


Да вот только сам по себе луа пустой. Его сфера применение - встраивание. И как бы если луа может реализовывать классы, то не факт что те же плюсы смогут реализовать фичи луа (имеется ввиду из коробки). Да и к тому же, есть устоя́вшиеся нормы и правила написания софта. Класс - удобно, красиво, хоть иногда и громоздко. А луа сегодня есть, завтра нет...отсюда как бы еще и вытекает вопрос а зачем собственно и переучиваться на луа и вникать в него, если он не востребован практически нигде(по сравнению с питоном, js и другими) ?

Автор: DarkMaster 27.10.2018, 14:00

Цитата
Да вот только сам по себе луа пустой.

Классы этого никак не меняют.
Цитата
Его сфера применение - встраивание.

И справляется на самом деле очень неплохо. Тем не менее есть те же сокеты, биндинги под wxWidgets и Qt. Т.е. на нем пишут. Его распространненость скорее следствие работы не шибко большой группы и отсутствия макетинга. Это не Google который штампует языки и на них _будут_ писать вне зависимости от качества продукта.
Цитата
Класс - удобно, красиво, хоть иногда и громоздко.

Тут холивар может быть очень большим. Я не сторнник ооп. Да, оно бывает в определенных ситуациях нужно, но количество этих ситуаций и количество "написал на классах потому, что модно и современно" я не считал. Для меня очень неожиданно было, когда случайно наткнутся на статистику кода в линях: кода на чистом си оказалось в 2.5 раза больше, чем на плюсах. Заставило задуматься на самом деле.
Цитата
А луа сегодня есть, завтра нет...отсюда как бы еще и вытекает вопрос а зачем собственно и переучиваться на луа и вникать в него, если он не востребован практически нигде(по сравнению с питоном, js и другими) ?

У него есть своя ниша в которую он плотно засел - геймдев. Сейчас по сути он там стандарт. Тот же wow по части аддонов полностью на нем написан (это просто дикий объем кода - их сотни тысяч), GTA вся логика на lua описывается. Причем если вов был изначально такой, то переход на lua такой большой корпорации, как Rockstar не мог не быть тщательно взвешан. Так же в обработке траффика его частенько используют - nginx, wireshark. Это маркеры. Серьезные проекты и встаривание в них было вполне успешным. Да, язык не топ популярности, но ниша занята, его там никто не теснит, а нужное он делает на 5.
Зачем переучиваться? Ну я, например, знаю одну студию разработки в которой плюсовики нафигачили кода с классами и кучей переназначений в метатаблицах. Т.е. использовали возможности языка на все 100%. Вот только когда приходишь со своим самоваром в другой язык, то не очень хорошо получается в плане результа. Потом команда сильно разосралась, т.к. натуральным луашникам этот изврат не очень нравился, а плюсовикам было все пофигу и пальцы веером. В итоге выкинули всех за не совсем адекватность, уже год ищут луашников именно для переписывания всей этой крутоты на классах. Обрывки кода видел лично - искать где, что править в 10 раз переназначенных метаблицах полный бред. Это нужно делать либо тому человеку, который это писал, либо сидеть с маном в котором вся структура чуда. Луа не святой, есть свои огрехи, си я уважаю больше, асм еще больше, но у всего есть ниша и причины почему ни один язык не стал универсальным и доминирующим везде. Это я все к чему - со своим самоваром не стоит =)

Автор: Cockney 27.10.2018, 14:48

Цитата(DarkMaster @ 27.10.2018, 14:00) *

Классы этого никак не меняют.

И справляется на самом деле очень неплохо. Тем не менее есть те же сокеты, биндинги под wxWidgets и Qt. Т.е. на нем пишут. Его распространненость скорее следствие работы не шибко большой группы и отсутствия макетинга. Это не Google который штампует языки и на них _будут_ писать вне зависимости от качества продукта.


Как бы меняют, ведь qt и виджеты являются ооп (или нет ?). Если бы не поддержка ооп из коробки, он бы загнулся в самом начале.

Цитата

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


это про линуксы ? Статистика чего ? Ядра ? Ну тогда не удивительно, что там си больше. printf быстрее потоков раза в 3 если не больше. А попробуй вывести через него сложную структуру, класс. Неудобно, не так ли ?

Цитата

У него есть своя ниша в которую он плотно засел - геймдев. Сейчас по сути он там стандарт. Тот же wow по части аддонов полностью на нем написан (это просто дикий объем кода - их сотни тысяч), GTA вся логика на lua описывается. Причем если вов был изначально такой, то переход на lua такой большой корпорации, как Rockstar не мог не быть тщательно взвешан. Так же в обработке траффика его частенько используют - nginx, wireshark. Это маркеры. Серьезные проекты и встаривание в них было вполне успешным. Да, язык не топ популярности, но ниша занята, его там никто не теснит, а нужное он делает на 5.


Да никто и не спорит с этим. Только вот учить его чтобы попасть на одну из 2 вакансий в Москве (hh.ru), когда есть unity c# 360+ вакансий.....Это если говорить о реальной его пользе, а не уровне пилота. Конечно, на нем пишут, только где....

Цитата

Зачем переучиваться? Ну я, например, знаю одну студию разработки в которой плюсовики нафигачили кода с классами и кучей переназначений в метатаблицах. Т.е. использовали возможности языка на все 100%. Вот только когда приходишь со своим самоваром в другой язык, то не очень хорошо получается в плане результа. Потом команда сильно разосралась, т.к. натуральным луашникам этот изврат не очень нравился, а плюсовикам было все пофигу и пальцы веером. В итоге выкинули всех за не совсем адекватность, уже год ищут луашников именно для переписывания всей этой крутоты на классах. Обрывки кода видел лично - искать где, что править в 10 раз переназначенных метаблицах полный бред. Это нужно делать либо тому человеку, который это писал, либо сидеть с маном в котором вся структура чуда. Луа не святой, есть свои огрехи, си я уважаю больше, асм еще больше, но у всего есть ниша и причины почему ни один язык не стал универсальным и доминирующим везде. Это я все к чему - со своим самоваром не стоит =)


Не стоит. А еще не стоит ставить человека на луа проект, который знает только c++.

Ради интереса зашел на одну из вакансий по луа:

Цитата
Для этого необходимо:

Опыт разработки на C#/C++
Опыт разработки на Android платформе: SDK, NDK
Английский язык - технический
Умение работать в команде
Желание работать в игровой индустрии
Желание и способность учиться
Необходимо знание языка LUA



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

Автор: sutra 27.10.2018, 16:09

Во какую тему замутил. А я вот со своим дилетантским взглядом считаю так, что если мне нужно вбить колышек, я беру кувалду, пару раз стукну и всё, а не вызываю машину для забивки свай. 99% пользователей Пилота "забивают колышки". Здесь не игрушки пишут и не рассчитывают турбулентность. Поэтому овчинка должна стоить выделки. Зачем мне тратить уйму времени и забивать голову ненужной информацией если нужно выполнить примитивнейшие действия. Лично для меня язык Пилота был абсолютно понятен сразу на 100%. И я быстро разберусь с любым скриптом, если будут адекватные имена переменных. С Lua намного сложней, там уже нужно частенько вникать подробно и с ходу в чужом коде можно мозги вывихнуть. Для меня Пилот, просто полезный и лёгкий в освоении инструмент. И меня практически всё в нём устраивает, но возникло пару моментов, где не хватает быстродействия, вот и решил перейти на Lua , но придётся потратить немало времени.

Автор: DarkMaster 27.10.2018, 17:08

Цитата
Как бы меняют, ведь qt и виджеты являются ооп (или нет ?).

Насколько я понял там вообще пофигу ибо линкуется там все через очередь и пушится каждый параметр. Что есть дикий минус ибо дллки нужно обертывать весьма своеобразно и спокойно ту же сишную либу не подключишь. Так что едва ли =)
Цитата
И вот риторический вопрос, а зачем знание плюсов, да еще и тем более шарпов (где все классы) луашнику ? Сам по себе луа самодостаточен. Модули, метатаблицы - все что хочешь. Никак работодатель желает биндить классы (ведь для этого нужен опыт шарпа ?) через луа

Ну собственно ответ выше. Да и как бы начали с того, что это встраиваемый язык. Встраивать то его тоже надо =) А вот что там классы или не классы суть не важно.
Цитата
Лично для меня язык Пилота был абсолютно понятен сразу на 100%.

И да и нет. Честно? Разницы по сложности - ноль. Самого языка. Вот когда на грабли вставать будете - поймете, что луа намного проще) Разница в том, что луа в рамках пилота не настолько интегрирован. Те же записи/чтения файла. Не так много людей идут на луа (очень зря кстати), а те кто идут зачастую не считают проблемой самим написать такие вещи. Это недоработки интеграции. Пилот 20 лет почти вылизывался, луа - год. Ну и примеров совсем другое количество. Cirus вон какую сказку с допиливанием вики сделал. Для луа этого просто нет. Мне - это не нужно, я и так сориентируюсь по старым примерам, а человеку который только вникает и не имеет опыта программирования - это сложно. Грубо говоря не обжитой он просто.

Автор: olduo.com 27.10.2018, 18:17

Цитата(Cockney @ 27.10.2018, 14:48) *

Ради интереса зашел на одну из вакансий по луа:
Цитата
Для этого необходимо:

Опыт разработки на C#/C++
Опыт разработки на Android платформе: SDK, NDK
Английский язык - технический
Умение работать в команде
Желание работать в игровой индустрии
Желание и способность учиться
Необходимо знание языка LUA

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

хороший пример, именно потому что из игровой индустрии. большинство серверов с которыми работал в качестве скриптового движка используют луа, но не всегда все его возможности. обычно это просто серверный хук, который вызывает обработку в скрипте. потом ты уверен, что это вакансия луашника? ну т.е. если это серверный программист, то тебе нужно и "Опыт разработки на C#/C++" и "Необходимо знание языка LUA". если это луашник, то согласен, опыт в остальном второстепенен. я както тут писал про пацаньчика, которого взял на серверный луа.

Автор: sutra 27.10.2018, 18:24

Я попробовал и даже простейшую функцию не смог сделать в Lua. Что-то не так с видимостью. А что не так пока не понимаю.

Автор: cirus 27.10.2018, 18:31

Цитата
Я попробовал и даже простейшую функцию не смог сделать в Lua.

Выкладывайте код, поправим.
Для примера:
Код
--lua
-- функция должна находится выше её вызова
function f(x, y)   -- принимает 2 параметра
    return x+y     -- возвращает сумму
end

local z=f(5, 6)    -- вызов функции
log (z)


Автор: sutra 27.10.2018, 19:53

Не смог реализовать goto как только не пробовал, даёт ошибку.

Такая и у меня работает. Мне нужно передать в неё переменную, там с ней выполняются действия и мне нужна модифицированная ПЕРЕМЕННАЯ. А точнее таблица.

То есть я должен передать в функцию таблицу.

Хотя и с обычной переменной ничего не получилось.

Надо типа такого, чего не работает.

--lua
function proba(a)
return a = 12
end
log "clear"
local zz = 5
local tt = proba(zz)
log(tt)

если без return то в основном теле будет nil

Автор: cirus 27.10.2018, 19:53

Цитата
Не смог реализовать goto

Лучше сразу забудьте про него.
Код
--lua
function proba(a)
    a = 12
    return a
end

log "clear"
local zz = 5
local tt = proba(zz)
log(tt)

Код
--lua
log "clear"  log "mode compact"
function f(arr2)
    for i=1, #arr2 do
        arr2[i]=arr2[i]*2     -- умножить все элементы на 2
    end
end

local arr={}
for i=1, 10 do     -- заполнить массив числами от 1 до 10
    arr[i]=i
end

log (table.concat(arr, " "))     -- содержимое массива
f(arr)    -- вызов функции
log (table.concat(arr, " "))     -- содержимое массива после вызова функции

Автор: sutra 27.10.2018, 20:01

Спасибо. То есть goto не работает??

Автор: cirus 27.10.2018, 20:04

Цитата
То есть goto не работает??

Нет. Он и не нужен.
В луа его вообще нет. Вроде как есть в луа 5.3.

Автор: sutra 27.10.2018, 20:16

Меня конечно учили в своё время, что goto использовать является минимум признаком дурного стиля, но иногда это сильно упрощает код.

Всё верно, именно Lua 3 я и смотрел.

Буду думать, если не смогу модифицировать скрипт без goto придётся отказаться от Lua.

Да, конечно можно без goto , но придётся городить огород с кучей while-ов код будет ужасно плохо читаемым. У меня goto использовался например для рестарта скрипта в случае отключения интернета, ну и ещё в 2-х критических случаях, придётся всё заключать в циклы и брейками прерывать скрипт.

Автор: DarkMaster 28.10.2018, 2:11

Цитата
Да, конечно можно без goto , но придётся городить огород с кучей while-ов код будет ужасно плохо читаемым. У меня goto использовался например для рестарта скрипта в случае отключения интернета, ну и ещё в 2-х критических случаях, придётся всё заключать в циклы и брейками прерывать скрипт.

Как правило подобные проблемы говорят о том, что изначально структура кода не очень хорошо продумана.
Цитата
Всё верно, именно Lua 3 я и смотрел.

У нас luajit - стабильный релиз которого соответсвует версии 5.1. Это форк с динамической компиляцией, который существенно шустрее в работе. Сейчас он, пожалуй, более распространен, чем оригинальный луа. Можно смело исользовать мануалы от 5.1.

Автор: sutra 29.10.2018, 0:00

А оператор continue в цикле while есть?

Автор: cirus 29.10.2018, 0:18

В луа нет continue.

Автор: sutra 29.10.2018, 1:28

Это очень нехорошо. Если честно, то я не понимаю. С одной стороны типа прогрессивная вещь, а с другой стороны вроде очевидных вещей нет. Придётся буквально весь код запихивать в функции, которые будут содержать куски кода без особой логики. Видимо придётся их так и называть blok01 .. blok77. А основное тело будет состоять из вызова этих кусков. Просто в моём случае десятки раз вызывается функция обработки ошибок и обработки возникших неадекватных ситуаций. Собственно там и были goto которые перенаправляли код на повторные действия. Так что придётся работать брейками и кусками с ретурнами.

Автор: DarkMaster 29.10.2018, 4:29

Код
while var > 1 do
    local result = check_some_params()
    if result then
        some_actions()
    end
end

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

Он там и должен быть. Весь. Не в функциях у тебя может быть какая-то инициализация (подгрузка параметров из файла настроек, например, или массивов). Кроме этого у меня не в функции вот такая строчка:
main()
Т.е. вызов основной функции. Больше там ничего и не должно быть.
Цитата
Видимо придётся их так и называть blok01 .. blok77

А вот так делать не надо. Уверяю можно найти нормальное решение. smile.gif

Цитата
В луа нет continue.

5.3, но, в классическом 5.1 нет, ну и в luajit релизе тоже нет.

Автор: sutra 29.10.2018, 12:55

Спасибо Дарк. Но у меня так не получится. Допустим у меня проверка в 4-ом колене ветвления if . После проверки происходит дальнейшее выполнение кода в этом же ИФе. То есть проверить и по результатам что-то выполнить - это не требуется, а наоборот в обязательном порядке прекратить выполнение кода (ну глупо что-то выполнять если отключили интернет или сервер недоступен) и в данном примере идти почти в самое начало скрипта и крутить цикл пока не появится связь с сервером. Поэтому выход вижу только один всё пихать в функции. После проверки выполнять return из функции, а вот весь остальной код придётся запихивать в if. И таких ифов до конца всего кода будет ну с десяток точно.

Автор: sutra 29.10.2018, 13:15

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

По логике у тебя тоже всё правильно. Собственно так примерно и будет, только эти вайлы будут как снежный ком. И формат уедет настолько сильно вправо, что код будет плохо читаемым. Буду как-то сочетать. Что-то сделаю локальным распихав по функциям, что-то придётся умещать в одном блоке кода.

Автор: sutra 29.10.2018, 13:25

Грубо говоря есть определённое количество событий, которые могут вызываться один из другого. И простыми вызовами функций я могу получить неконтролируемую рекурсию. Поэтому в Пилотовском коде я и использовал goto. Тут придётся крепко репу почесать, чтобы было красиво и эффективно.

Автор: sutra 29.10.2018, 14:41

local n = "123.txt"
local f = io.open(n, "r")

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

Автор: DarkMaster 29.10.2018, 14:44

Цитата
Не смог открыть файл при помощи переменной

А лежит он где? Рядом с ехе пилота? Пилот перезапускали?

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

Автор: sutra 29.10.2018, 15:04

Обычным текстом открывает [[123.txt]]

Минутку, теперь и обычным не открывает, сейчас гляну.

Доигрался, вообще Пилот завис.

Автор: cirus 29.10.2018, 15:09

Цитата
вообще Пилот завис.

Скорее всего были какие-то ошибки.
Код
--lua
local n = "123.txt"   -- файл лежит рядом с exe пилота
local f = io.open(n, "r")

log "clear" log "mode compact"
if f then   -- если файл открылся
    log(f:read())  -- первая строка из файла
else
    log ("Файл не открылся")
end

Автор: sutra 29.10.2018, 15:17

Перегрузил Пилот через прибивалку, всё заработало, спасибо Дарк.

Видимо крепко я накуралесил, да ещё и игра играет в параллельном скрипте.

И тебе cirus тоже спасибо.


Теперь буду знать, что иногда надо пнуть ногой по баллону.

Автор: sutra 29.10.2018, 15:40

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

Автор: DarkMaster 29.10.2018, 18:00

Цитата
Понял причину, забыл поставить двойной слеш при указании полного пути.

Не редактируйте код перед тем, как выложить. Ну либо тестируйте перед тем, как выкладывать =)
Чтобы не писать двойные слэши просто ставьте вместо кавычек [[текст]]

Автор: sutra 29.10.2018, 18:21

Я не редактировал. Просто сначала использовал полный путь. Потом пути были без слешей и не работало только с переменной, потом вообще не работало, причину Вы мне подсказали (перегрузить).

Я понял почему изначально не работало.

Автор: DarkMaster 30.10.2018, 5:31

Цитата
причину Вы мне подсказали (перегрузить).

это фиксанули буквально пару дней назад

Автор: sutra 31.10.2018, 13:03

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

Автор: sutra 31.10.2018, 13:14

И конечно примеры на lua "надёжно" зарыты. Через спецстраницы, через страницы-сироты. Но и там есть далеко не всё, а если бы было, то дилетанты типа меня не донимали бы элементарными вопросами.

Автор: cirus 31.10.2018, 13:29

Цитата
реальный пример findimage

Код
--lua
local a, c = findimage(0, 0, 1920, 1080, {[[C:\Users\abc\Desktop\image.bmp]]}, 2)
-- a - это массив, c - количество картинок или точность поиска, если картинка одна
if a then
    move(a[1][1], a[1][2])
end

Цитата
findcolor

Вроде как не доделан. Поэтому костыль. Передавать все параметры в виде строки.
Код
--lua
local a = findcolor("0, 0, 1920, 1080, 1, 1, 7223552, 2")
hint (a)

Цитата
примеры на lua "надёжно" зарыты

http://uopilot.tati.pro/index.php?title=Список_функций_(Lua)
Только то, что работает в 2.40 (релиз, а не бета).


Автор: sutra 31.10.2018, 13:35

Спасибо.

Цитата
Только то, что работает в 2.40 (релиз, а не бета).

Так я и говорю надёжно спрятано. Я случайно туда попал. Надо бы прямую ссылочку сделать.

Автор: cirus 31.10.2018, 13:50

Цитата
Надо бы прямую ссылочку сделать.

Когда выйдет полноценная версия пилота на луа, тогда и будет дописана (где-то исправлена) справка и дана ссылка.

Автор: sutra 31.10.2018, 14:01

--lua
log "clear" log "mode compact"
addressl, widthl, heightl, lengthl = loadimage ([[C:\TMP\Original.bmp]])
log(widthl, heightl, lengthl)
addressg, widthg, heightg, lengthg = getimage (470, 924, 500, 933)
log(widthg, heightg, lengthg)
local a, c = FindImage(0, 0, 1920, 1080, addressl, addressg, 100)
deleteimage (addressl)
deleteimage (addressg)

Не работает, дает ошибку.

Сорри, забыл на строчные переделать. Спасибо.

Автор: cirus 31.10.2018, 14:10

Да, в findimage есть баг, если искать на скрине от координат 0 0, то нормально ищет. Иначе не находит.

Автор: sutra 31.10.2018, 14:17

--lua
log "clear" log "mode compact"
addressl, widthl, heightl, lengthl = loadimage ([[C:\TMP\Original.bmp]])
log(widthl, heightl, lengthl)
addressg, widthg, heightg, lengthg = getimage (470, 924, 470, 933)
log(widthg, heightg, lengthg)
local a, c = findimage(0, 0, 1920, 1080, {addressl, addressg})
if a then
move(a[1][1], a[1][2])
end
log(a, c) -- результат LuaTable 100 Примерно так. При ширине захвата 1 пиксель
deleteimage (addressl)
deleteimage (addressg)

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

Автор: cirus 31.10.2018, 14:23

Код
--lua
log "clear" log "mode compact"
addressl = loadimage ([[C:\TMP\Original.bmp]])
addressg = getimage (0, 0, 1920, 1080)

local a, c = findimage(0, 0, 1920, 1080, {addressl}, addressg)
if a then
    move(a[1][1], a[1][2])
end
log(a, c)
deleteimage (addressl)
deleteimage (addressg)


Автор: sutra 31.10.2018, 14:43

Спасибо разобрался. Ну в общем тот баг и в lua проявляется точно так же. Результат один в один.

Цитата
Иначе не находит

Да в том то и фишка, что находит, только нужно большее пространство захвата по ширине. Видимо блок координат анализа зависит от ширины картинки оригинала.

Не зря же результат начинает падать (уменьшаться от 100%) при уменьшении зоны захвата (если не задавать параметр поиска 100%, а скажем оставить поумолчанию 80%).

А как чё-нить положить в клипбоард в lua ?
Как я понимаю это потом можно забрать в пилотовском коде.

Автор: cirus 31.10.2018, 14:57

Цитата
А как чё-нить положить в клипбоард в lua ?
Как я понимаю это потом можно забрать в пилотовском коде.

Код
--lua
log "clear" log "mode compact"
clipboard ("проверка связи")   -- записать в буфер обмена фразу
wait (300)                     -- пауза 300 мсек
local text = clipboard ()      -- получить из буфера обмена текст в переменную text
log (text)                     -- отобразить в логе значение переменной text
--endlua

get clipboard $a               // получили из буфера обмена текст
log $a
end_script


Автор: sutra 31.10.2018, 15:12

Спасибо.

Автор: DarkMaster 31.10.2018, 19:04

Цитата
Ну в общем тот баг и в lua проявляется точно так же. Результат один в один.

Суть в том, что само тело пилотовских функций одинаковое. Там просто чуть-чуть иной формат забра данных и их возврата. Основое отличие в типах данных, которых пользователь и не видит.

Автор: sutra 1.11.2018, 12:54

Цитата
local a = findcolor("0, 0, 1920, 1080, 1, 1, 7223552, 2")

А получить массив найденных пикселей, где хранятся их координаты и цвет получается что нельзя?

Автор: cirus 1.11.2018, 13:09

Код
--lua
local a = findcolor("0, 0, 1920, 1080, 1, 1, 6106880, %arr, 2")
if arr then
    move (arr[1][1], arr[1][2])
end

Автор: sutra 1.11.2018, 13:26

Спасибо.

А какой самый простой способ в lua убить массив?

Типа повторно инициализировать?
local arr {}

Вот я тугодум, понял. Просто arr={}

Автор: DarkMaster 1.11.2018, 13:44

Цитата
А какой самый простой способ в lua убить массив?

arr = nil
Цитата
Вот я тугодум, понял. Просто arr={}

вы не убили массив. Вы создали новый пустой.

Автор: WKnight 1.11.2018, 13:51

Цитата
local a = findcolor("0, 0, 1920, 1080, 1, 1, 7223552, 2")
Плин, вот так скажешь ваське ченить полезное, и потом с полной уверенностью считаешь, что все это знают...

arr, err = findimage(10, 20, 1020, 810, {"C:\\tmp\\image.bmp"}, 2)
arr, err = findcolor(10, 20, 1040, 810, {"r(255)"}, 2, -1, "abs")
только цвета задаются строкой и в старом формате, но обязательно в фигурных скобках, т.е. в таблице луа.

Автор: sutra 1.11.2018, 14:20

Спасибо. Вывод... лучше спросить, коли с мозгами туго.

Автор: sutra 4.11.2018, 18:46

Всем огромное спасибо, кто потратил своё время на моё обучение. Не стал дожидаться доводки до ума файндов и соорудил временную конструкцию, но даже она дала отличный результат. Переделал блок распознавания чисел в тексте.
Хочу просто поделиться результатами:
set timer3
set #tmp findcolor (688 639 825 639 1 1 (R(0-255)) %tmp)
set %tmp[139 1] #HandleWorkWindow
save_array %tmp "a:\_find.txt" // запись на RAM диск для считывания в lua
set timer4
start_script 8 wait // скрипт на lua
set #time1 timer3 // время выполнения 36-49 тыс. секунды (раньше было 360-800 тыс.)
set #time2 timer4 // время выполнения 16-26 тыс. секунды

Раньше время варьировалось в зависимости от количества распознаваемых цифр (требовалось около 0,1 сек. на цифру). Сейчас всё мгновенно, время выполнения - чистый рэндом и не зависит от количества распознаваемых символов. Грубо говоря старт и выполнение скрипта на lua требует не более 25 тысячных секунды.

Автор: sutra 8.11.2018, 12:01

--lua
check=5
checkint=0
for i=1, 10 do
for j=1, 10 do
if j > check then
checkint = 1
break
end
end
if checkint == 1 then
break
end
end

Поправьте меня если я опять чего-то напутал. Другого варианта прерывания циклов нет? Уровень прерывания всегда равен 1? break 2 - недопустимая конструкция?

Автор: cirus 8.11.2018, 12:36

Цитата
Другого варианта прерывания циклов нет?

Нет.

Автор: DarkMaster 8.11.2018, 17:34

Не забывайте области видимости - пишите local при объявлении переменных.

Автор: sutra 9.11.2018, 1:59

Цитата
Не забывайте области видимости

Спасибо, я не забываю. На примерах просто лень, учту, буду локальными объявлять, хотя вроде говорили, что только текущий скрипт видит.
Кстати, тестанул свой обработчик памяти, на 170 строках, при анализе вертикальной зоны, получились те же 3 сотых, то есть никакого реального ускорения нет, время как у повторного вызова функции обработки изображений. Если по вертикали немного пикселей, то всё супер. Ну может Кнайт доделает финды.

Автор: WKnight 9.11.2018, 2:07

Цитата
доделает финды
А напомните, что именно имеется ввиду. Я как раз разломал финдимидж, думал переписать, но похоже это надолго, чето он не хочет переписываться.

Автор: sutra 9.11.2018, 2:12

Так Cirus показывал на примере моей картинки в теме по Пилоту.

На 10-й страничке.

А колор в памяти путает координаты поиска, я тоже там говорил.

Автор: cirus 9.11.2018, 2:19

Цитата
А напомните, что именно имеется ввиду.

https://forum.uokit.com/index.php?s=&showtopic=68521&view=findpost&p=428122

Автор: DarkMaster 9.11.2018, 10:07

Цитата
Спасибо, я не забываю. На примерах просто лень, учту, буду локальными объявлять, хотя вроде говорили, что только текущий скрипт видит.

1) Глобальные переменные медленные.
2) В луа ограничение на 63 upvalue, что может потом привести к внезапоному рефакторингу.
3) Учитывая, что в луа все находится в таблице, то подозреваю, что добавление в верхний уровень таблицы ключей может замедлить работу скрипта в целом, если они добавлены не в хвост.

Автор: WKnight 9.11.2018, 12:48

Цитата
Так Cirus показывал
А, я думал может еще чего интересного нашли smile.gif

Автор: DarkMaster 9.11.2018, 13:02

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

Автор: sutra 9.11.2018, 16:59

Цитата
А, я думал может еще чего интересного нашли

Кнайт, мне нравится подход, ЕЩЁ ... Я считаю, что хвататет глюков.
Ты про findcolor не забывай, на мой взгляд он поважнее будет имиджа. Буду повторяться.

ГЛЮК № 1 !! Даже скажу где искать. При поиске в памяти колор путает ОРДИНАТУ поиска.
Тестовая картинка проста до безобразия, 20 строк чёрного цвета (0), далее 60 белого (16777215), потом изображение.

set %pic GetImage (0 0 500 500)
set #err findcolor (100 420 100 420 1 1 (0-16777215) %arr %pic[1 1])
save_array %arr "C:\TMP\_memory.txt" // результат 100 0 0
set $b deleteimage(%pic[1 1])
end_script

То есть, потерял ординату, цвет получили из нулевой ординаты
Меняем область, смещая вниз на 30 пикселей.

set %pic GetImage (0 30 500 500)

Результат массива 100 0 16777215 , т.е. опять потерял ординату и вернул цвет из нулевой ординаты.


ГЛЮК № 2 !! Это в lua. Тестовая картинка та же.

--lua
log "clear"
local arr, err = findcolor(100, 0, 199, 39, "(0)", 2)
log(arr, err) -- результат nil 2000
--endlua

Хотя бы ищет верно 100*20=2000

--lua
log "clear"
local arr, err = findcolor(100, 0, 199, 39, "{r(0)}", 2)
log(arr, err) -- результат nil 0
--endlua

При использовании RGB совсем не ищет. А также НЕ ВОЗВРАЩАЕТ массив.


Автор: WKnight 9.11.2018, 18:28

Цитата
область берется больше,
Чет не помню такого.

Автор: DarkMaster 9.11.2018, 18:36

В приват ща опишу. А то "секретные технологии" палить не хочу)

Автор: Cockney 10.11.2018, 0:05

Цитата

Ну собственно ответ выше. Да и как бы начали с того, что это встраиваемый язык. Встраивать то его тоже надо =) А вот что там классы или не классы суть не важно.


Начали мы как раз с того, что луа живет за счет общепринятых фич, а не собственных. И удобство его как языка ничем не выделяется среди других встраиваемых.

Автор: sutra 10.11.2018, 1:16

Блин, секретные технологии. Ну у меня тоже есть такие. Конечно не так универсально, но у меня работает как часы собственный findimage. Конструкция Exec ... пока работает внешняя программа, Пилот не успевает добраться до результатов её работы, потому что конструкция ExecAndWait выполняется всего 2 сотых секунды. Ищется картинка размером 500х26 среди почти 900 файлов эталонов. Результат пишется в файл сценария который может менять ход игры.

Автор: sutra 10.11.2018, 1:39

Фишка в том, что анализируются не изображения, а файлы. Картинки в формате jpg с качеством 90% (чтобы был больше разброс по размеру файлов). Считывание имён и размеров без открытия самих файлов происходит практически мгновенно. Одинаковых по размеру не так много, вот только они и сравниваются, если отличаются, то обычно сразу же на первых байтах. Главный секрет как сделать так, чтобы картинки не "плавали от рендеринга" и всегда получались идентичными. Но это отдельная тема.

Автор: sutra 10.11.2018, 2:13

Думаю всё это легко можно сделать в lua , но мне просто лень переделывать и так всё чудно работает.

Надо было конечно вообще сделать 100% качество jpg, тогда думаю вообще одинаковых бы не встречалось, но опять же лень по новой коллекцию эталонов делать, скорости хватает.

Ха, в lua. Я не знаю как там получить список файлов.

Стыдно признаться, но всё это сделал на убогом 32-х разрядном делфи образца 1999 года. Не думал, что придётся программировать спустя столько лет. Си выучить не получилось, в 90-е было не до этого, надо было семью кормить.

Автор: cirus 10.11.2018, 2:29

Цитата
не знаю как там получить список файлов

Код
--lua
log "clear"  log "mode compact"
resultarray, count = dir ([[C:\Windows]], "*.exe", "norecursion")
log ("Найдено файлов: " .. count)
if count > 0 then
    for i=1, count do
        log(resultarray[i][1])
    end
end

Автор: DarkMaster 10.11.2018, 13:07

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

Автор: sutra 10.11.2018, 14:51

Цитата
resultarray, count = dir ([[C:\Windows]], "*.exe", "norecursion")

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


Спасибо за совет, надо конечно эксперементировать.

Цитата
забыть про jpg

Дарк, так я для себя сделал, файлов эталонов будет наверное около 1500 штук, но это не скажется на быстродействии, в любом случае мой метод намного быстрее и практичнее. Я его делал, когда не было поиска в памяти, но думаю и поиск в памяти будет медленнее и НАМНОГО.


Хотя вариант с dir сопоставим по скорости, сравнение и циклы в lua тоже без тормозов. Спасибо Cirus. Но lua тоже не было раньше, а переделывать мне лень.

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

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

Автор: sutra 10.11.2018, 15:08

Цитата
resultarray, count = dir ([[C:\Windows]], "*.exe", "norecursion")

Сорри, не доглядел, действительно, я не знал синтаксиса этой команды. Ещё раз спасибо.

Автор: DarkMaster 10.11.2018, 15:29

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

Автор: sutra 10.11.2018, 15:44

Так в том то и фишка, что колор в памяти только-только начал свой путь в большую жизнь. Колором я бы ещё мог ускорить распознавание. Вызов printscreen и getimage по скорости абсолютно одинаков (у меня 27 тысячных), а обработка колором (в теории) быстрее тех 2-х сотых, которые кушает моя программа.

Конечно я имею ввиду lua, а его я начал осваивать без году неделя.

Автор: cirus 10.11.2018, 16:25

Код
--lua
-- сделать привязку Ctrl+A
local h = workwindow()
local t, addr=os.clock()
for i=1, 100 do  -- для теста 100 скринов
    addr = getimage (0, 0, 500, 500)
end
log(os.clock()-t)

t=os.clock()
for i=1, 100 do  -- для теста 100 скринов
    addr = getimage (0, 0, 500, 500, h)    -- так быстрее чем вызов без указания хендла
end
log(os.clock()-t)

Разница по времени зависит от приложения.

Автор: sutra 10.11.2018, 16:52

Цитата
так быстрее чем вызов без указания хендла

Спасибо большое. Век живи и век учись. Я просто плохо пока понимаю принципы работы, но потихоньку учусь.


А где ещё можно указывать хендл? В каких операторах?

Автор: cirus 10.11.2018, 17:07

Цитата
А где ещё можно указывать хендл?

Color, findimage, findcolor, getimage, move, left, readmem, writemem.

Автор: sutra 10.11.2018, 17:30

ОК.

Автор: sutra 12.11.2018, 16:22

Теперь про борьбу с рендерингом. Может кому пригодится. Даже используя стандартный Пилотовский findimage соблюдая два нехитрых правила результат поиска становится стабильнее и точнее.
1) На рендеринг (прорисовку) любой картинки влияют соседние с ней ИЗМЕНЯЮЩИЕСЯ объекты. Поэтому захват нужной картинки надо производить по возможности дальше от таких объектов.
Например, есть текст, который надо захватить для сравнения с неким оригиналом, и над этим текстом вверху постоянно меняющееся изображение каких-либо объектов.
Предположим, что высота символов 12 пикселей. Осуществляйте захват не по всей высоте текста, а сместите верхнюю границу зону захвата на 2-3 (а возможно и больше) пикселя ниже.
Грубо говоря скрин будет размером не 40х12, а скажем 40х10. Картинка конечно смотрится неприглядно, но идентифицировать её будет проще, так как подверженные влиянию верхние пиксели мы отбросим, кстати границы объектов всегда наиболее подвержены рендерингу.
2) Сильно может влиять положение рабочего окна, поэтому лучше чтобы рабочее окно всегда находилось на "своём привычном месте", я его устанавливаю при помощи set windowpos ...

Мне на 100% избежать влияния рендеринга удаётся не всегда, но в таких случаях у меня есть 2-3 (ничто не мешает сделать и больше) эталонных файла картинки. Имена файлов эталонов содержат номер события, поэтому все они легко распознаются в соответствии с событием (0001.jpg; 0002-a.jpg; 0002-b.jpg; и т.д.). Размеры файлов варьируются очень сильно, поэтому в подавляющем большинстве случаев, опознание производится по размеру файлов не прибегая к открытию файлов и их сравнению.

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

Автор: sutra 12.11.2018, 18:38

Конечно если картинки очень сложные, то спасёт только deviation Пилотовского имиджа, тут без вариантов. Ну или надо напрячь серое вещество и работать колором.

Автор: sutra 12.11.2018, 23:31

Код
function FindRGB(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf,h)
  -- addr,len : адрес в памяти и длина строки в памяти (то, что даёт getimage)
  -- scrX1,scrY1 : координаты скрина, аналогичны координатам getimage (конечные X и Y не требуются)
  -- fx1,fy1,fx2,fy2 : координаты поиска, абсолютные относительно рабочего окна (мне так удобнее). Должны быть внутри диапазона скрина.
  -- usl : условие поиска "R(10-255) G(70-100) B(50) R-G[50 200] R-B[-40 -20] G-B[15]"
  -- условие ОДНО, по принципу ужесточения параметров поиска. R-G - разность между каналами с возможностью интервала
  -- G-B[15] идентично G-B[15 255]
  -- никакой проверки лексики естественно нет
  -- numf : количество искомых пикселей
  -- h : хендл пилота
  local _,_,r1,r2 = usl:find("R%((%d+)%-*(%d*)")
  local _,_,g1,g2 = usl:find("G%((%d+)%-*(%d*)")
  local _,_,b1,b2 = usl:find("B%((%d+)%-*(%d*)")
  local _,_,RG1,RG2 = usl:find("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local _,_,RB1,RB2 = usl:find("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local _,_,GB1,GB2 = usl:find("G%-B%[(%-*%d+)%s*(%-*%d*)")
  r1=tonumber(r1)  r2=tonumber(r2)
  g1=tonumber(g1)  g2=tonumber(g2)
  b1=tonumber(b1)  b2=tonumber(b2)
  RG1=tonumber(RG1)  RG2=tonumber(RG2)
  RB1=tonumber(RB1)  RB2=tonumber(RB2)
  GB1=tonumber(GB1)  GB2=tonumber(GB2)
  if r1==nil then  r1,r2=0,255  else  if r2==nil then  r2=r1  end  end
  if g1==nil then  g1,g2=0,255  else  if g2==nil then  g2=g1  end  end
  if b1==nil then  b1,b2=0,255  else  if b2==nil then  b2=b1  end  end
  if RG1==nil then  RG1,RG2=-255,255  else  if RG2==nil then  RG2=255  end  end
  if RB1==nil then  RB1,RB2=-255,255  else  if RB2==nil then  RB2=255  end  end
  if GB1==nil then  GB1,GB2=-255,255  else  if GB2==nil then  GB2=255  end  end
  local r,g,b=0,0,0
  local arr,ss,k,numbyte,pos={},"",0,255,(fx1-scrX1)*3                   -- pos -  количество первых байтов в строке памяти не требующих анализа
  if len<253 then
    local rgb=1
    local ind=addr+(fy1-scrY1)*len+pos                                   -- начальный индекс в памяти для считывания данных
    local maxind=addr+(fy2-scrY1)*len+(fx2-scrX1+1)*3-1                  -- конечный индекс в памяти для считывания данных
    local x,y,j=fx1,fy1,1
    while ind<=maxind do
      numbyte=math.min(255,maxind-ind+1)                                   -- количество байт для очередной итерации считывания из памяти
      ss=readmem(ind,"s",numbyte,h)
      ind,j=ind+numbyte,1
      while j<=numbyte do
        if x>=fx1 and x<=fx2 then
          if rgb==1 then  b=string.byte(ss,j)  end
          if rgb==2 then  g=string.byte(ss,j)  end
          if rgb==3 then
            r=string.byte(ss,j)
            if r>=r1 and r<=r2 and g>=g1 and g<=g2 and b>=b1 and b<=b2 and r-g>=RG1 and r-g<=RG2 and r-b>=RB1 and r-b<=RB2 and g-b>=GB1 and g-b<=GB2 then
              k=k+1  arr[k]={}  arr[k][1]=x  arr[k][2]=y  arr[k][3]=r  arr[k][4]=g  arr[k][5]=b
              if numf<=k then  return arr  end
            end
          end
        end
        j,pos=j+1,pos+1
        if rgb<3 then  rgb=rgb+1  else  rgb,x=1,x+1  end
        if pos==len then  pos,y,rgb,x=0,y+1,1,scrX1  end
      end
    end
  else
    local numreed=math.ceil((fx2-fx1+1)*3/255)
    local ost=math.fmod((fx2-fx1+1)*3,255)
    for i=fy1,fy2 do
      local ind=addr+(i-scrY1)*len+pos
      local x=fx1
      for s=1,numreed do
        if s==numreed then numbyte=ost  else  numbyte=255  end
        ss=readmem(ind,"s",numbyte,h)
        for j=1,numbyte,3 do
          b=string.byte(ss,j)
          g=string.byte(ss,j+1)
          r=string.byte(ss,j+2)
          if r>=r1 and r<=r2 and g>=g1 and g<=g2 and b>=b1 and b<=b2 and r-g>=RG1 and r-g<=RG2 and r-b>=RB1 and r-b<=RB2 and g-b>=GB1 and g-b<=GB2 then
            k=k+1  arr[k]={}  arr[k][1]=x  arr[k][2]=i  arr[k][3]=r  arr[k][4]=g  arr[k][5]=b
            if numf<=k then  return arr  end
          end
          x=x+1
        end
        ind=ind+numbyte
      end
    end
  end
  return arr
end

log "clear"  log "mode compact"
local x1,y1,x2,y2=49,100,551,941
local address, w, h, len = getimage (x1, y1, x2, y2)
local handle = windowhandle()
local bmp={}
bmp=FindRGB (address, len, x1, y1, 49,700,51,901,"R(0-255)",20000,handle)
deleteimage(address)
for i=1, #bmp do
    log(table.concat(bmp[i], "  "))     -- вывод массива в лог
end

Наваял тут, может ткнут носом что совсем не так делаю. И вопрос, а как сделать, чтобы сохраняя формат в отдельном окошке код помещать?

Автор: sutra 13.11.2018, 0:00

Круто, я так не умею, не знаю как.

Автор: sutra 13.11.2018, 0:16

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

А может Кнайт всё-таки сделает колор инструментом №1.

Автор: DarkMaster 13.11.2018, 0:21

Цитата
len

Может быть рассчитан на основе кооридант. Т.е. его передача по сути не требуется.
Цитата
local _,_,r1,r2 = usl:find("R%((%d+)%-*(%d*)")
local _,_,g1,g2 = usl:find("G%((%d+)%-*(%d*)")
local _,_,b1,b2 = usl:find("B%((%d+)%-*(%d*)")
local _,_,RG1,RG2 = usl:find("R%-G%[(%-*%d+)%s*(%-*%d*)")
local _,_,RB1,RB2 = usl:find("R%-B%[(%-*%d+)%s*(%-*%d*)")
local _,_,GB1,GB2 = usl:find("G%-B%[(%-*%d+)%s*(%-*%d*)")
r1=tonumber(r1) r2=tonumber(r2)
g1=tonumber(g1) g2=tonumber(g2)
b1=tonumber(b1) b2=tonumber(b2)
RG1=tonumber(RG1) RG2=tonumber(RG2)
RB1=tonumber(RB1) RB2=tonumber(RB2)
GB1=tonumber(GB1) GB2=tonumber(GB2)

Можно избавиться передавая вместо стринга массив. Что-то врод:
{r={0, 255}, g={100, 200}}
При этом парсинг, как таковой не очень нужен, читаемость едва ли шибко хуже, но при этом уже полностью стандартизирована и чистый луа в который можно и переменной задать какие-то куски.
Обращаю внимание на то, что избавиться можно именно от парсинга, но вот таблицу привести к массиву ради скорости работы все же нужно. Задание переменными по сути структуры не очень хорошо - массивы как-то логичнее (навсякий случай проверить скорость работы).

Цитата
function FindRGB

local опять уплыл.

Цитата
for

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

Автор: sutra 13.11.2018, 0:39

Спасибо Дарк. Я не знал про переменные. В Паскале это вроде влияло только на размер дебуггера. Хотя всё равно тормоз - reedmem.

Цитата
При этом парсинг, как таковой не очень нужен

Да я вообще в этом почти ничего не понимаю. Я самоучка, методом тыка на примерах. Нет у меня образования. Ты объясняешь, я примерно пытаюсь понять.

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

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

Автор: DarkMaster 13.11.2018, 0:46

Цитата
Я сегодня 3 часа убил только на изучение шаблонов при обработке строк, а ты говоришь таблицей. Нигде "у нас" не сказано, что * - это нуль и более или что () - возвращают результат.

Это регэкспы. Можно почтиать в regex, но в луа они специфические, поэтому рекомендую все-таки или буржуйскую справку или какие-то общие статьи. Тема на самом деле достаточно объемная и не самая простая для восприятия. Там очень много подводных камней с оптимизацией. Я хоть и очень люблю регэкспы, но стараюсь руководствоваться правилом: чем меньше, тем лучше. В понятие "меньше" входит частота вызова участка кода. Регэксп быстр в описании и медленный в работе, нужно это учитывать при написании, хотя конкретно в текущем коде он не критичен, но просто там и не нужен smile.gif Тем не менее не смотря на его тормознутость при выполнении когда-то мной был написан конвертор параметров мобов сервера уо в c#. Так просто было быстрее в плане написания, а код этот по сути должен отработать был только один раз.
Поверьте потраченные 3 часа на регэкспы - это мелочь и они вам точно еще пригодятся в жизни.

Автор: sutra 13.11.2018, 1:01

Спасибо на добром слове Дарк. Примерно я понимаю. Это раньше за каждый байт и даже бит "бились". Я работал на Искре-1030 (512 кб оперативки, 10 МБ разбитый на 5 лог. дисков винт) приходилось некоторые участки кода на ассемблере писать. А сейчас ... кто на чём будет экономить? Памяти - дохренища, винт - солид + РАМ гиг на 16. Прогресс не умолим, я отстал от него неотвратимо. Помню теоретические выкладки о пороге частоты в 1 гигагерц, вот смешно сейчас.

Да ещё и в очередь, 286 машинка стоила тогда более 50 000, не один жигуль можно было купить. Помню как кто-то сказал ... а Нортон то синий, на монохроме мы сидели. Но тогда было интереснее, сейчас все "зажрались".

Да и игры заточены только на выманивание денег - интеллекта - нуль целых, хрен десятых. Вот мы и будем кликать Кнайтовским Пилотом.

Автор: sutra 13.11.2018, 1:32

Цитата
и они вам точно еще пригодятся в жизни

А вот это не факт. Каркать не стану, но сдаётся мне, не так уж много мне осталось.

Автор: DarkMaster 13.11.2018, 2:17

Цитата
Да и игры заточены только на выманивание денег - интеллекта - нуль целых, хрен десятых.

Вот поэтому я играю последнее время и игры 90-х, начала 2000, когда ресурсы уже позволяли сделать что-то удобоваримое, а качество еще встречалось. Кстати говоря неплохие проекты есть и сейчас, причем они как правило DRM-free и распространяются через gog. Могу предложить взглянуть на RimWorld, Pillars of Eternity (играл только в первый).
Цитата
А вот это не факт.

Чаще всего использую в блокноте (notepad++) когда обычным поиском бывает неудобно.
Цитата
Это раньше за каждый байт и даже бит "бились". Я работал на Искре-1030 (512 кб оперативки, 10 МБ разбитый на 5 лог. дисков винт) приходилось некоторые участки кода на ассемблере писать. А сейчас ... кто на чём будет экономить?

Сейчас тоже не все так просто. Просто сами операции зачастую очень невменяемые с точки зрения программиста. Например, распознавание текста на экране с помощью анализа изображения. А иногда приходится делать именно вот так вот. Причем как раз в этих ситуациях очень сильно аукается jpg со своим рендерингом. Приходилось делать до 300 изображений букв и это давало не 100% результат, но приемлимый для отбраковки. Такое количество анализа неизбежно тратит очень большое количество тактов и время работы программы увеличивается до превышающее допустимое. Приходится оптимизировать и выкрадывать каждый пиксель, прогозировать смещения, вместо распознавания фразы начинать распознавать буквы и предугадывать возможные ветвления. Узкие места всегда есть. Но тут уже специфика задачи не позволяет просто взять и считать значение из памяти.

Автор: sutra 13.11.2018, 15:36

Не поленился и потестил чутка некоторые вещи.

local ss=""
local handle=windowhandle()
local tmm = os.clock()
for i=1,100000 do ss=readmem(address,"s",255,handle) end
log(os.clock()-tmm) -- Время теста 15.511 - 16.245 секунд

Меняем строку цикла
ss=readmem(address,"s",1,windowhandle())
Время теста 30.214 - 30.931 секунд

tmm = os.clock()
for i=1,200 do bmp=FindRGB (address, len, x1, y1, x2, 49,402,51,901,"R(0-255)",20000) end
log(os.clock()-tmm)
--Время теста 16.083 - 16.153 секунд (ровно 100000 вызовов reedmem)

local tmm = os.clock()
for i=1,50000 do bmp=FindRGB (address, len, x1, y1, x2, 41,900,51,901,"R(0-255)",20000) end
log(os.clock()-tmm) -- Время теста 24,215

Тот же тест, но я убрал из функции local handle=windowhandle() поместив его в тело скрипта
Время теста 16.151

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


Цитата
распознавание текста

Я конечно не спец по этому вопросу. Но применительно к Пилоту и lua я этот вопрос решил. Мне же не нужно писать свой файнридер. Я знаю точно какой шрифт распознаю. По реперным точкам колором в lua - это делается мгновенно. Раньше в Пилоте были проблемы, а в lua for и if просто летают.


Собственно почему мне и нужен анализ цветовой разницы каналов. Сделал скрин и "вылизываю" его как хочу. Свой имидж на анализ 800 файлов я делал когда не было lua. Пока работает мой имидж джипеговский мне переделывать лень, процесс долгий, пока ещё вычислишь все цветовые значения реперных точек.

Автор: sutra 13.11.2018, 17:34

Вот что значит программировать за кружкой пива.
Надо так
local maxind=addr+(fy2-scrY1)*len+(fx2-scrX1+1)*3-1 -- конечный индекс в памяти для считывания данных
А было так
local maxind=addr+(fy2-scrY1+1)*len-(scrX2-fx2)*3-1 -- конечный индекс в памяти для считывания данных

Как я мог такую дурь придумать, параметр scrX2 вообще не нужен. И логически дурь и практически дурь. Хендл передаю теперь параметром в функцию. Вроде работает, пока чего-нибудь не вылезет.

Автор: sutra 15.11.2018, 17:21

Что-то я опять застрял. Как hint с параметрами вызывать? Типа с размером шрифта.

Автор: DarkMaster 15.11.2018, 17:58

У меня не получилось... Более того там остались паразитные преобразования параметров судя по всему. Фикс нужен.
hint ([fontSize fontColor [posX posY [width height]]] (any text))
не соответсвует реальности в lua. Скобки можно кстати вообще опустить - они не нужны ни в одном из синтаксисов - кавычек должно быть достаточно, тем не менее ломать пилотовский, думаю, не стоит. В луа просто принять за текст последний из переданных параметров, скобки опустить - текст в любом случае будет последним.

пилотовский синтаксис:
hint ("123")
(0): Ошибка! Проварьте правильность скрипта! EIntOverflow Integer overflow hint ("123")

Где-то что-то пошло не так smile.gif

Автор: sutra 15.11.2018, 18:56

Без параметров у меня работает.
hint ("СДВИГ РАВЕН : ",ControlShift)

Автор: DarkMaster 15.11.2018, 20:11

Ну так вопрос вроде был, как с параметрами вызвать)
Без параметров есть какие-то проблемы не в lua вызове. Раньше можно было в некоторых операторах все задать в виде одной строки и тогда вызывался парсинг параметров из пилотовского синтаксиса. Тут так не получилось, решил просто сменить синтаксис и проверить. Резльтат выше smile.gif

Автор: sutra 17.11.2018, 15:18

Дарк, спасибо, разобрался с ридмемом, вроде всё работает. Но вопрос у меня есть. Ходил на ссылочку которую ты дал по использованию СИ структур. Вопрос собственно вот в чём, можно и если можно то как описать структуру из 5-ти элементов {x, y, red, green, blue}

В примере так, но мне тут не всё понятно
local ffi = require("ffi")
ffi.cdef[[
typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;
]]
uint8_t - это что-то типа 8 бит?
rgba_pixel - а это зарезервированный тип или просто имя структуры?


local img = ffi.new("rgba_pixel[?]", n)

Это в примере инициализация, я правильно понял, что n - это заранее объявленный размер массива?

rgba_pixel[?] - а вот про знак вопроса - это не совсем понял.

Автор: sutra 17.11.2018, 15:30

В моём случае x и y должны быть естественно типа word.
И смогу я из функции вернуть такой массив в массив lua.
И есть ли смысл городить такой огород. Я попробовал, чтение действительно происходит мгновенно. Тормоза (хотя конечно и не критические) происходят именно при инициализации значений результирующего массива. Инициализация массива в 2 435 403 элементов осуществляется 3-4 сотых секунды. Конечно мне такие огромные не понадобятся, просто всегда хочется сделать по максимуму.

Автор: sutra 17.11.2018, 16:43

А вообще не трать время Дарк, всё и так просто летает, вызов моего файнда, затрачивает на 28000 элементов массива найденных пикселей 1 тысячную секунды. Для меня результат более чем ... Просто раньше стремился минимизировать вызовы файнда, поэтому и массивы результирующие были побольше, теперь ридмем выполняется мгновенно, следовательно можно крутить файндом сколько угодно. Спасибо тебе огромное Дарк, такую проблему помог решить.

Если кому надо пользуйтесь, может ошибки найдёте.

Код
function FindRGB(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)                                  -- Функция поиска RGB в области памяти
  -- addr,len : адрес в памяти и длина строки в памяти (те, что даёт getimage)
  -- scrX1,scrY1 : координаты верхнего левого угла скрина в памяти, аналогичны координатам getimage (конечные X и Y не требуются)
  -- fx1,fy1,fx2,fy2 : координаты поиска, абсолютные относительно рабочего окна. Обязательно должны быть внутри диапазона скрина.
  -- usl : условие поиска ОДНО, по принципу ужесточения параметров "R(0-255) G(70-90) B(50) R-G[10 80] R-B[-40 -20] G-B[15]" (G-B[15] идентично G-B[15 255]
-- разность между каналами с возможностью интервала)
  -- numf : максимальное количество искомых пикселей
  local rmem = require "ffi".cast
  local _,_,r1,r2=usl:find("R%((%d+)%-*(%d*)")  r1,r2=tonumber(r1),tonumber(r2)                    -- Получение синтаксических значений поиска по каналу RED
  local _,_,g1,g2=usl:find("G%((%d+)%-*(%d*)")  g1,g2=tonumber(g1),tonumber(g2)                    -- Получение синтаксических значений поиска по каналу GREEN
  local _,_,b1,b2=usl:find("B%((%d+)%-*(%d*)")  b1,b2=tonumber(b1),tonumber(b2)                    -- Получение синтаксических значений поиска по каналу BLUE
  local _,_,RG1,RG2=usl:find("R%-G%[(%-*%d+)%s*(%-*%d*)")  RG1,RG2=tonumber(RG1),tonumber(RG2)
  local _,_,RB1,RB2=usl:find("R%-B%[(%-*%d+)%s*(%-*%d*)")  RB1,RB2=tonumber(RB1),tonumber(RB2)
  local _,_,GB1,GB2=usl:find("G%-B%[(%-*%d+)%s*(%-*%d*)")  GB1,GB2=tonumber(GB1),tonumber(GB2)
  if r1==nil then  r1,r2=0,255  else  if r2==nil then  r2=r1  end  end
  if g1==nil then  g1,g2=0,255  else  if g2==nil then  g2=g1  end  end
  if b1==nil then  b1,b2=0,255  else  if b2==nil then  b2=b1  end  end
  if RG1==nil then  RG1,RG2=-255,255  else  if RG2==nil then  RG2=255  end  end
  if RB1==nil then  RB1,RB2=-255,255  else  if RB2==nil then  RB2=255  end  end
  if GB1==nil then  GB1,GB2=-255,255  else  if GB2==nil then  GB2=255  end  end
  local arr,k,indY,ind,r,g,b={},0
  for i=fy1,fy2 do
    indY=addr+(i-scrY1)*len
    for j=fx1,fx2 do
      ind=indY+(j-scrX1)*3
      b=rmem("unsigned char*", ind)[0]
      g=rmem("unsigned char*", ind+1)[0]
      r=rmem("unsigned char*", ind+2)[0]
      if r>=r1 and r<=r2 and g>=g1 and g<=g2 and b>=b1 and b<=b2 and r-g>=RG1 and r-g<=RG2 and r-b>=RB1 and r-b<=RB2 and g-b>=GB1 and g-b<=GB2 then
        k=k+1  arr[k]={}  arr[k][1]=j  arr[k][2]=i  arr[k][3]=r  arr[k][4]=g  arr[k][5]=b
        if numf<=k then  return arr  end
      end
    end
  end
  return arr
end

Автор: cirus 17.11.2018, 18:10

Код
arr[k][1]=j  arr[k][2]=i  arr[k][3]=r  arr[k][4]=g  arr[k][5]=b

Тоже самое:
Код
arr[k]={j, i, r, g, b}

Автор: DarkMaster 17.11.2018, 20:40

Цитата
uint8_t - это что-то типа 8 бит?

Это типа условно новые стандарты старых понятий.
Unsignet int 8 bit _ type, если расшифровать. Т.е. это беззнаковое число 8 бит, прямое указание на то, что это тип, а не функция или еще что-нибудь.
Конкретно в данном случае отличий от char в реалиях не будет, но теоретически char может быть больше 8 бит (он регламентирован, как "не менее 8 бит" и значения "не менее чем от 0 до 255".

Цитата
Для обычного использования стоит использовать следующие: [u]int_leastN_t и [u]int_fastN_t (где N=8, 16, 32, 64). Всё это — типы, которые не уже указанного числа битов (то есть диапазон представления —2N—1+1...2N—1—1 для знаковых и 0...2N—1 для беззнаковых). При этом ..._least_t — самая компактная форма представления, а ..._fast_t — самая быстрая

Тут же наоборот. Не ниже данного числа битов. Т.е. uint_fast8_t скорее всего окажется 32 битным, либо 8 бит с выравниванием до 10. Зависит от платформы. Подобное объявление просто позволяет не заморачиваться с различными особенностями платформ по части типов данных - компилятор подствит то, что нужно.
Цитата
rgba_pixel - а это зарезервированный тип или просто имя структуры?

Имя.
Цитата
local img = ffi.new("rgba_pixel[?]", n)

Это в примере инициализация, я правильно понял, что n - это заранее объявленный размер массива?

Это заранее НЕ объявленный размер массива. Этот разрмер передается при вызове функции, после чего массив создается. Заранее объявленный может быть только константой, т.е. по сути строкой либо переменной типа const.

Цитата
В моём случае x и y должны быть естественно типа word.

16 бит будет достаточно. Можно использовать определения выше: uint_fast16_t.
Цитата
И смогу я из функции вернуть такой массив в массив lua.

Вы можете как минимум читать память этого массива, соответственно его вернуть. Насколько нужно его возвращать вызывает некоторые вопросы. Ведь можно все вычисления произвести прям там, что будет явно быстрее, а результат уже можно и вернуть.
Цитата
_,_,r1,r2=usl:find

Можно вместо find использовать match. Разница только в том, что match не вернет позиции найденных вхождений. Т.е. то, что вы отправили в мусор (_,_,) даже создаваться не будет.
Цитата
if r1==nil then r1,r2=0,255 else if r2==nil then r2=r1 end end

вместо else if можно использовать elseif (слитно). Спец оператор, вроде как от этого будет чуть быстрее.
Цитата
b=rmem("unsigned char*", ind)[0]
g=rmem("unsigned char*", ind+1)[0]
r=rmem("unsigned char*", ind+2)[0]
if r>=r1 and r<=r2 and g>=g1 and g<=g2 and b>=b1 and b<=b2 and r-g>=RG1 and r-g<=RG2 and r-b>=RB1 and r-b<=RB2 and g-b>=GB1 and g-b<=GB2 then

Возможно узкое место. При вызове rmem вы считываете char(8 бит) и сохраняете, как double (64 бита с плавающей точкой). Такое преобразование точно тормозит процесс. Тут имеет смысл проэкспериментировать либо с созданием функции:
Код
local function b() -- аналогично для других каналов
    return rmem("unsigned char*", ind)[0]
end

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

Особое внимение при этом нужно уделить r1, r2 и прочим созданным переменным, которые используются в условии. Они являются типом double. Т.е. даже если мы избежим преобразования наших цветов в конструкции:
b=rmem("unsigned char*", ind)[0]
то они неизбежно будут преобразованы при сравнении, т.к. остальные переменные другого типа. Чтобы этого избежать нужно создать небольшую структурку, скорее всего такую же 8 битную(можно потестить разные варианты, т.к. производительность может изменится).

Цитата
("R%((%d+)%-*(%d*)")

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

Автор: sutra 17.11.2018, 20:53

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

Автор: sutra 17.11.2018, 21:18

Цитата
Сам факт вызова функции теоретически может дать просадку по скорости

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

Цитата
Спец оператор, вроде как от этого будет чуть быстрее

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

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

Цитата
Проще задавать сразу таблицей, а не строкой

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

Автор: sutra 17.11.2018, 21:29

Будет время на досуге покажи мне хотя бы усеченный вариант на 2-х каналах, как это обрабатывать таблицей. Я обязательно глобально протестирую все варианты и обязательно поделюсь результатами. Конечно результаты сильно зависят от проца, но хотя бы относительная разница по времени даст понятие. У меня конечно старенький проц (i7-4930K), но уж теперь другого не будет, в принципе не самый плохой, вроде устраивает.

Автор: sutra 17.11.2018, 21:40

Цитата
arr[k]={j, i, r, g, b}

Спасибо, sirus, не додумал, прирост производительности почти в 2 раза, точнее 1,8 раза.

Автор: DarkMaster 17.11.2018, 21:42

Цитата
Насколько я помню, уж не знаю как комилируется в lua

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

Да, но при этом мы неизбежно вызываем функцию rmem, и едва ли она стек минует. Скорее всего тут вопрос в первую очередь стоит в том, развернет ли компилятор:
Код
local function rmem()
    ...
end
local function g()
    rmem(params)
end
a = g()

В чистый вызов rmem минуя вызов g(). Тут у меня знаний и практики нет.
Бесполезные пустые ифы и присвоения скипает на ура, а что с функциями будет я хз.
Цитата
компиляция тем и отличается от интерпретации, что автоматом оптимизирует код и любой if , else в результате просто выполнит свой джамп на нужный адрес.

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

В луа все является элементом таблицы. Вообще все.
Цитата
и интуиция подсказывает мне, что выигрыша по скорости не будет.

Будет 100%. Вопрос в том на сколько этот выигрыш будет существенным.
Цитата
Да и не понимаю я пока как реализовать эту мысль на практике.

Код
local usl = {r1=10, g1=12}
FindRGB(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)
r1 = usl.r1 or 0 -- если usl.r1 задан, то он останется, если не задан, то задаст 0.
g1...
b1...

Тут прямо напрашивается, чтобы r1, g1, b1 и т.д. были сишными. Вот прям вот молит об этом.

Автор: sutra 17.11.2018, 21:45

Уменьшение параметров прироста производительности не даёт : arr[k]={j, i, color}

Цитата
были сишными. Вот прям вот молит об этом.

Так не умею я!!! Только если есть примеры.

Автор: DarkMaster 17.11.2018, 21:47

Цитата
Уменьшение параметров прироста производительности не даёт

Перефразируйте.
Цитата
Так не умею я!!! Только если есть примеры.

Так и я не пробовал. Я узнал то о возможности вчера) Сейчас потестим.

Автор: sutra 17.11.2018, 21:52

Цитата
Перефразируйте.

Это я sirus-у отвечал. Не важно сколько присвоений {r,g,b, ...} Зависит от перераспределения памяти при обработке таблиц, за один оператор сразу выделяет памяти сколько надо, тормоза (как я понял) зависят именно от этого. Я ж чую уже эти таблицы.

Автор: DarkMaster 17.11.2018, 21:57

Код
local ffi      = require "ffi" -- в шапку.

local params = ffi.new("uint8_t[10]")
params[0] = 11
params[1] = 5
params[2] = params[0] + params[1]
log (params[2])

Создаем массив на 10 элементов по 8 бит.
Обратите внимание на изменившийся require. Раньше мы только часть ffi подключали, теперь весь.

fast/least не понимает. С оптимальным размером по поводу производительности нужно тестить. Весьма возможно, что это окажется не 8 бит, даже если будем сравнивать с 8 битами.

Автор: sutra 17.11.2018, 21:59

Цитата
Тут прямо напрашивается, чтобы r1, g1, b1 и т.д. были сишными

Да сомнений нет, что чисто СИ-шный код (да хоть и паскалевский) всё это должен делать мгновенно. Я 30 лет назад ворочал эти массивы без всяких тормозов.

Автор: DarkMaster 17.11.2018, 22:01

Цитата
Зависит от перераспределения памяти при обработке таблиц, за один оператор сразу выделяет памяти сколько надо, тормоза (как я понял) зависят именно от этого. Я ж чую уже эти таблицы.

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

Автор: sutra 17.11.2018, 22:01

В любом случае, "внешних" функций нет и результат на лицо, конечно если "вылизать" получится супер-пупер!

Но без вашей помощи мне не вылизать.

Автор: DarkMaster 17.11.2018, 22:04

params[0] - это ваши r1, r2 и т.д.
Тут подставить по сути осталось =)

Автор: sutra 17.11.2018, 22:04

Цитата
Ключи скорее всего перестраивает при удалении

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

Автор: sutra 17.11.2018, 22:16

Цитата
params[0] - это ваши r1, r2 и т.д.

Эх, Дарк, у меня жесткий иммунитет, ежели нет понятия, то только на "неживых" данных, только на виртуалке. Это дети и внуки жмут не глядя, а меня воспитывали "в страхе". 7 раз отмерь - 1 отрежь. Лучше уж на конкретном примере покажешь и то не факт, что я пойму. Так это уже не так страшно, тупо скопирую без понятия и тупо буду пользоваться.

Автор: DarkMaster 17.11.2018, 22:29

local rmem = require "ffi".cast
это из тела функции лучше вынести в самый верх скрипта.

Код

local ffi      = require "ffi" -- в шапку.



function FindRGB(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)                                  -- Функция поиска RGB в области памяти
  -- addr,len : адрес в памяти и длина строки в памяти (те, что даёт getimage)
  -- scrX1,scrY1 : координаты верхнего левого угла скрина в памяти, аналогичны координатам getimage (конечные X и Y не требуются)
  -- fx1,fy1,fx2,fy2 : координаты поиска, абсолютные относительно рабочего окна. Обязательно должны быть внутри диапазона скрина.
  -- usl : условие поиска ОДНО, по принципу ужесточения параметров "R(0-255) G(70-90) B(50) R-G[10 80] R-B[-40 -20] G-B[15]" (G-B[15] идентично G-B[15 255]
-- разность между каналами с возможностью интервала)
  -- numf : максимальное количество искомых пикселей
  local rmem = require "ffi".cast

  local params = ffi.new("uint8_t[10]") -- сколько переменных не считал. 10 при необходимости поменяете.
  local _,_,params[0],params[1]=usl:find("R%((%d+)%-*(%d*)")  r1,r2=tonumber(r1),tonumber(r2)                    -- Получение синтаксических значений поиска по каналу RED

Поменял две последнии строчки. Остально по аналогии. Т.е. у нас теперь вместо r1 будет params[0].

Автор: sutra 17.11.2018, 22:47

ОК. Спасибо, попробую.

Дарк и "сочини" инициализацию СИ-шного массива, тормоза то ИМЕННО на нём. На досуге разумеется. Конечно это актуально только при поиске всех пикселей на большой зоне захвата. Конечно такое вряд ли потребуется, но если будет СИ-й массив - это сделает функцию абсолютно универсальной без потерь скорости.

Автор: DarkMaster 17.11.2018, 22:50

А зачем его создавать? Его же getimage создает, а мы фактически его перебираем.
Вообще я хз что там можно сочинить... На 1 000 000 000 элементов (гигабайт почти) у меня уходит 0.46 сек, на 2 400 000 уходит 0.001 примерно(иногда больше, иногда вообще 0 показывает).

Автор: sutra 17.11.2018, 22:58

Ну или я не понял чего-то, или ты меня не понял. Я имею ввиду операцию присваивания arr[k]={j,i,r,g,b} - именно этот оператор является признаком тормозов на 99%.

Вот нужно, чтобы он был СИ-шным.

Автор: DarkMaster 17.11.2018, 23:06

Размер arr как-то регламентирован? Допустимо ли его задать жестко?

Автор: sutra 17.11.2018, 23:08

В том то и фишка, что нет - это массив найденных пикселей, конечно можно задать по максимально возможному по переменным fx1,fy1,fx2,fy2

Автор: DarkMaster 17.11.2018, 23:12

Использовано на практике может быть любое количество совпадений? Например, я не представляю себе ситуацию, когда будет использовано хотя бы 100 совпадений по findimage, не говоря уже о миллионах =)
Просто учитывая определенную тормознутость выделения памяти это может быть узким местом, если выделять лишнюю. В противном случае нужно прикручивать массив в котором будут содержаться указатели на другие массивы. В рамках луа возникнет много вопросов.

Автор: sutra 17.11.2018, 23:24

Цитата
Использовано на практике

Условие R(0-255) должно вернуть массив всей области поиска. На практике, раньше я только так анализировал окно игры, при нынешнем (моём) файнде - это гипотетический случай.

Сейчас вообще нет тормозов на вызов файнда, поэтому можно по зоне захвата делать хоть сотню (это даже ОЧЕНЬ с запасом)вызозов файнда. Вопрос возможно без тормозов получить весь массив или нет, практического применения этого на данный момент я не вижу. Но я максималист, просто интересно, возможно это или нет.

local ffi = require("ffi")
ffi.cdef[[
typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;
]]
Вот про какую вещь я спрашиваю, как я понял фишка именно в этом, в том примере, ссылочку которого ты мне дал.

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

Автор: DarkMaster 17.11.2018, 23:30

Код
local t = os.clock()
ffi.cdef[[
typedef struct { uint16_t x; uint16_t y; uint8_t red; uint8_t green; uint8_t blue; } rgba_pixel;
]]

function FindRGB(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)  
local arr = ffi.new("rgba_pixel[?]", (fx2 - fx1)*(fy2-fy1) )
....
....
if r>=r1 and r<=r2 and g>=g1 and g<=g2 and b>=b1 and b<=b2 and r-g>=RG1 and r-g<=RG2 and r-b>=RB1 and r-b<=RB2 and g-b>=GB1 and g-b<=GB2 then
arr[k].x=j  arr[k].y=i  arr[k].red=r  arr[k].green=g  arr[k].blue=b

как-то так

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

Надо проверять. Это в первую очередь зависит от конкретной архитектуры процессора. У меня там 16 и 8 бит заданы, но еще раз оговорюсь - надо тестить.

Автор: sutra 17.11.2018, 23:31

Спасибо, вот это я и хотел, попробую, хотя сегодня уже башка не варит, ну если не сегодня, то завтра потестирую.

Автор: DarkMaster 17.11.2018, 23:37

Мне на самом деле очень интересно, что по скорости получится.

Автор: DarkMaster 18.11.2018, 9:34

Произвел синтетический тест. Результаты местами неожиданные.
1) Время выполнения операций межу си типом и lua типом меньше, чем между одинаковыми си типами.
Скорее всего при сложении производится конвертация обоих параметров в double, в double же производится вычисление и потом конвертится обратно. При этом должна теряться точность целочисленных вычислений, что плохо(очень).
Косвенно в пользу этой версии говорит то, что сложение long double и lua переменной оказалось невозможно(сохранение производилось в long double).
Так же за эту версию говорит результат сложения двух double. Время практически идентичное сложению lua.
2) uint32_t / unsigned int. Просто какой-то дикий невероятный тормоз, которому я не могу вообще никакого оправдания придумать. u_int64_t и unsigned long long int идут с минимальным отставаением. При этом знаковые 64 битные вычисления оказываются быстрее беззнаковых 32 битных (хоть и не на много). Т.е. если нам нужно хранить число которое не помещается в int, но помещается в unsigned int, то для быстродействия лучше использовать не unsigned int, a long long int. Как? Жесть какая-то. При этом в double 52 бита отведены под целочисленные значения. Там даже привидения типа как такового быть не должно. Ужас...
3) Вычисления на чистом lua. Скорость вычислений слабенькая. Этого по сути и следовало ожидать - операции с плавающей запятой всегда были не очень шустрыми, сейчас вроде получше, но камушек у меня древний. Минимальное отставание от double - видимо какие-то накладные расходы есть (возможно при обращении к массиву). А вот инициализация поистине медленная - дикое отставание от всего, плюс согласно данным luajit.org там идет огромный оверхед по памяти, чем легко можно объяснить время инициализации.

В целом могу оценить результаты кроме unsigned int вполне логичные.

Код. Где ошибка?
Код
print = log
print "clear"
print "mode compact"


local ffi      = require "ffi" -- в шапку.

local t, t2 = nil, nil

local count = 1024*1024*1000
--local count = 1



local data_type ={
    {"int8_t"},
    {"char"},
    {"uint8_t"},
    {"unsigned char"},
    {"int16_t"},
    {"short"},
    {"uint16_t"},
    {"unsigned short"},
    {"int32_t"},
    {"int"},
    {"long int"},
    {"uint32_t"},
    {"unsigned int"},
    {"unsigned long int"},
    {"int64_t"},
    {"long long int"},
    {"uint64_t"},
    {"unsigned long long int"},
    {"float"},
    {"double"},
    }

local my_var = random(10) + 1
for i = 1, #data_type do
    type = data_type[i][1]
    log(type)


--    Время присвоения одного элемента статического массива
    local arr = ffi.new(type.."[".. count / 1000 .."]")
    t = os.clock()
    for j = 1, 1000 do
        for i = 0, count / 1000 - 1 do
            arr[i] = my_var
        end
    end
    t2 = (os.clock() - t)
    data_type[i][2] = t2


    --Время сложения двух элементов статического массива
    arr[0] = random(10) + 1
    t = os.clock()
    for j = 1, 1000 do
        for i = 0, count / 1000 - 1 do
            arr[i] = arr[i] + arr[0]
        end
    end
    t2 = (os.clock() - t)
    data_type[i][3] = t2

    --Время сложения элемента статического массива и переменной lua
    t = os.clock()
    for j = 1, 1000 do
        for i = 0, count / 1000 - 1 do
            arr[i] = arr[i] + my_var
        end
    end
    t2 = (os.clock() - t)
    data_type[i][4] = t2
    arr = nil
end


-- pure lua
for i = 1, 1 do
    local data_type = {{}}
    data_type[i][1] = "lua"
    type = data_type[i][1]
    log(type)

--    Время присвоения одного элемента статического массива
    local arr = nil
    t = os.clock()
    for j = 1, 1000 do
        arr = {}
        for i = 1, count / 1000 do
            arr[i] = my_var
        end
    end
    t2 = (os.clock() - t)
    data_type[i][2] = t2


    --Время сложения двух элементов статического массива
    arr[1] = random(10) + 1
    t = os.clock()
    t = os.clock()
    for j = 1, 1000 do
        for i = 1, count / 1000 do
            arr[i] = arr[i] + arr[1]
        end
    end
    t2 = (os.clock() - t)
    data_type[i][3] = t2
--    data_type[i][3] = "  -  "

    --Время сложения элемента статического массива и переменной lua
    t = os.clock()
    for j = 0, 1000 do
        for i = 1, count / 1000 do
            arr[i] = arr[i] + my_var
        end
    end
    t2 = (os.clock() - t)
    data_type[i][4] = t2
    arr = nil
    log ("           type                 init   sumC   sumLua")
    log(string.format("%-27s:    %.3f %.3f  %.3f", unpack(data_type[i])))
end


for i = 1, #data_type do
    log(string.format("%-27s:    %.3f  %.3f  %.3f", unpack(data_type[i])))
end

t = os.clock()

for i = 0, count do
end
t2 = (os.clock() - t)
log("Время перебора пустого for :    " .. string.format("%.3f",t2))

log ("")
log ("done.")

Результаты
Код
тип данных        инициализация        сложение с массивом того же типа         сложение с lua массивом
           type                 init   sumC   sumLua
lua                        :    16.324 3.161  3.192
int8_t                     :    0.653  0.682  0.653
char                       :    0.650  0.675  0.650
uint8_t                    :    0.648  0.678  0.650
unsigned char              :    0.650  0.678  0.651
int16_t                    :    0.660  0.690  0.665
short                      :    0.660  0.704  0.669
uint16_t                   :    0.660  0.691  0.669
unsigned short             :    0.660  0.689  0.676
int32_t                    :    1.463  1.481  1.463
int                        :    1.468  1.486  1.550
long int                   :    1.442  1.474  1.483
uint32_t                   :    1.445  2.505  1.673
unsigned int               :    1.446  2.502  1.676
unsigned long int          :    1.448  2.503  1.678
int64_t                    :    3.127  3.214  3.167
long long int              :    3.113  3.178  3.173
uint64_t                   :    3.131  3.206  3.183
unsigned long long int     :    3.119  3.174  3.241
float                      :    1.449  1.905  1.635
double                     :    3.103  3.126  3.152
Время перебора пустого for :    0.322

Надо бы еще на си через ffi написать аналогичный тест. Там можно функции создавать. Если есть желающие - буду рад.

Автор: cirus 18.11.2018, 11:41

Цитата
но камушек у меня древний

Походу очень древний.
i7 7700K, результаты
Код
           type                 init   sumC   sumLua
lua                        :    4.458 0.625  0.541
int8_t                     :    0.266  0.344  0.343
char                       :    0.284  0.353  0.329
uint8_t                    :    0.265  0.469  0.328
unsigned char              :    0.266  0.468  0.328
int16_t                    :    0.266  0.359  0.468
short                      :    0.282  0.359  0.469
uint16_t                   :    0.286  0.355  0.339
unsigned short             :    0.269  0.370  0.340
int32_t                    :    0.281  0.344  0.343
int                        :    0.282  0.359  0.344
long int                   :    0.281  0.468  0.328
uint32_t                   :    0.282  0.953  0.843
unsigned int               :    0.265  0.929  0.859
unsigned long int          :    0.281  0.938  0.849
int64_t                    :    0.578  0.734  0.656
long long int              :    0.578  0.734  0.687
uint64_t                   :    0.578  0.735  0.656
unsigned long long int     :    0.563  0.734  0.656
float                      :    0.281  0.594  0.491
double                     :    0.312  0.500  0.485
Время перебора пустого for :    0.231

Автор: sutra 18.11.2018, 13:38

Правильность поиска пока не проверял, потестил чисто на скорость. Прирост более чем в 10 раз, точнее 11,8. На моём камушке 50 000 000 пикселей в секунду.

Скрин 900х900, получаю весь массив за 16 тысячных, результат более чем приемлемый.

Автор: sutra 18.11.2018, 14:05

Код
           type                 init   sumC   sumLua
lua                        :    7.750 1.040  1.107
int8_t                     :    0.380  0.676  0.648
char                       :    0.372  0.703  0.620
uint8_t                    :    0.358  0.641  0.659
unsigned char              :    0.363  0.655  0.686
int16_t                    :    0.387  0.665  0.620
short                      :    0.407  0.630  0.663
uint16_t                   :    0.375  0.659  0.621
unsigned short             :    0.405  0.653  0.621
int32_t                    :    0.414  0.663  0.688
int                        :    0.373  0.691  0.632
long int                   :    0.392  0.656  0.694
uint32_t                   :    0.381  2.270  1.083
unsigned int               :    0.416  2.285  1.144
unsigned long int          :    0.376  1.436  1.051
int64_t                    :    0.897  1.352  1.062
long long int              :    0.878  1.311  1.107
uint64_t                   :    0.931  1.354  1.134
unsigned long long int     :    0.960  1.279  1.081
float                      :    0.391  1.290  0.958
double                     :    0.439  0.729  0.762
Время перебора пустого for :    0.355


На пустом переборе - худший результат. Но слава богу не самый худший.

Автор: sutra 18.11.2018, 16:10

Ну в общем чего я так интуитивно боялся, то и происходит. Проблема в совместимости СИ-шных и LUA-шных структур. Причём вешает LUA наглухо, только перезагрузка Пилота.

Автор: DarkMaster 18.11.2018, 23:24

Цитата
Ну в общем чего я так интуитивно боялся, то и происходит. Проблема в совместимости СИ-шных и LUA-шных структур. Причём вешает LUA наглухо, только перезагрузка Пилота.

хотелось бы какой-то конкретики. В lua нет структур кстати. В том, то luajit кривой у меня очень большие сомнения.

Автор: sutra 19.11.2018, 8:57

Код

--lua
local ffi = require "ffi"
ffi.cdef[[
typedef struct { uint16_t x; uint16_t y; uint8_t red; uint8_t green; uint8_t blue; } rgba_pixel;
]]
function FindRGB(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)                                  -- Функция поиска RGB в области памяти
  -- addr,len : адрес в памяти и длина строки в памяти (те, что даёт getimage)
  -- scrX1,scrY1 : координаты верхнего левого угла скрина в памяти, аналогичны координатам getimage (конечные X и Y не требуются)
  -- fx1,fy1,fx2,fy2 : координаты поиска, абсолютные относительно рабочего окна. Обязательно должны быть внутри диапазона скрина.
  -- usl : условие поиска ОДНО, по принципу ужесточения параметров "R(0-255) G(70-90) B(50) R-G[10 80] R-B[-40 -20] G-B[15]" (G-B[15] идентично G-B[15 255] - разность
  -- между каналами с возможностью интервала)
  -- numf : максимальное количество искомых пикселей
  local rmem = require "ffi".cast
  local n=(fx2 - fx1+1)*(fy2-fy1+1)          -- если будет работать, сделать минимум по параметру numf
  local arr = ffi.new("rgba_pixel[?]", n )
  local _,_,r1,r2=usl:find("R%((%d+)%-*(%d*)")  r1,r2=tonumber(r1),tonumber(r2)                    -- Получение синтаксических значений поиска по каналу RED
  local _,_,g1,g2=usl:find("G%((%d+)%-*(%d*)")  g1,g2=tonumber(g1),tonumber(g2)                    -- Получение синтаксических значений поиска по каналу GREEN
  local _,_,b1,b2=usl:find("B%((%d+)%-*(%d*)")  b1,b2=tonumber(b1),tonumber(b2)                    -- Получение синтаксических значений поиска по каналу BLUE
  local _,_,RG1,RG2=usl:find("R%-G%[(%-*%d+)%s*(%-*%d*)")  RG1,RG2=tonumber(RG1),tonumber(RG2)
  local _,_,RB1,RB2=usl:find("R%-B%[(%-*%d+)%s*(%-*%d*)")  RB1,RB2=tonumber(RB1),tonumber(RB2)
  local _,_,GB1,GB2=usl:find("G%-B%[(%-*%d+)%s*(%-*%d*)")  GB1,GB2=tonumber(GB1),tonumber(GB2)
  if r1==nil then  r1,r2=0,255  else  if r2==nil then  r2=r1  end  end
  if g1==nil then  g1,g2=0,255  else  if g2==nil then  g2=g1  end  end
  if b1==nil then  b1,b2=0,255  else  if b2==nil then  b2=b1  end  end
  if RG1==nil then  RG1,RG2=-255,255  else  if RG2==nil then  RG2=255  end  end
  if RB1==nil then  RB1,RB2=-255,255  else  if RB2==nil then  RB2=255  end  end
  if GB1==nil then  GB1,GB2=-255,255  else  if GB2==nil then  GB2=255  end  end
  local k,indY,ind,r,g,b=0
  for i=fy1,fy2 do
    indY=addr+(i-scrY1)*len
    for j=fx1,fx2 do
      ind=indY+(j-scrX1)*3
      b=rmem("unsigned char*", ind)[0]
      g=rmem("unsigned char*", ind+1)[0]
      r=rmem("unsigned char*", ind+2)[0]
      if r>=r1 and r<=r2 and g>=g1 and g<=g2 and b>=b1 and b<=b2 and r-g>=RG1 and r-g<=RG2 and r-b>=RB1 and r-b<=RB2 and g-b>=GB1 and g-b<=GB2 then
        k=k+1  arr[k].x=j  arr[k].y=i  arr[k].red=r  arr[k].green=g  arr[k].blue=b
        if numf==k then  return arr  end
      end
    end
  end
  return arr
end

log "clear" log "mode compact"
local addr, width, height, len = getimage (0, 0, 9, 9)
local vi={}
tmm = os.clock()
for i=1, 300 do
  vi=FindRGB(addr,len,0,0,0,0,9,9,"R(0-255)",10000000)
end
log(os.clock()-tmm)
deleteimage(addr)
log(#vi)             -- ошибка, если заремарить - ошибка закрытия lua


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

По логике - проблема вроде как в размерности таблицы.

Автор: sutra 19.11.2018, 9:23

set timer3
set %arr[1 1] #WR // рабочее окно
save_array %arr "a:\_find.txt" // на RAM
start_script 8 wait // вызов 2-х файндов, более сотни ифов и собственно getimage
load_array %res "a:\_res.txt"
set #res1 %res[1 1]
set #res2 %res[1 2]
set #res3 %res[1 3]
set #tmp timer3
hint (28 (#res1 #res2 #res3 Время : #tmp)) // 19 - 26 тысячных

Дарк, собственно меня и старый вариант устраивает, так что если и не получится, я не расстроюсь.

Автор: sutra 19.11.2018, 10:56

Цитата
В том, то luajit кривой у меня очень большие сомнения.


Прикол ещё в том, что в какой-то момент времени вроде всё работало, но восстановить этот рабочий вариант так и не смог. А всё, что работает не стабильно, я всегда избегаю.

Автор: DarkMaster 20.11.2018, 1:03

Цитата
log(#vi) -- ошибка, если заремарить - ошибка закрытия lua

Дык конечно ошибка =) Вы пытаетесь получить размер массива си структур оператором который возвращает размер массива луа(он по сути является скрытым полем таблицы). Я более того скажу, даже если вы попытаетесь получить размер массива внутри си, то у вас будут те же самые проблемы. Дело в том, что массив созданный даже в нормальной си-программе в пределах одной функции передается в другую функцию по указателю/ссылке (суть одна и та же - просто адрес в памяти 32/64 бита в зависимости от разрядности). Это приводит к тому, что создав массив в функции А мы не можем получить его размер в функции В, т.к. в функцию В прилетает только адрес этого массив. Размер в таком случае передается дополнительной переменной. На самом деле мой косяк - хотел предупредить и забыл.

Автор: sutra 20.11.2018, 1:12

Перевёл ещё один "хитрый" блок на lua, всё чудно работает, теперь не думаю про дополнительные операторы (if и for). Усилил логику за счёт добавления ифов и форов и за счёт расширения диапазона проверок и количества вызова файнда, всё мгновенно и точно на 100%. Как и обещал, да хоть блоху. Улучшился анализ временнЫх параметров, по факту время тратится только на getimage. Но за один такой вызов "высасываю" максимум возможного, да ещё и с предсказанием дальнейших действий.

Цитата
Вы пытаетесь получить размер массива си структур

Если заремарить - ошибка закрытия lua.


Цитата
Дык конечно ошибка

Дарк, у меня нет сомнений, что косячу я, у меня нет сомнений, что можно сделать ВСЁ. Но только как это сделать я пока не знаю.

Автор: DarkMaster 20.11.2018, 1:16

Код
print = log
print "clear"
print "mode compact"

local ffi = require "ffi"
local rmem = ffi.cast
ffi.cdef[[
typedef struct { uint16_t x; uint16_t y; uint8_t red; uint8_t green; uint8_t blue; } rgba_pixel;
]]
function FindRGB(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)                                  -- Функция поиска RGB в области памяти
--   addr,len : адрес в памяти и длина строки в памяти (те, что даёт getimage)
--   scrX1,scrY1 : координаты верхнего левого угла скрина в памяти, аналогичны координатам getimage (конечные X и Y не требуются)
--   fx1,fy1,fx2,fy2 : координаты поиска, абсолютные относительно рабочего окна. Обязательно должны быть внутри диапазона скрина.
--   usl : условие поиска ОДНО, по принципу ужесточения параметров "R(0-255) G(70-90) B(50) R-G[10 80] R-B[-40 -20] G-B[15]" (G-B[15] идентично G-B[15 255] - разность
--   между каналами с возможностью интервала)
--   numf : максимальное количество искомых пикселей
  local n=(fx2 - fx1+1)*(fy2-fy1+1)          -- если будет работать, сделать минимум по параметру numf
  local arr = ffi.new("rgba_pixel[?]", n )
  local _,_,r1,r2=usl:find("R%((%d+)%-*(%d*)")  r1,r2=tonumber(r1),tonumber(r2)                    -- Получение синтаксических значений поиска по каналу RED
  local _,_,g1,g2=usl:find("G%((%d+)%-*(%d*)")  g1,g2=tonumber(g1),tonumber(g2)                    -- Получение синтаксических значений поиска по каналу GREEN
  local _,_,b1,b2=usl:find("B%((%d+)%-*(%d*)")  b1,b2=tonumber(b1),tonumber(b2)                    -- Получение синтаксических значений поиска по каналу BLUE
  local _,_,RG1,RG2=usl:find("R%-G%[(%-*%d+)%s*(%-*%d*)")  RG1,RG2=tonumber(RG1),tonumber(RG2)
  local _,_,RB1,RB2=usl:find("R%-B%[(%-*%d+)%s*(%-*%d*)")  RB1,RB2=tonumber(RB1),tonumber(RB2)
  local _,_,GB1,GB2=usl:find("G%-B%[(%-*%d+)%s*(%-*%d*)")  GB1,GB2=tonumber(GB1),tonumber(GB2)
  if r1==nil then  r1,r2=0,255  else  if r2==nil then  r2=r1  end  end
  if g1==nil then  g1,g2=0,255  else  if g2==nil then  g2=g1  end  end
  if b1==nil then  b1,b2=0,255  else  if b2==nil then  b2=b1  end  end
  if RG1==nil then  RG1,RG2=-255,255  else  if RG2==nil then  RG2=255  end  end
  if RB1==nil then  RB1,RB2=-255,255  else  if RB2==nil then  RB2=255  end  end
  if GB1==nil then  GB1,GB2=-255,255  else  if GB2==nil then  GB2=255  end  end

  local k,indY,ind,r,g,b=-1
  for i=fy1,fy2 do
    indY=addr+(i-scrY1)*len
    for j=fx1,fx2 do
      ind=indY+(j-scrX1)*3
      b=rmem("unsigned char*", ind)[0]
      g=rmem("unsigned char*", ind+1)[0]
      r=rmem("unsigned char*", ind+2)[0]
      if r>=r1 and r<=r2 and g>=g1 and g<=g2 and b>=b1 and b<=b2 and r-g>=RG1 and r-g<=RG2 and r-b>=RB1 and r-b<=RB2 and g-b>=GB1 and g-b<=GB2 then
        k=k+1
        arr[k].x=j
        arr[k].y=i
        arr[k].red=r
        arr[k].green=g
        arr[k].blue=b
        --k=k+1 arr[k].x=j  arr[k].y=i  arr[k].red=r  arr[k].green=g  arr[k].blue=b
        if numf==k then  return arr, k  end
      end
    end
  end
  log(k)
  return arr, k
end

log "clear" log "mode compact"
local addr, width, height, len = getimage (0, 0, 9, 9)
local vi, k={}
tmm = os.clock()
for i=1, 300 do
  vi, k=FindRGB(addr,len,0,0,0,0,9,9,"R(0-255)",10000000)
end
log(os.clock()-tmm)
deleteimage(addr)
log(type(vi))             -- ошибка, если заремарить - ошибка закрытия lua
log(k)

log "done."

Исправлена ошибка с выходами за пределы массива.
k - ранее объявлялся равным нулю, затем при первой же итерации перед записью данных происходил инкремент:
k = k + 1
Что в итоге приводило выходу за пределы массива на 1 элемент в хвосте.
Добавлен возврат количества совпадений:
if numf==k then return arr, k end
return arr, k
добавлено получение количества совпадений:
vi, k=FindRGB
изменено для понимания происходящего:
log(type(vi)) -- ошибка, если заремарить - ошибка закрытия lua
Обратите внимение на возвращаемый типа - cdata. Не table.

Автор: sutra 20.11.2018, 1:19

Спасибо, буду пробовать. Я просто многого не знаю, как всё это "фунциклирует", поэтому всё методом тыка.

Автор: DarkMaster 20.11.2018, 1:22

Еще раз обращаю внимание на то, что это Сишный массив. Т.е. индекс первого элемента равен нулю. Возвращается не "размер"(k), а номер последнего индекса в массиве. Т.е. элементов у нас 100, но k вернет 99, т.к. записаны данные в индексах 0-99. Если есть желание можно сделать +1 в return, но есть ли в этом смысл не понятно, т.к. если будете работать с данным масивом то в первом же переборе нужно будет делать -1.

Цитата
Я просто многого не знаю, как всё это "фунциклирует", поэтому всё методом тыка.

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

Автор: sutra 20.11.2018, 1:30

Цитата
return arr, k

Ну про эту вещь я тоже думал. Только я не совсем понял, получается первый элемент таблицы с индексом НУЛЬ?

Спасибо, пока я спрашивал, ответ получен.

А всё-таки, хоть я и неуч, но оказался прав, есть всё-таки проблемы с совместимостью. Если честно, то меня эти нули и единицы всегда раздражали, правильнее, если по уму, то наверное единица, поскольку нуль - это собственно говоря НИЧЕГО. Но булева алгебра накладывает отпечаток, так-как и нуль является информацией.

Автор: DarkMaster 20.11.2018, 1:36

Цитата
получается первый элемент таблицы с индексом НУЛЬ

в Си таблице - да, в lua - нет.
Цитата
А всё-таки, хоть я и неуч, но оказался прав, есть всё-таки проблемы с совместимостью.

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

Автор: sutra 20.11.2018, 1:42

Цитата
Едва ли это вопрос совместимости

Ну спорить не стану, но думаю, что если я на эти грабли наступил, а полным дурнем я себя не считаю, то и многие другие наступят или уже ...

Конечно нужно базовое образование. Но вот только за 30 лет всё ушло на столько вперёд ... А что будет ещё через 30 лет - мозги будут кипеть и охлаждать их будут кулером, управлять которым будет микрочип. Сдаётся мне будут не люди, а биороботы. Вообще-то в своё время не зря разрабатывались стандарты, не просто так принимали систему мер и весов СИ. И не зря учили ВСТИ (взаимозаменяемость, стандартизация ...)

Автор: sutra 20.11.2018, 2:26

Дарк, извини меня, я тут немножко вспылил и начал права качать, на самом деле, спасибо тебе, что "возишься тут со мной", да ещё и за бесплатно.

Автор: sutra 20.11.2018, 2:39

На самом деле тема уже не актуальна. Поскольку ридмем не тормозит, лично у меня уже нет необходимости получать результат поиска файндом в виде массива. Улучшить можно, но только, как я уже говорил, теперь медленный только get, а эти "крохи" выигрыша в виде нескольких микросекунд погоды не делают. Ты помог решить вопрос, СПАСИБО, научил наперёд, СПАСИБО. Пока попробую сам поковыряться. В конце концов, у меня нет цели изучать СИ, я не собираюсь писать свой кликер, меня вполне устраивает Кнайтовский, за что и ему СПАСИБО!

Автор: DarkMaster 20.11.2018, 2:43

Цитата
Дарк, извини меня, я тут немножко вспылил и начал права качать, на самом деле, спасибо тебе, что "возишься тут со мной", да ещё и за бесплатно.

Я даже корзину форума поднял, благо админка есть. Я хз где вы вспылили) Мной не обнаружено, идем дальше =)

Цитата
эти "крохи" выигрыша в виде нескольких микросекунд погоды не делают.

Не загадывайте. Когда нужно будет делать не один анализ, а десяток, а то и больше подряд на больших площадях, то поймете, что оказывается работает все не так быстро, как хотелось бы. Я тоже считал современный финдимидж в сочетании с гетимиджем невероятно быстрым. Ровно до того момента, как понадобилось искать ~200 изображений. Причем и область то была не большой, но тормоз дикий вышел и плясал я долго потом.

Автор: sutra 20.11.2018, 3:10

ОК.

Автор: DarkMaster 20.11.2018, 12:31

Меня больше заинтересовала возможность подлкючения dll'ок сишных напрямую без долбанных оберток луашных. Пока достижения правда не очень... В качестве примера попробовал загрузить и выполнить свою же дллку для работы с double из пилота, но подгрузив ее через ffi. ffi сказал гордо, что вызов таких функций, как в моей дллке пока еще не держит, но только пока. Что именно ему там не понравилось я хз. Zlib1 из обучалки прилинковался и даже работает. Тем не менее в первую очередь лично мне интересна возможность линковки qt или wxwidgets. Попробовал wx - не находит функции вроде как, хотя биндинг сделал. Идеи?

Автор: sutra 21.11.2018, 2:25

Заставил себя всё-таки ещё полопатить свой файнд. Результаты есть, удалось добиться ещё прироста в скорости почти в полтора раза. Скрипт подлатаю и выложу позже, на него сейчас без слёз не взглянешь. Но возникли вопросы.
Сишные переменные не прокатили в двух операторах, может опять чего не так делаю?
local _,_,r1,r2=usl:find("R%((%d+)%-*(%d*)")
r1,r2=tonumber(r1),tonumber(r2)

Обозвал их так: local s=ffi.new("uint8_t[9]")

Пришлось уже после их выполнения делать так:
s[0],s[1],s[2],s[3],s[4],s[5]=r1,r2,g1,g2,b1,b2

Возможно несовместимый тип, я так думаю.

local m=ffi.new("int16_t[6]")
m[0]=tonumber(r1)
log(m[0])

Да, вот так нормально, в общем надо ещё полопатить.

И то не факт, этот тип как я понял, только положительные значения. Надо наверное uint16 использовать.

И ещё вопрос. А не массивом, а обычными переменными как обозвать через ffi ?

И есть ли смысл? Может лучше массивом и оставить?

Автор: DarkMaster 21.11.2018, 6:52

Цитата
local _,_,r1,r2=usl:find("R%((%d+)%-*(%d*)")
r1,r2=tonumber(r1),tonumber(r2)

Код
local r1,r2=usl:match("R%((%d+)%-*(%d*)")
r1,r2=tonumber(r1),tonumber(r2)

Тоже самое без возврата начала и конца позиции, которые и так в _ пишутся.
Цитата
s[0],s[1],s[2],s[3],s[4],s[5]=r1,r2,g1,g2,b1,b2

Возможно несовместимый тип, я так думаю.

Тут пишутся double, хорошо если не string в char. Т.е. у нас следующая проблема:
Дано: 64 бита с плавающей точкой.
Задача: запихать 64 бита с плавающей в 8 бит целочисленных.
В целом если значение мешье или равно 255 все пройти должно нормально. Но тут должно быть приведение типов. Все значения удолетворяют этому условию? Успешное расширение до int16_t намекает, что там значения больше, чем 255.
Цитата
Надо наверное uint16 использовать.

Конкретно в вашем случае можно и знаковый тип использовать. Главное чтобы значение помеситлось. Беззнаковые были зачастую намного тормознутее - это настораживает, хотя 16 битные при сложении подобных проблем не показали.
Цитата
А не массивом, а обычными переменными как обозвать через ffi ?

По сути там все идет через оператор выделения памяти - new(), который обычно только для массивов вызвается в явном виде, хотя где-то в недрах, наверное, вызывается и при инициализации переменной.
Переменная, значение ей задали 10:
local my_var = ffi.new("int",10)

Переменная, значение не задано, но так лучше не делать, хороший тон хотя бы NULL туда помещать.
local my_var = ffi.new("int")
my_var = 10 -- приводит к тому, что она из cdata становится number.
Вообще подобная конвертация из cdata в number мне не понятна. Более того даже из примера https://luajit.org/ext_ffi.html так же становится number не смотря на то, что это элементы таблицы. Но и этого даже мало - спокойно дает переполнить переменную без каких либо ошибок. Что при это происходит в реальности и в каком типе находятся данные не ясно. Скорее всего если оставлять все в рамках, то все будет хорошо и типы не будут приводиться, тем не менее странно как-то это все.

Автор: DarkMaster 21.11.2018, 7:03

Код
local arr_uchar = ffi.new("unsigned char[10]", 2)

arr_uchar[0] = 1200

for i = 0, 9 do
    log (arr_uchar[i], type(arr_uchar[i]))
end

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

Автор: sutra 22.11.2018, 15:12

Цитата
local r1,r2=usl:match("R%((%d+)%-*(%d*)")

Спасибо Дарк, начал шаг за шагом "вылизывать" код.

Код
--lua
function Find1(usl)
  local _,_,r1,r2=usl:find("R%((%d+)%-*(%d*)")
  local _,_,g1,g2=usl:find("G%((%d+)%-*(%d*)")
  local _,_,b1,b2=usl:find("B%((%d+)%-*(%d*)")
  local _,_,RG1,RG2=usl:find("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local _,_,RB1,RB2=usl:find("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local _,_,GB1,GB2=usl:find("G%-B%[(%-*%d+)%s*(%-*%d*)")
end
function Find2(usl)
  local r1,r2=usl:match("R%((%d+)%-*(%d*)")
  local g1,g2=usl:match("G%((%d+)%-*(%d*)")
  local b1,b2=usl:match("B%((%d+)%-*(%d*)")
  local RG1,RG2=usl:match("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local RB1,RB2=usl:match("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local GB1,GB2=usl:match("G%-B%[(%-*%d+)%s*(%-*%d*)")
end

log "clear" log "mode compact"
tmm = os.clock()
for i=1, 1000000 do
  Find1("R(7-155)B(8-154)G(9-153)R-G[50 90]R-B[60 80]G-B[70 75]")
end
log(os.clock()-tmm)    -- среднее 3,137 сек
tmm = os.clock()
for i=1, 1000000 do
  Find2("R(7-155)B(8-154)G(9-153)R-G[50 90]R-B[60 80]G-B[70 75]")
end
log(os.clock()-tmm)    -- среднее 2,829 сек
tmm = os.clock()


Стало эстетичнее и на 10% быстрее (для этого участка кода).

Автор: sutra 22.11.2018, 17:01

Попытка переделать блок инициализации в СИ-шные переменные потерпела фиаско. tonumber с СИ-шной переменной работает только если строка реально является числом (по крайней мере я так понял). Поэтому перед вызовом tonumber пришлось анализировать строки и это привело к падению производительности.

Код
--lua
local ffi = require "ffi"
function Find1(usl)
  local r1,r2=usl:match("R%((%d+)%-*(%d*)")
  local g1,g2=usl:match("G%((%d+)%-*(%d*)")
  local b1,b2=usl:match("B%((%d+)%-*(%d*)")
  local RG1,RG2=usl:match("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local RB1,RB2=usl:match("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local GB1,GB2=usl:match("G%-B%[(%-*%d+)%s*(%-*%d*)")
  r1,r2=tonumber(r1),tonumber(r2)
  g1,g2=tonumber(g1),tonumber(g2)
  b1,b2=tonumber(b1),tonumber(b2)
  RG1,RG2=tonumber(RG1),tonumber(RG2)
  RB1,RB2=tonumber(RB1),tonumber(RB2)
  GB1,GB2=tonumber(GB1),tonumber(GB2)
  if r1==nil then  r1,r2=0,255  else  if r2==nil then  r2=r1  end  end
  if g1==nil then  g1,g2=0,255  else  if g2==nil then  g2=g1  end  end
  if b1==nil then  b1,b2=0,255  else  if b2==nil then  b2=b1  end  end
  if RG1==nil then  RG1,RG2=-255,255  else  if RG2==nil then  RG2=255  end  end
  if RB1==nil then  RB1,RB2=-255,255  else  if RB2==nil then  RB2=255  end  end
  if GB1==nil then  GB1,GB2=-255,255  else  if GB2==nil then  GB2=255  end  end
end
function Find2(usl)
  local r1,r2=usl:match("R%((%d+)%-*(%d*)")
  local g1,g2=usl:match("G%((%d+)%-*(%d*)")
  local b1,b2=usl:match("B%((%d+)%-*(%d*)")
  local RG1,RG2=usl:match("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local RB1,RB2=usl:match("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local GB1,GB2=usl:match("G%-B%[(%-*%d+)%s*(%-*%d*)")
  local s=ffi.new("uint8_t[6]")
  local m=ffi.new("int16_t[6]")
  if r1==nil then s[0],s[1]=0,255
  else
    s[0]=tonumber(r1)
    if r2=="" then s[1]=s[0]  else s[1]=tonumber(r2)  end
  end
  if g1==nil then s[2],s[3]=0,255
  else
    s[2]=tonumber(g1)
    if g2=="" then s[3]=s[2]  else s[3]=tonumber(g2)  end
  end
  if b1==nil then s[4],s[5]=0,255
  else
    s[4]=tonumber(b1)
    if b2=="" then s[5]=s[4]  else s[5]=tonumber(b2)  end
  end
  if RG1==nil then m[0],m[1]=-255,255
  else
    m[0]=tonumber(RG1)
    if RG2=="" then m[1]=255  else m[1]=tonumber(RG2)  end
  end
  if RB1==nil then m[2],m[3]=-255,255
  else
    m[2]=tonumber(RB1)
    if RB2=="" then m[3]=255  else m[3]=tonumber(RB2)  end
  end
  if GB1==nil then m[4],m[5]=-255,255
  else
    m[4]=tonumber(GB1)
    if GB2=="" then m[5]=255  else m[5]=tonumber(GB2)  end
  end
end

log "clear" log "mode compact"
tmm = os.clock()
for i=1, 1000000 do
  Find1("R(7-155)B(8-154)G(9-153)R-G[50 90]R-B[60 80]G-B[70 75]")
end
log(os.clock()-tmm)    -- 3.480 сек. и 3.569 сек.
tmm = os.clock()
for i=1, 1000000 do
  Find2("R(7-155)B(8-154)G(9-153)R-G[50 90]R-B[60 80]G-B[70 75]")
end
log(os.clock()-tmm)    -- 4.774 сек. и 4.866 сек.
tmm = os.clock()

Автор: sutra 22.11.2018, 18:38

Точнее к падению производительности привело преобразование типов при выполнении tonumber.

Автор: sutra 22.11.2018, 20:32

Код
--lua
local ffi = require "ffi"
local rmem = ffi.cast
ffi.cdef[[
typedef struct { uint16_t x; uint16_t y; uint8_t red; uint8_t green; uint8_t blue; } rgba_pixel;
]]
function FindRGBold(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)
  local n=math.min(numf,(fx2-fx1+1)*(fy2-fy1+1))
  local arr = ffi.new("rgba_pixel[?]", n )
  local r1,r2=usl:match("R%((%d+)%-*(%d*)")
  local g1,g2=usl:match("G%((%d+)%-*(%d*)")
  local b1,b2=usl:match("B%((%d+)%-*(%d*)")
  local RG1,RG2=usl:match("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local RB1,RB2=usl:match("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local GB1,GB2=usl:match("G%-B%[(%-*%d+)%s*(%-*%d*)")
  r1,r2=tonumber(r1),tonumber(r2)
  g1,g2=tonumber(g1),tonumber(g2)
  b1,b2=tonumber(b1),tonumber(b2)
  RG1,RG2=tonumber(RG1),tonumber(RG2)
  RB1,RB2=tonumber(RB1),tonumber(RB2)
  GB1,GB2=tonumber(GB1),tonumber(GB2)
  if r1==nil then  r1,r2=0,255  else  if r2==nil then  r2=r1  end  end
  if g1==nil then  g1,g2=0,255  else  if g2==nil then  g2=g1  end  end
  if b1==nil then  b1,b2=0,255  else  if b2==nil then  b2=b1  end  end
  if RG1==nil then  RG1,RG2=-255,255  else  if RG2==nil then  RG2=255  end  end
  if RB1==nil then  RB1,RB2=-255,255  else  if RB2==nil then  RB2=255  end  end
  if GB1==nil then  GB1,GB2=-255,255  else  if GB2==nil then  GB2=255  end  end
  local k,indY,ind,r,g,b=-1
  for i=fy1,fy2 do
    indY=addr+(i-scrY1)*len
    for j=fx1,fx2 do
      ind=indY+(j-scrX1)*3
      b=rmem("unsigned char*", ind)[0]
      g=rmem("unsigned char*", ind+1)[0]
      r=rmem("unsigned char*", ind+2)[0]
      if r>=r1 and r<=r2 and g>=g1 and g<=g2 and b>=b1 and b<=b2 and r-g>=RG1 and r-g<=RG2 and r-b>=RB1 and r-b<=RB2 and g-b>=GB1 and g-b<=GB2 then
        k=k+1 arr[k].x, arr[k].y, arr[k].red, arr[k].green, arr[k].blue = j,i,r,g,b
        if numf==k then  return arr, k  end
      end
    end
  end
  return arr, k
end
function FindRGB(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)
  local n=math.min(numf,(fx2-fx1+1)*(fy2-fy1+1))
  local arr = ffi.new("rgba_pixel[?]", n )
  local r1,r2=usl:match("R%((%d+)%-*(%d*)")
  local g1,g2=usl:match("G%((%d+)%-*(%d*)")
  local b1,b2=usl:match("B%((%d+)%-*(%d*)")
  local RG1,RG2=usl:match("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local RB1,RB2=usl:match("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local GB1,GB2=usl:match("G%-B%[(%-*%d+)%s*(%-*%d*)")
  r1,r2=tonumber(r1),tonumber(r2)
  g1,g2=tonumber(g1),tonumber(g2)
  b1,b2=tonumber(b1),tonumber(b2)
  RG1,RG2=tonumber(RG1),tonumber(RG2)
  RB1,RB2=tonumber(RB1),tonumber(RB2)
  GB1,GB2=tonumber(GB1),tonumber(GB2)
  if r1==nil then  r1,r2=0,255  else  if r2==nil then  r2=r1  end  end
  if g1==nil then  g1,g2=0,255  else  if g2==nil then  g2=g1  end  end
  if b1==nil then  b1,b2=0,255  else  if b2==nil then  b2=b1  end  end
  if RG1==nil then  RG1,RG2=-255,255  else  if RG2==nil then  RG2=255  end  end
  if RB1==nil then  RB1,RB2=-255,255  else  if RB2==nil then  RB2=255  end  end
  if GB1==nil then  GB1,GB2=-255,255  else  if GB2==nil then  GB2=255  end  end
  local s,m=ffi.new("uint8_t[9]"),ffi.new("int16_t[6]")
  s[0],s[1],s[2],s[3],s[4],s[5],m[0],m[1],m[2],m[3],m[4],m[5]=r1,r2,g1,g2,b1,b2,RG1,RG2,RB1,RB2,GB1,GB2
  local k,indY,ind,r,g,b=-1
  for i=fy1,fy2 do
    indY=addr+(i-scrY1)*len
    for j=fx1,fx2 do
      ind=indY+(j-scrX1)*3
      s[8]=rmem("unsigned char*", ind)[0]
      s[7]=rmem("unsigned char*", ind+1)[0]
      s[6]=rmem("unsigned char*", ind+2)[0]
      if s[6]>=s[0] and s[6]<=s[1] and s[7]>=s[2] and s[7]<=s[3] and s[8]>=s[4] and s[8]<=s[5] and s[6]-s[7]>=m[0] and  -- ПЕРЕНЕС УСЛОВИЕ. ФОРУМ ЛОМАЛО.
             s[6]-s[7]<=m[1] and s[6]-s[8]>=m[2] and s[6]-s[8]<=m[3] and s[7]-s[8]>=m[4] and s[7]-s[8]<=m[5] then
        k=k+1 arr[k].x,arr[k].y,arr[k].red,arr[k].green,arr[k].blue=j,i,s[6],s[7],s[8]
        if numf==k then  return arr, k  end
      end
    end
  end
  return arr, k
end
function ImageToArray(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2)
  local n=(fx2-fx1+1)*(fy2-fy1+1)
  local arr = ffi.new("rgba_pixel[?]", n )
  local s=ffi.new("uint8_t[3]")
  local k,indY,ind,r,g,b=-1
  for i=fy1,fy2 do
    indY=addr+(i-scrY1)*len
    for j=fx1,fx2 do
      ind=indY+(j-scrX1)*3
      s[2]=rmem("unsigned char*", ind)[0]
      s[1]=rmem("unsigned char*", ind+1)[0]
      s[0]=rmem("unsigned char*", ind+2)[0]
      k=k+1 arr[k].x,arr[k].y,arr[k].red,arr[k].green,arr[k].blue=j,i,s[0],s[1],s[2]
    end
  end
  return arr, k
end

log "clear" log "mode compact"
local addr, width, height, len = getimage (0, 0, 999, 999)
local vi, k={}
tmm = os.clock()
for i=1, 1000 do
  vi,k=FindRGBold(addr,len,0,0,0,0,999,999,"G-B[0 255]",10000000)
end
log(os.clock()-tmm)  -- 22.037 сек.
tmm = os.clock()
for i=1, 1000 do
  vi,k=FindRGB(addr,len,0,0,0,0,999,999,"G-B[0 255]",10000000)
end
log(os.clock()-tmm)   --15.357 сек.
tmm = os.clock()
for i=1, 1000 do
  vi,k=ImageToArray(addr,len,0,0,0,0,999,999)
end
log(os.clock()-tmm)   --7.139 сек.

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

Автор: DarkMaster 22.11.2018, 21:27

Цитата
local _,_,RG1,RG2=usl:find("R%-G%[(%-*%d+)%s*(%-*%d*)")
local _,_,RB1,RB2=usl:find("R%-B%[(%-*%d+)%s*(%-*%d*)")
local _,_,GB1,GB2=usl:find("G%-B%[(%-*%d+)%s*(%-*%d*)")
end
function Find2(usl)
local r1,r2=usl:match("R%((%d+)%-*(%d*)")
local g1,g2=usl:match("G%((%d+)%-*(%d*)")
local b1,b2=usl:match("B%((%d+)%-*(%d*)")

Почему такое принципиальное нежелание использовать таблицы, а не строку для передачи параметров?

Автор: sutra 23.11.2018, 1:08

Цитата
Почему такое принципиальное нежелание использовать таблицы, а не строку для передачи параметров?

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

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

Цитата
у меня нет вызовов файнда в цикле

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


Хотя, что-то мне подсказывает, что в ближайшее время тебе будет не до примеров. rolleyes.gif

Автор: sutra 23.11.2018, 1:29

И опять же, я же не зря потестил всё. Полноценный разбор строки составляет менее 300 микросекунд. Даже на дохлом камне и то это всё мгновенно будет, ну а Cirus-а вообще наверное всё должно летать. Хотя если научите, конечно сделаю и таблицей.

В принципе получилась замечательная вещь. Я переделал свой распознаватель текста и уверен, что могу сделать любой распознаватель, который с помощью вот такого файнда будет всё распознавать намного быстрее, чем делается getimage.

Автор: sutra 23.11.2018, 2:42

Вот если бы ещё и getimage через ffi прикрутить, вот это была бы суперскорость, только сдаётся мне что получить доступ к окну быстро всё равно не получится, наверняка всё делается как обычно через "третьи" руки, а значит однозначно тормоза.

Автор: DarkMaster 23.11.2018, 6:11

Цитата

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

Дык я же писал. Ща еще раз smile.gif
Код
function FindRGBold(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)
  local n=math.min(numf,(fx2-fx1+1)*(fy2-fy1+1))
  local arr = ffi.new("rgba_pixel[?]", n )
  local r1,r2=usl:match("R%((%d+)%-*(%d*)")
  local g1,g2=usl:match("G%((%d+)%-*(%d*)")
  local b1,b2=usl:match("B%((%d+)%-*(%d*)")
  local RG1,RG2=usl:match("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local RB1,RB2=usl:match("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local GB1,GB2=usl:match("G%-B%[(%-*%d+)%s*(%-*%d*)")
end

-- Usl у нас теперь таблица, а не строка.
-- Задаем только те параметры которые нужны.
-- Остальные можно дописать в теле таблицы умолчательными.
local usl = {r1=10, r2=12, GB2=32}

-- Объявление функции не меняется. Тело:
function FindRGBold(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)
  local r1 = usl.r1
  local r2 = usl.r2
  local g1 = usl.g1
  local g2 = usl.g2
...
  local GB2 = usl.GB2

На самом деле, как вы уже, наверное догадались, смысла в подобном присвоении, немного и на самом деле можно напрямую использовать usl.r1 и другие параметры. В стандартном случе не требующим большой производительности это действительно было бы так. В нашем же случае все более требовательно. Поясню:
Код
local arr = {10,11,22} -- мы создали одномерный массив на 3 элемента. Это именно массив, находящийся одним неразрывным куском в памяти.
log (arr[1]) -- вывод первого элемента массива, отсчет с единицы.
local t = {first=10, second=11, third = 22} -- мы создали таблицу, которая размазана по памяти.
log (t.first) -- вывод первого элемента таблицы.

А теперь собственно главное:
arr[1] и t.frist - какая разница кроме написания? Разница во времени обращения. Она отличается в 1.7 раза (по данным luajit.org).
Дело в реализации данных конструкций.
arr - как я уже говорил это просто кусок памяти, где последовательно записаны значения. Отсюда и скорость работы с ним.
t - это массив _ключей_ аналогичный arr и ссылок на данные. Т.е. в случае с t у нас в памяти одним куском записан массив структур:
ключ1 = адрес_данных1, ключ2 = адрес_данных2, ключ3 = адрес_данных3
Соответственно, чтобы получить непосредственно данные приходится искать нужный ключ в массиве, потом считывать адрес и только потом получать данные.
Массивы быстрее, если необхоимо последовательно обрабатывать данные последовательно (наш случай).
Работа с таблицами бывает быстрее, если необходимо удалять/добавлять объекты не в конце/начале массива. В случае с массивом он должен будет полностью перестроен в памяти заново, в случае же с таблице перестроен будет только массив ключей (может и не перестроен, зависит от реализации).
Скорость переменных относительно массивов не знаю, не тестил.
Немного теории которая может быть не актуальной из-за особенностей реализации и jit оптимизации. Есть очень важный момент - чем больше таблица тем медленнее работает поиск ключа. Какое отношение это имеет к переменным? В lua самое прямое. Даже если вы объявлете переменную, то на самом деле объявляете элемент скрытой таблицы. В луа все является таблицей. Для увеличения быстродействия может быть полезно не создавать много переменных, а часть данных помещать в таблицу, т.к. созданные переменные будут неизбежно замедлять общую скорость работы. Я когда-то давно обнаружил в lua подобное снижение производительности и даже на форуме с cirus это обсуждал. Там что-то было про регекспы и os.clock(). Вопрос на тот момент остался повисшим и тогда причин я не знал, тесты не все были полностью однозначными и производительность явно "гуляла". Гуляла она скорее всего из-за изменения порядка переменных в скрытой таблице луа (порядок элементов там не гарантируется).


И так мы задали часть параметров таблицей local usl = {r1=10, r2=12, GB2=32}. Все параметры мы писать едва ли захотим, да и читаемость будет не очень. Нам нужно задать параметры по умлчанию. Тут есть два основных пути:
Задание параметров по умолчанию вариант 1
-- Проверяем существует ли поле в таблице, если нет, то присваиваем значение по умолчанию.
Код
local r1 = usl.r1 or 10

or и and можно использовать не самым очевидным образом в луа. Эти операторы на самом деле возрващают значения.
var1 or var2 работает следующим образом:
Код
if var 1 then
    return var1
else
    return var2
end

var1 and var2 работает следующим образом:
Код
if var 1 then
    return var2
else
    return var1
end

Способ хороший, наглядный.


Задание параметров по умолчанию вариант 2

Мы можем наглым образом объявить значения таблицы, а потом перезаписать имеющимися:
Код
local function fcolor(my_var)
    local var = {n1=1, n2=2, n3=3, n4=4}    
    for k, v in next, my_var do  -- Перебираем все ключи и значения таблицы t2
        local var[k]=v           -- Подменяем значение с таким же ключем.
    end
end

local my_var = {n2=20, n3 = 30}
fcolor(my_var)

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



Можно пойти дальше и довести все до логичного завершения - поместить все эти данные в массив или структуру Си. Ну это у вас уже реализовано. Хотя лично мне кажется более логичным сначала создать структуру, а потом уже непосредственно в нее помещать данные не создавая временные lua переменные r1-GB2. Не забываем, что они могут замедлить выполнение всей функции. В идеале я бы вообще в рамках функции которая осуществляет непосредственный перебор оставил только одну си-структуру или си-массив, чтобы исключить все возможные проблемы.
Структура си, по идее не должна иметь разницы по скорости относительно массива си не смотря на то, что поля там текстовые, читаемость повысится.

Автор: sutra 23.11.2018, 9:58

Цитата
В идеале я бы вообще в рамках функции которая осуществляет непосредственный перебор оставил только одну си-структуру или си-массив

Я тоже конечно думал на эту тему. Но, как я уже говорил, мой опыт в СИ - нулевой, ну и главный демотиватор - мне просто жаль убивать своё время, его не так много осталось, а овчинка выделки не стоит. В идеале можно вообще полностью с нуля написать свою программу, НО ЗАЧЕМ? Если у нас уже есть Пилот, который в подавляющем большинстве случаев делает свою работу "на ура". У меня была всего одна проблема - скорость при обработке динамично меняющегося изображения, я её с твоей и божьей помощью с блеском решил. Да и проблема то во многом была из-за пост-обработки (анализа данных) изображения. При переходе на lua - проблема "ПОСТ" - просто исчезла. Спасибо Дарк, что потратил на меня столько времени, я многому научился.

Автор: sutra 23.11.2018, 10:11

Скорость обработки порядка 40 кадров в секунду меня более чем устраивает. Перелопачивание массивов пикселей требовалось только при распознавании символов, но там требования к скорости были не критичны, хотя и в этом направлении результат получился супер. До сих пор пока ещё запускаю параллельный скрипт и то время выполнения менее 3 сотых сек. Так что пока наверное я остановлюсь на достигнутом. Надо скрипт переделывать на lua, а скрипт ой какой не хилый, думаю даже за месяц не управлюсь.

Автор: DarkMaster 23.11.2018, 14:04

Цитата
а овчинка выделки не стоит.

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

Маленький совет. Все финдколоры, финдимиджи выносить сразу в шапку скрипта в отдельную таблицу, открытие менюшек тоже делать таблицу с функциями. Это уже просто шишки набитые. Все равно в итоге придете к этому либо бардак будет. Слишком много однотипной писанины, а вызов финдов в этой писанины потом к проблемам приводит, т.к. одинаковый финд может быть востребован в нескольких местах, а при изменении области/погрешностей выискивать каждый финд заново бывает запарно и высока вероятность появления двух разных по содержанию финдов ищущих одно и то же.
local fi, fc, open, click = {},{},{},{}
Это у меня из сохраненного шаблона скрипта.

Автор: sutra 7.12.2018, 5:47

Не дождался я фикса на findimage, нацарапал свой, используя СИ-шные переменные. Ещё раз огромное спасибо Дарку. Доморощенный, без наворотов findimage работает примерно в 130 раз быстрее (100 раз искал картинку в цикле поиска 26 картинок - всего 0.009 сек). Кстати, у Кнайта скорость ОЧЕНЬ сильно зависит от параметра deviation, чем он больше, тем медленнее. А этот параметр я использую практически всегда. Мне не совсем понятно почему такая зависимость, видимо шибко хитрый и мудрёный алгоритм.

Автор: sutra 7.12.2018, 13:54

Всё-таки офигительную штуку подсказал мне Дарк. Раньше при многоступенчатом выборе тех или иных действий приходилось выставлять ожидание до 300 миллисекунд после клика, для гарантированной связи с сервером и отрисовки нового изображения на экране. Теперь сделал собственную функцию LeftWait, которая перед кликом запоминает определённую область экрана и после клика - ждёт обновления экрана, прежде чем вернуться в основное тело скрипта. Результат? Теперь всё просто "летает", ждёт ровно столько, сколь нужно.

Автор: DarkMaster 7.12.2018, 16:54

Цитата
Теперь сделал собственную функцию LeftWait, которая перед кликом запоминает определённую область экрана и после клика - ждёт обновления экрана, прежде чем вернуться в основное тело скрипта. Результат? Теперь всё просто "летает", ждёт ровно столько, сколь нужно.

Это при условии, что приложение нормальное. Частенько клики проходят через раз, вместо одного окна выбивает другое, слишком ранние контрольные клики приводят к морганию новых окон, быстрые клики к зависанию crazy.gif Так что могу поздравить с приложением smile.gif
А что не так было в финдимидже то? Он работает на ура. Проблемы некоторые есть с координатами из-за рамки, вроде проблемы еще были при поиске через getimege (координаты съезжали), но там можно было ручками фикисть да и вроде уже исправлено. У меня этот метод просто засунут в другой скрипт который постоянно используется, а потроха я уже точно не помню, как именно используют его.

Автор: sutra 7.12.2018, 23:00

Цитата
А что не так было в финдимидже то?

Ну cirus показывал что не так. И по скорости очень много вопросов. Точно по "нужной" области финд работает некорректно, приходится расширять зону поиска, а это приводит к потере скорости. Как я говорил, у меня есть ситуации, когда приходится ставить deviation 6%, можешь потестить сам и удивишься, как сильно падает производительность, в своём финде, мне наплевать какая разница в цветовых каналах, я даже сам не ожидал такой скорости, ну очень быстро. Я знаю где лежит искомая область для картинки, и для такого случая, когда не надо "бороздить просторы мирового экрана" поиск осуществляется практически мгновенно. Например для Сайрусовского распознавателя текстов при помощи картинок - это был бы прорыв.

Автор: sutra 7.12.2018, 23:15

Цитата
Частенько клики проходят через раз

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

Автор: sutra 12.12.2018, 1:24

Цитата
if numf==k then return arr, k end

Вот из-за такой мелочи убил несколько часов. В новой версии Пилота просто вылетал lua, попробовал на предыдущей версии и получил реальную ошибку. Фишка в том, что ошибка проявлялась намного позже её совершения, поэтому пришлось ВСЁ перелопатить, сидел и думал - ... есть причина, ... должна быть причина ... А причина как всегда - или нолик, или единичка. Надо было так:
Цитата
if numf-1==k then return arr, k end
Видимо никто не пользовался моей фигнёй, ну или стряпали свою.

Автор: sutra 12.12.2018, 3:55

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

Дарк в своё время ткнул меня носом, что индексация массива начинается с нуля, вот тупо и поменял нолик на -1, а посмотреть весь код функции поленился, вот и результат, "как не надо на фиг делать".

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

Автор: sutra 12.12.2018, 4:20

Дарк, я тут забубенил свой файндимидж (я уже говорил). Решил проверить как будет работать на 1000+ картинок, вместо вызова внешней проги (которая джипеги смотрит). Пока толком не тестировал на скорость, но присобачил элемент самообучения. Идея такая, может тебе пригодится. У меня deviation не в %, а разности каналов RGB, с точностью до 1. Использую файл конфигурации, в который записывается этот deviation. Ищет например с нулевой погрешностью, если не находит картинку, увеличивает погрешность и так пока не найдёт картинку. Результат записывает в файл конфигурации и в дальнейшем использует именно эту погрешность. Смысл? Чем меньше погрешность, тем быстрее осуществляется поиск. На большом объёме картинок прирост уже проявляется. Раньше просто делал погрешность с запасом, теперь ровно такая, какая нужна.

Предположительно (когда все картинки соберу) скорость поиска будет максимум 2-3 сотых секунды, сопоставимо с той какая у меня сейчас, но есть плюс - алгоритм железобетонный, будет искать как надо со 100% вероятностью надёжного поиска.

Автор: sutra 12.12.2018, 9:36

Попробовал подключить модуль lua, ничего у меня не получилось.

Автор: DarkMaster 12.12.2018, 11:40

Цитата
У меня deviation не в %, а разности каналов RGB, с точностью до 1

Еще раз расскажу эту историю-байку. Дело было во время написания финдимиджа. Кнайт предлагал сделать погрешность в единицах rgb, я предлагал сделать в % (там кстати не проценты нужны, а хотя бы промилле). Но проценты должны были отражаеть соотношения каналов. Т.е. по сути не просто разнобой цветовых отклонений, а светлее-темнее. Мы друг друга недопоняли и получилось вот такое историческое наследие wink.gif

Цитата
Попробовал подключить модуль lua, ничего у меня не получилось.

Как подключал, что не получилось?

Правильным будет создание файла в котором будет описана некторая функция/массив функций/параметров. В конце файла просто делается return с этим творением(функцией/массивом).

Автор: sutra 12.12.2018, 15:47

Я хотел ВСЕ свои функции поместить в отдельный файл и как-то сделать их доступными из любой вкладки Пилота, чтобы не таскать их в каждую вкладку. И если что-то изменил в какой-либо функции - это "поняли" бы все скрипты, а то опять можно ошибок накрошить.

Грубо говоря без хотя бы простенького примера думаю не разберусь. 2 вопроса. Что нужно изменить в самом файле? Про ретурн уже понял. Но всё равно нужен примерчик. И как подцеплять типа require.

Автор: DarkMaster 13.12.2018, 0:54

Код
local my_func = {}

my_func.show = function()
    ...
end

my_func.hide = function()
    ...
end

return my_func

ну и уже во кладках подгружаем:

Код
local f = require [[lua_plugins\my_func]]

f.show()
f.hide()

Автор: DarkMaster 13.12.2018, 3:16

Цитата
Использую файл конфигурации, в который записывается этот deviation. Ищет например с нулевой погрешностью, если не находит картинку, увеличивает погрешность и так пока не найдёт картинку. Результат записывает в файл конфигурации и в дальнейшем использует именно эту погрешность. Смысл? Чем меньше погрешность, тем быстрее осуществляется поиск. На большом объёме картинок прирост уже проявляется. Раньше просто делал погрешность с запасом, теперь ровно такая, какая нужна.

Точно так же будет влиять и точность. По большму счету тут точность основопологающий параметр, поднимая дивиэйшн мы просто начинаем попадать в эту самую точность и получать обработку бОльшего количества пикселей пока из-за точности не оборвется. Это я к чему. Увеличивая точность можно добиться так же очень хорошего роста производительности. И тут уже нужно подбирать верное соотношение этих параметров. Т.е. я предлагаю анализировать не только deviation, но и accuracy и их сочетания. Да, будет дольше проверять, но тем не менее.
Так же по личному опыту могу сказать, что, как правило, гораздо бОльшее значение имеет задание минимально возможной области поиска и минимально возможного изображения. Так же обработка изображения чрезвычайно повышает производительность. Под обработкой имеется ввиду обрезка и закраска не несущих полезной информации частей. Если делаешь подобный анализ, то крайне рекомендую сохранять изображения с явным указанием на совпавшие части и не прерывать его по accuracy во время анализа для сохранения отпечатка, который совпал. Это очень сильно поможет в понимании происходящего и того, какие действительно параметры нужны и как следует обработать изображение.

Автор: sutra 13.12.2018, 5:01

Спасибо Дарк за инфу. Пробовать буду завтра (точнее уже сегодня, но позже).

Цитата
Т.е. я предлагаю анализировать не только deviation, но и accuracy и их сочетания

Всё верно ты мыслишь, конечно нужно уменьшать область поиска, этим я и занимаюсь. Не зря даже делал картинки по 1 пикселю в высоту (или ширину). Только пришлось руками их делать. У Кнайта тут косяк. Если честно, то я не понимаю принципа работы параметра accuracy. Но сдаётся мне именно на него заточен алгоритм и по моей логике он анализирует смещение картинки в искомой области. Иначе, попытка решить проблему за бестолкового юзера, который туго соображает чего и главное где ищет. Иначе я не могу объяснить падение скорости при увеличении deviation. Лично в моём случае, точнее во всех моих случаях, мне accuracy не нужен. Возможно он анализирует также общее отклонение цветовой гаммы. В любом случае, на мой взгляд, deviation НАМНОГО актуальнее. Именно он помогает бороться легко, просто и эффективно с рендерингом, но конечно это для случая когда точно известно местоположение картинки (именно мой случай, я не люблю, когда чего-то не знаю).

Ну а скорость меня теперь уже мало интересует, если знать чего искать, да хоть 10 тыс. картинок за 2 сотых перелопачу, если их проиндексировать. Благо в lua нет проблем по скорости с циклами. Индексировать можно по чему угодно, по месту применения в скрипте ... по количеству фона в картинках (что например может говорить о количестве символов в картинках содержащих текст), ну и т.д. Для себя я этот вопрос однозначно решил, всё меня устраивает.

Цитата
Увеличивая точность можно добиться так же очень хорошего роста производительности

Ну и поскольку я не знаю как реализован алгоритм этой точности, у меня его естественно нет. Всё-таки повторюсь, тут Кнайт просто хотел добиться универсальности поиска, ну чтобы ИСКАЛО. Но по скорости он сильно уступает СИ-шным массивам, поэтому тут вообще не возникает вопросов чем пользоваться.

Автор: DarkMaster 13.12.2018, 7:01

Цитата
не понимаю принципа работы параметра accuracy

Количество_совпавших_пикселей / Количество_пикселей_в_картинке_кроме_фона

Цитата
Ну а скорость меня теперь уже мало интересует

А я тут хотел предложить еще и распраллелить =)

Автор: sutra 13.12.2018, 14:53

Цитата
Количество_совпавших_пикселей

Ну и как мы будем отличать 0 от О.


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

А вот deviation моментально бы нашёл отличия. Не понимаю почему скорость зависит от его значения.

Автор: DarkMaster 13.12.2018, 15:10

общая схема работы в моем понимании такова:
Пусть у нас дано изображение из 10 полезных пикселей.
Задна accuracy 90. Т.е. в нашем случае требуется совпадение не менее 9 пикселей.
Область дана в которой изображение может быть найдено в 20 наборах координат.
Финдимидж берет первую точку в заданной области и начинает попорядку сверять все 10 пикселей.
Как только количество допустмых ошибок превысит ограничение (у нас это 10-9=1), то происходит переход к следующей точке.
Справедливо и обратное, как только найдено 9 сопадений, то попытки найти 10 не будет - засчитается совпадение.

Таким образом, поскольку минимальное количество несовпадающих пикселей для позиции равно 2, а позиций у нас 20, то как минимум будет проверено 40 точек (при условии, что вообще нет никаких совпадений по цветам).
Допустим мы уменьшим параметр accuracy до 70. При этом количество ошибок должно быть не менее 4 (10-10*70%+1), чтобы изображение считалось не совпавшим. Позиций у нас все так же 20, но теперь количество проверок точек уже будет не менее 4*20=80. Вот таким не хитрым способом мы посадили производительность до двух раз.

Тем не менее очевидно, что у нас будут не только крайние случаи, но и частично совпавшее начало и отбраковка уже на середине. Напрмер, 3 пикселя в начале совпало, а только потом 4 уже были отбракованы.

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

Автор: sutra 13.12.2018, 15:23

Цитата
Причем тут deviation?

Да как причём? Пока таким способом искать количество, deviation отбракует вариант на ПЕРВОМ же неугодном пикселе. Ну или я тупой вообще, но реальный поиск у меня работает ну просто на ура.

Автор: DarkMaster 13.12.2018, 15:30

Цитата
Да как причём? Пока таким способом искать количество, deviation отбракует вариант на ПЕРВОМ же неугодном пикселе. Ну или я тупой вообще, но реальный поиск у меня работает ну просто на ура.

accuracy какой при это задаете? 100? Отбракуется он на первом только при высокой контрастности обязательно заданным accuracy равном 100. Поверьте, есть приложения в которых я искал баланс между этими двумя параметрами неделями и месяцами, т.к. контраст был низкий, а рендер ездил во все стороны, как итог все изображение сливалось для пилота.

Автор: sutra 13.12.2018, 16:07

Да, 100

Возможно есть хитрые картинки, не знаю. Если картинки сильно плавают - ничего не поможет. В любом случае будут якоря.

Точнее у меня нет аккуратности, я просто анализирую заданную разность RGB.

Код
--lua
local ffi=require "ffi"                                                        -- Использование модуля ffi для использования СИ структур
local rmem=ffi.cast                                                            -- Использование функции чтения из памяти модуля ffi
ffi.cdef[[typedef struct{uint16_t x,y; uint8_t red,green,blue;}xyrgb]]         -- Определение структуры массива чтения данных из памяти образа картинки
local function ImageToArray(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2)              -- ЧТЕНИЕ ВСЕХ ПИКСЕЛЕЙ В ОБЛАСТИ ПАМЯТИ
  local n=(fx2-fx1+1)*(fy2-fy1+1)                                                -- Определение максимальной размерности возвращаемого функцией СИ массива считанных пикселей
  local arr=ffi.new("xyrgb[?]",n)                                                -- Инициализация СИ массива искомых пикселей (используя ранее описанную структуру)
  local s=ffi.new("uint8_t[3]")                                                  -- Инициализация СИ массива из 3-х элементов типа беззнаковый байт для чтения из памяти значений пикселей RGB
  local k,indY,ind,r,g,b=-1
  for i=fy1,fy2 do
    indY=addr+(i-scrY1)*len
    for j=fx1,fx2 do
      ind=indY+(j-scrX1)*3
      s[2]=rmem("unsigned char*",ind)[0]
      s[1]=rmem("unsigned char*",ind+1)[0]
      s[0]=rmem("unsigned char*",ind+2)[0]
      k=k+1 arr[k].x,arr[k].y,arr[k].red,arr[k].green,arr[k].blue=j,i,s[0],s[1],s[2]
    end
  end
  return arr,k
end
local function ImageCompare(pl,wl,hl,ll,pg,lg,x,y,fx1,fy1,fx2,fy2,dev)
  local arl,arg,kl,kg={},{}
  arl,kl=ImageToArray(pl,ll,0,0,0,0,wl-1,hl-1)
  arg,kg=ImageToArray(pg,lg,x,y,fx1,fy1,fx2,fy2)
  for i=0,kl do
    if math.abs(arl[i].red-arg[i].red)>dev or math.abs(arl[i].green-arg[i].green)>dev or math.abs(arl[i].blue-arg[i].blue)>dev then
      return 0
    end
  end
  return 1
end


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

pl - адрес картинок pg - адрес getimage соответственно ll и lg - длина для них и т.д. разберешься в общем.

Конечно там доделывать всё надо, это чисто для тестов. У меня на вскидку получилось в 130 раз быстрее.

Фона нет, по барабану. Поиск до первого "неугодного" пикселя.

И смею заметить это ещё лишнее движение по получению массива из образа. Хотя его можно получить только один раз. Ну чисто для теста, не доделано. Следовательно будет ещё быстрее.

Загрузка картинок в память выполняется намного медленнее самого поиска, примерно вот так.

Код
tmc=os.clock()
for j=1,100000 do
  for i=1,19 do
    if 1==ImageCompare(U[i],uw[i],uh[i],ul[i],p,l,455,915, 461,925,489,932, 153) then nnn=i break end
  end
end
log(os.clock()-tmc)  -- 9,424 сек.
log(nnn)


Здесь deviation 153. Сделал 5 - результат ТОТ ЖЕ. Видимо картинки качественные.

Эх! Забыл, искалась картинка №18, ну почти по максимуму.

Автор: cirus 13.12.2018, 16:08

Цитата
Загрузка картинок в память выполняется намного медленнее самого поиска

Это разовая операция. Да хоть секунду пусть грузятся, потом всё равно работа с памятью.

Автор: sutra 13.12.2018, 16:20

Цитата
Это разовая операция

Ну конечно. Это уж я так, чисто для сравнения. Если что придумаете новенького или найдёте косяки, маякните.

Картинки кстати, те, которую из них и ты тестил на Кнайтовском финде.

Но я проверял на многих, в том числе на реальных картинках, с приличным рендерингом - результат всё равно супер. Конечно в плавающих координатах будет намного медленнее, возможно сделаю раздельные функции поиска.

Конечно от камня сильно зависит, но у тебя cirus будет всё однозначно лучше.

Автор: sutra 13.12.2018, 18:14

Цитата
local my_func = {}my_func.show = function()

Спасибо Дарк. Всё как обычно просто (когда уже знаешь). Всё работает. По привычке тестанул новые возможности. Тормозов при использовании внешнего файла не выявлено, потерь скорости нет, а вот плюс очевиден. Ещё раз огромное спасибо.


Закинул свой файл в папку Scripts и забыл... Во всём люблю порядок.

Автор: sutra 13.12.2018, 21:14

Ловить количество пикселей - очень рискованная идея. А вот такие вещи как будет отличать 1 или l (единица или L) особенно если посмотреть на их шрифт в том же Пилоте. Не пробовал, просто лень, но если ищет количество пикселей, то ни хрена не отличит.

И не только в Пилоте, гляньте на шрифт цитат...

А мой убогий алгоритм отличит железобетонно.

Думаю ты ошибаешься Дарк, если приоритет количество пикселей, тогда при поиске таких картинок "123" и "321" количество пикселей будет практически одинаковым. Сдаётся мне там более хитрый алгоритм.

Во всяком случае, чисто для борьбы с рендерингом достаточно параметра deviation. А вот если гамму отлавливать - это другая песня.

Автор: sutra 13.12.2018, 22:06

Кажется я понял какая была изначальная идея, искать картинки символов, на которые не рендеринг влияет, а сглаживание шрифтов. Ой, какая плохая идея. У меня совсем иная реализация, ну а если уж делать поиском картинок, тогда для каждого символа может потребоваться и 5 и может даже и больше картинок. Да, делать такие картинки муторно и время убьёшь, но за то со скоростью не будет проблем. Переделал свой финд, как и планировалось скорость выросла в 2 раза.

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

Автор: sutra 13.12.2018, 22:17

На мой вгляд (на перспективу, вдруг добьёшь компиляцию) надо сделать 2 раздельные функции, для неприхотливых сделать скромную SingleFind (скоростную) и не рекламировать её, просто пусть будет. А для всех остальных сделать функцию SmartFind.

Автор: sutra 13.12.2018, 22:40

Нет, не сингл, а SpeedFind.

Выбор чем пользоваться оставить за юзером.

Юзер попробует и сделает для себя вывод ... юзер он или лузер. biggrin.gif

Автор: DarkMaster 13.12.2018, 22:57

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

Они идут в подавляющем большинстве рука об руку и все эти наложения через deviation без очень большого диапазона не поймаешь с точностью выской. А так пару самых двинутых точек проигнорировал и пошел дальше.
Цитата
Думаю ты ошибаешься Дарк, если приоритет количество пикселей, тогда при поиске таких картинок "123" и "321" количество пикселей будет практически одинаковым.

Почему? Пиксели то дожны быть на своих позициях. Написать вместо 123 321 для скрипта примерно тоже самое, что вместо 123 написать 824 (сглаживание, рендеринг не трогаем). Все гораздо хуже бывает в 3 и 8, 4 и 1, 7 и 1, самый ужас O и Q. И вот там действительно большие ограничения. От шрифта еще очень много зависит. В целом для текста я ставлю обычно 97-98% точность, при крупном кегле можно до 95 сбросить. Так же очень важно бывает правильно обтравить изображения. Поэтому я и говорил, что подобный анализ не помешал бы.

Автор: sutra 13.12.2018, 23:52

Цитата
Все гораздо хуже бывает в 3 и 8, 4 и 1, 7 и 1

Знаю, знаю. Ещё хуже когда стоит цифра между 2 или 7. Типа 282 или 787. Двушки портят низ, семёрки верх. Но я говорил, я просто по реперным точкам смотрю. Для той же Q - есть своя "неубиенная" точка. И повторюсь, мой нехитрый и при этом быстрый алгоритм ну никак он не пропустит хвостик от Q даже с диким deviation. Конечно сейчас я говорю во многом голословно, может есть очень хитрые тексты. При случае обязательно поэксперементирую. Для моего алгоритма болезненно если реально плавают символы. Специально соберу коллекцию таких текстов и что-то мне подсказывает, что проблема возникнет и у Кнайтовского финда. Как уже говорил, на мой взгляд, понадобится несколько вариантов написания символов. И опять же, вот допустим рядовой, тупой юзер. Ну как он будет определять сколько дать аккуратности, а сколько погрешности. Я уж не самый тупой и то не очень понимаю.

Я поначалу (когда был совсем тупой) пробовал всяко и частенько финд либо не мог найти, либо находил не то, что требовалось, а это ещё хуже. Должно искать, искать железно, 100%. Я решил эти вопросы - мгновенно и 100% (конечно благодаря lua) В Пилоте тоже было 100%, но требовалось до 7 десятых секунды.

Конечно может я бы так и остался тупым. Но, к счастью, на форум я залез когда уже скрипт был готов на 99%. Оставалась одна нерешенная проблема (она ещё до сих пор не решена). И я смотрел новые версии Пилота (апгрейд работы с памятью смотрел) и просто решил полазить по форуму и увидел cirus-овский скрипт. Но когда ты мне дал этот неубиенный инструмент с массивами СИ, мне уже просто всё это не очень интересно. У меня куда сложнее задача осталась. Мне нужно составить математическую формулу ускорения, на основе статистики, это при очень нехилом разбросе данных. Но я обязательно её состряпаю эту формулу.

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

Автор: sutra 14.12.2018, 0:25

Подводя итог этой теме. У Кнайта фишка - это фон. Я же наоборот рассматриваю фон, как рабочий пиксель. При таком подходе хвост от Q ну никак не "проскочит" мимо. Теперь о минусах... Вот плавающие символы, вот тут да, мой алгоритм начнёт тупить, потому что та же единичка рисуется 2-3 мя палками. Одна тёмная, другая светлая и они в зависимости от знакоместа меняются местами (плавают). Тут я точно не могу сказать как лучше, использовать Кнайтовский финд или сделать несколько вариантов картинок для моего алгоритма (думаю 3-х вариантов будет достаточно).

Ну а для поиска реальных картинок, могу конечно ошибаться, но сколько не пробовал мой вариант однозначно ищет 100% и как минимум быстрее. Потому что у Кнайта использование deviation начинает очень сильно тормозить.

Сильно тормозить - это в разы, а не на 15-20%.

Автор: sutra 14.12.2018, 1:09

Не поленился ещё раз потестил:

Код

tmc=os.clock()
local argg,kg=fn.ImageToArray(p,l,455,915,461,925,489,932)
for j=1,10000 do
  for i=1,19 do      -- картинки размером 29 х 8
    if 1==ImageCompare(U[i],uwid[i],uhei[i],ulen[i],argg, 27) then nu=i break end
  end
end
log(os.clock()-tmc)                   -- 0.477 сек.

local ar,err={}
tmc=os.clock()
local p1,w,h,l=getimage(461,925,489,932,ok[1][1])
for j=1,1000 do
  for i=1,19 do      -- картинки размером 29 х 8
    ar,err=findimage(0,0,27,8,{U[i]},p1,100,1,0)
    if err==100 then nk=i end
  end
end
log(os.clock()-tmc)                    -- 5.628 сек  (в 10 раз меньше картинок)

for j=1,1000 do
  for i=1,19 do      -- картинки размером 29 х 8
    ar,err=findimage(0,0,27,8,{U[i]},p1,100,1,7)
    if err==100 then nk=i end
  end
end
log(os.clock()-tmc)                    -- 13.644 сек  (в 10 раз меньше картинок)


Как и говорил, deviation действует на алгоритм гипнотически, причин я не понимаю, видимо действительно вторичный параметр, что НА МОЙ ВГЛЯД неправильно.

Именно тормоз deviation заставил меня рисовать свой финд.

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

Автор: DarkMaster 14.12.2018, 2:16

Цитата
Вот плавающие символы, вот тут да, мой алгоритм начнёт тупить, потому что та же единичка рисуется 2-3 мя палками.

Даже при кнайтовском финде словарь доходил до 250 картинок и не 100% результате.
Цитата
Я же наоборот рассматриваю фон, как рабочий пиксель.

Полупрозрачный игровой чат со сглаживанием и рендерингом. Без deviation и accuracy можно не пытаться smile.gif
Я не спорю, есть частные случаи, но они, к сожалению, на то и частные, что встречаются не всегда.Финдимидж комбайн и им можно очень много сделать. На мой взгляд этому комбайну не хватает изначальной задумки с яркостью (соотношением каналов). По части скорости... Я допускаю, что там могут быть какие-то существенные тормозящие моменты, но у меня есть сомнения. Скорее всего в первую очередь все обусловлено именно площадями, точностью. Там кстати есть еще предварительный анализ искомого изображения, что негативно скажется на большом количестве вызовов в маленькой области. В целом - знает только кнайт. Вообще учитывая, что в примитивном виде код очень невелик, а финды так и не пересобрались из-за масштабности работы, то видимо там все не очень просто, возможно связано со старым синтаксисом, но это мои догадки.

Автор: sutra 14.12.2018, 2:44

Цитата
Полупрозрачный игровой чат со сглаживанием и рендерингом

Я бы даже не думал - однозначно для такого случая анализ реперных точек. Извращаться с имиджем при таких условиях - дело неблагодарное.

Стандартными средствами в любом случае будет небыстро, имея на руках СИ-шный инструментарий, придётся конечно ковыряться, но задача 100% решаема, со 100% результатом.

Автор: DarkMaster 14.12.2018, 7:00

Прикрепленный файл  0_big.bmp ( 66,05 килобайт ) Кол-во скачиваний: 138

Вот и что с одним deviaton тут делать? Вот эта вот радуга фактически может в любую сторону плавать. При комбинации с accuracy получается хотя бы проглатывать крайние положения.

Автор: sutra 14.12.2018, 16:48

Цитата
Вот и что с одним deviaton тут делать?

Вопрос как плавает радуга по цветам, НО пиксели фона - они и могут решить проблему. И всё-таки я ошибался, когда говорил, что у Кнайта погрешность вторичный параметр, просто по логике он не может быть вторичным. Как раз он первичный и чем меньше он пикселей забраковал, тем ДОЛЬШЕ с ними возится параметр аккуратности, отсюда и тормоза. Кстати, есть у меня такие радуги, вроде как всё у меня ищет. Да посмотри, я даже тестовый пример приводил, я там ищу с погрешностью 153 - это +- 153 (более половины всего диапазона) и находит без ошибок. Я дал конкретный код, ты пробовал им??? Я конечно не Кнайт, я и 10% не знаю, того, чего знает он. Но надеюсь, что мои доводы, помогут ему найти сбалансированное и эффективное решение.

И даже скажу где эту радугу ставлю на место, да посмотри тот же микшер (сразу оговорюсь под WIN7), там мама не горюй какой шрифт у надписей, но при грамотном подходе, всё решаемо. Нельзя сделать супер-пупер функцию, которая бы сама думала за всех юзеров. Кнайт дал инструмент, но если молоток в руках не держал - доверь специалисту. Ну вот ты пишешь? И даже не только для себя, я уверен, ты сможешь. А кто не может, нечего и соваться.

Автор: DarkMaster 14.12.2018, 16:50

Цитата
я там ищу с погрешностью 153 - это +- 153 (более половины всего диапазона) и находит без ошибок.

Проблема в том, что меня интересуют те случаи, когда deviation в +/-7%, т.е. +/-18rgb приводят к ложным срабатываниям. Ну вот такая вот там хрень.
Цитата
Но надеюсь, что мои доводы, помогут ему найти сбалансированное и эффективное решение.

Как минимум меня заинтересовал и я сидел в фоторедакторе и искал способы решить поставленную задачу. Вроде даже решил. Остался вопрос самому огород городить либо все это запихается в find(бабушкааа).

Автор: sutra 14.12.2018, 17:06

Цитата
в +/-7%, т.е. +/-18rgb

А аккуратность при этом КАКАЯ???

Цитата
Остался вопрос самому огород городить либо все это запихается в find(бабушкааа).

Аналогично!


Просто не стоит ещё доверять собственному субъективному мнению. Логику процесса я озвучил. Искать с увеличением погрешности, до тех пор, пока не найдёт. Будут ложные срабатывания - значит нужна дополнительная картинка с новым вариантом. Главное скорость то позволяет лопатить без ограничений.

И ещё раз повторюсь, да не получится нарисовать финд, который будет искать всё. Это всего лишь прога (алгоритм), просто теоретически метод поиска чисто путём тупого перебора не способен искать как надо. Что мы первые что ли озадачились этим. А как файнридер ищет? А как распознавание лиц?? Только по реперным точкам. А вот где эти точки выставить, вот тут нужны мозги, статистика и труд...

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

Я полностью переделал все свои поисковые функции, даже аналог if 100 100 2345 сделал свой (кстати родной в lua не работает).

В смысле работает, но не ищет, может конечно сам чего не так делаю, но вроде всяко пробовал - плюнул, сделал свой.

Автор: cirus 14.12.2018, 17:10

Цитата
А как файнридер ищет?

OCR - оптическое распознавание символов. Там вообще не влияет шрифт, его размер или цвет.

Автор: sutra 14.12.2018, 17:17

Цитата
Там вообще не влияет шрифт

Естественно, отличается фон от остального. Там много чего наворочено, потому и работает в 10-ки раз медленнее наших алгоритмов, которые заточены под конкретику.


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

Автор: DarkMaster 14.12.2018, 17:18

Цитата
А аккуратность при этом КАКАЯ???

А там уже пофигу. Шмное изображение с очень маленькой градацией оттенка.

Автор: sutra 14.12.2018, 17:22

Показательно в этом случае распознавание лиц. Там однозначно реперные точки. Алгоритмы тоже на протяжении десятков лет совершенствуются.

Цитата
А там уже пофигу.

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

Автор: DarkMaster 14.12.2018, 17:25

Прикрепленный файл  cross.bmp ( 361,22 килобайт ) Кол-во скачиваний: 132

Вот пример. Наложен фильтр оттенка. Примерно так видит в данном случае deviation.

Автор: sutra 14.12.2018, 17:29

В нашем случае шрифт известен. Сглаживание - это тоже алгоритм, для своего случая я его вычислил на 100%, не более 7 вариантов написания символа, в зависимости от соседних, рендеринг побеждается погрешностью. Никаких проблем не вижу. Так у меня ещё и текст центрированный, мне приходится искать и начало и конец текста. И всё работает. Поначалу много было неизвестных, но статистика собиралась, неизвестные варианты добавлялись. В lua проблем нет. Распознаватель на 5 страницах, но работает быстро.

Автор: DarkMaster 14.12.2018, 17:35

Цитата
Распознаватель на 5 страницах, но работает быстро.

А мой чем не устроил?) Скоростью из-за стандартного финда?

Автор: sutra 14.12.2018, 17:47

Цитата
Вот пример. Наложен фильтр оттенка

Круто, я думал я самый упёртый, ан нет. Но если серьёзно, да мне всё равно, что там кто видит. Находит, значит видит, не находит, значит нет. У меня находит, возможно у меня намного более простые шрифты и "тепличные" условия. Значит мне повезло. Спорить я ни с кем не собираюсь. Я хотел бы только одного, если Кнайт сделает компиляцию, чтобы он оставил возможность что-то делать самому, просто сделав отдельную функцию без наворотов. Но если и не сделает, не вопрос, если уж я без lua изголялся и пусть небыстро, но решал практически любые задачи, то уж c lua думаю разберусь и с заковыристыми вопросами. Так что давайте закроем эту тему.

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

Автор: DarkMaster 14.12.2018, 17:47

Цитата
Так что давайте закроем эту тему.

Эх. Жаль. Давно не было таких интересных и продуктивных дискуссий.

Автор: sutra 14.12.2018, 17:56

Для текстов вроде ДА, даёт эффект аккуратность, для картинок наоборот, конечно можно также эпмирическим методом найти наилучший вариант для каждого случая, вот только как с потерей скорости??? В общем закрыли тему.

Цитата
Эх. Жаль. Давно не было таких интересных и продуктивных дискуссий.

Да брось, я ляпнул - ты ответил. Ну если скажете чего, поддержу, а из пустого в порожнее чего переливать то!!
biggrin.gif

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

Автор: DarkMaster 14.12.2018, 18:08

Цитата
Лично меня подкупила скорость обработки

Можно прикрутить поиск с помощью пользовательской функции =)

Автор: sutra 14.12.2018, 18:22

Цитата
Можно прикрутить поиск с помощью пользовательской функции =)

Ну всё верно. Кстати ты спрашивал типа чем мой не устроил? Твой - это какой? Ты про распознаватель который в теме cirus-а?


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

Всю статистику я всегда собирал и прямиком запихивал в эксель, поэтому сейчас у меня подробнейшая таблица на каждый символ и я до такой степени скрупулезно всё анализировал, что сейчас распознаю число аж вот так FindRGB(address,len,244,639, 688,639,825,639,"R(0-255)",10000)


Это ещё по старинке вызывается параллельный скрипт на lua.

Автор: DarkMaster 14.12.2018, 18:22

Цитата
А когда ты дал СИ шный инструментарий, я вообще прямо загорелся - ну нет никаких ограничений, реально нет.

Могу еще рассказать, как сделать дллку и написать на реально чистом си и прилинковать через ffi. Соответственно скорость совсем улетит вверх) Знаний чтобы писать ифы и форы там не надо.

Автор: sutra 14.12.2018, 18:26

Обрати внимание достаточно анализ ОДНОЙ строки пикселей. Я точно знаю все варианты этой строки. Это я делал ещё для тормозного Пилота.

Цитата
Могу еще рассказать, как сделать дллку и написать на реально чистом си и прилинковать через ffi.

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


Это знаешь типа как раньше, полез поворотник в Жигулях посмотреть, подправить, а в итоге коробку передач разобрал.

Автор: sutra 15.12.2018, 5:34

Дарк, я тут просто пробежался по темам форума, по вопросам и ответам. Что могу сказать, конечно не все зададут вопрос, но всё-таки, статистика - вещь неумолимая. Кто спросил как работает findimage? Как сделать быстрее? Как воспользоваться той или иной функцией? Вот лично я задавал вопросы по синтаксису, потому, что не знаю ничего, а люди то вообще спрашивают А КАК? Там проблемки поглубже, там не синтаксис, там основы программирования и алгоритмирования. И мы им прикрутим deviation и accurace? Надо так ... чем проще, тем лучше, а для особо одарённых просто менюшку "advanced" и мелким шрифтом и в 3-й уровень вложенности.

Автор: DarkMaster 15.12.2018, 5:45

Цитата
И мы им прикрутим deviation и accurace?

Для этого есть параметры по умолчанию. Возможно их стоит как-то более агрессивно доводить до пользователей. Например, изменить схему вставки из меню по пкм. Для луа я вообще параметры раскидываю по строкам:
Код
local arr, err = findimage(
    x1,y1,x2,y2,
    {[[path]]},
    2, 90, 1, 4)

Так просто нагляднее и проще. Последнюю строку я бы просто не вставлял, чтобы не путать людей. Вообще на самом деле самая большая трагедия в том, что люди не умеют читать синтаксис. Я уже задолбался везде писать, что параметры в квадратных скобках не являются обязательными. Люди этого не знаю, не понимают, пытаются задать все возможное, зачастую ненужное.

Автор: sutra 15.12.2018, 5:56

А вообще классная компания (чуть не сказал тусовка) собралась. Балом правит W(hite) Светлый Князь, Разруливает Тёмный Мастер. Незримое око у серого кардинала cirus (перевода не знаю). Ну и я в роли королевского шута (надеюсь мне простят мои шутки).

Цитата
Так просто нагляднее и проще

Нет, ну ты красавец, мне нравится твой оптимизм, значит всё не так плохо.


cirus, наверное это RUS-сский СИ-шник. Я буду SovietUnion... дальше личная информация.

Автор: sutra 15.12.2018, 6:10

Анекдот из реальной жизни.
90-е годы. Формирование ЖКХ. Соседка встречает соседа и говорит
- Николай, за воду будем теперь платить отдельно.
Николай в ответ
- Какому на х..рен заводу?

Автор: sutra 15.12.2018, 6:21

В продолжение темы...
Жена мужу.
- Ты ребёнку на сок дал? (подразумевалось денег)
Ответ.
- Какой носок?

Автор: sutra 17.12.2018, 18:30

Код
local cscrX,cscrY,cfx1,cfy1,cfx2,cfy2,cl=ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t")

Как то можно от таких соплей избавиться? Чтобы нужные переменные объявить один раз нужным типом или придётся терпеть универсальность lua, которая в данном случае у меня вызывает улыбку.
И возникла ещё одна идея, но не уверен в правильности своих мыслей. Есть смысл перейти с for-ов например на repeat-ы, с использованием СИ переменных? Так как в for-ах переменные локальные и по определению lua-шные. Вроде по логике должно быстрее работать с репитами и вайлами?

Автор: sutra 17.12.2018, 18:43

Вроде допинал сравнение картинок. Убрал считывание картинки целиком в память. Считывается ровно столько, сколько необходимо. В нормальных ситуациях прирост по скорости несопоставимо быстрее. А вот если куча холостых сравнений, тогда может быть и хуже (но это уже вопрос, как правильно делать картинки). А ещё сделал возможность анализировать не все три канала RGB, а вплоть до одного. Если радуги нет, как в моём случае, скорость выростает ещё в 3 раза и всё работает как надо. Вроде удалось переплюнуть (только при правильных картинках) скорость моего джипеговского распознавателя. Всё-таки пока работал на Пилотовском языке - это был ПРОРЫВ, проверил его ещё раз досконально. Скорость его выполнения всего 15-20 миллисекунд и плюс его ещё и в том, что скорость не зависит от условий, сам алгоритм проверяет (отсекает) ВСЕ варианты картинок.

Автор: sutra 17.12.2018, 19:04

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

Автор: DarkMaster 18.12.2018, 5:03

Цитата

Как то можно от таких соплей избавиться? Чтобы нужные переменные объявить один раз нужным типом или придётся терпеть универсальность lua, которая в данном случае у меня вызывает улыбку.

Все зависит от области, где вы их объявлете. Можно их просто сделать upvalue.
Код
local function my_func() end -- прототип функции
do -- создаем карман namespace, аналогичный while, for, function
    local my_var = 123
    function my_func()
        my_var = my_var + 1
        print(my_var)
    end
end

Обратите внимание, что upvalue в данном случае не будет высвобождаться и значение будет сохраняться, но за пределам do end вы его прочитать не сможете. Вообще это логично и очевидно - если вы используете переменную, то вы ее инициализруете каждый раз, если высвобождаете память. Где-то это не так? Конкретно в данном случае возможно имеет смысл объявить структуру, а не набор переменных.
Цитата
А ещё сделал возможность анализировать не все три канала RGB, а вплоть до одного.

А теперь делай сравнение по минимальному значению канала и максимальному. Я фильтры покрутил и офигел =) Крайне полезная вещь. Так же в теории может пригодится сумма каналов. На самом деле я думал, что именно сумма даст лучший результат для того, чтобы избежать рендеринга и сглаживания шрифтов. Однако по тем случаям, что я анализировал лучшим результатом был минимум и максимум. Контраст оказался просто огромным.
Цитата
всё равно бывают случаи, когда приходится делать несколько вариантов картинок

Читай выше wink.gif

Автор: sutra 18.12.2018, 17:16

Спасибо Дарк, да, я тут тоже всё экспериментирую. Вопрос по repeat снят. Я удивился, но скорость с репитом выросла ровно в 2 раза, а это очень нехило.

Цитата
что именно сумма даст лучший результат для того

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

Автор: sutra 18.12.2018, 17:33

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

Автор: sutra 18.12.2018, 17:51

Ахренеть, добился скорости поиска среди 1000 картинок, размером 500х23, при условии просмотра ВСЕХ картинок аж всего за ТРИ тысячных секунды. Думаю на этом можно поставить жирную точку.

Использовал для поиска только один канал и только нужной, а не всей зоны картинки, естественно оставляя возможность анализировать все каналы и все пиксели для сложных и не текстовых картинок.

Автор: sutra 18.12.2018, 20:54

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

Код
      k=0
      repeat
        sg[k]=rmem("unsigned char*",indg+k)[0]
        sl[k]=rmem("unsigned char*",indl+k)[0]
        if math.abs(sg[k]-sl[k])>cdev then  return 0  end
        k=k+1
      until k>cch[code]



Вот такой цикл при сравнительном тесте выполнялся 2,559 сек.

А вот такой цикл 1,559
Код
      for k=0,2 do
        sg[k]=rmem("unsigned char*",indg+k)[0]
        sl[k]=rmem("unsigned char*",indl+k)[0]
        if math.abs(sg[k]-sl[k])>cdev then  return 0  end
      end



Надо тестить с разными типами переменных.

Этих типов мама не горюй. Дарк, есть предпочтения? Какие типы обрабатываются лучше? Знаковые? Беззнаковые? и скольки битовые? 16 32 или вообще 64?

Автор: DarkMaster 18.12.2018, 21:51

Цитата
k=0

сишной объявите.

Цитата
Этих типов мама не горюй. Дарк, есть предпочтения? Какие типы обрабатываются лучше? Знаковые? Беззнаковые? и скольки битовые? 16 32 или вообще 64?

n страниц назад я выкладывал тесты по типам и ваши результаты тестов там тоже есть =)

Цитата
Я уже давно использую сумму и даже суммы одного канала может быть достаточно.

Попрбуй использовать для сравнения наименьший и наибольший каналы. Это дало лучший результат чем суммы. Т.е.:
rgb
100 255 35 -- берем 35
25 50 200 -- берем 25
сравниваем 25 и 35.
На первый взгляд маразм, но при анализе фильтрами в фоторедакторе именно этот вариант был очень хорош по результатам. Ну и наоборот максимумы.

Автор: sutra 18.12.2018, 23:01

Цитата
сишной объявите.

Так и была сишная. Играл с типами, но что-то толком не понял как быстрее, всё равно медленнее. Не стал забивать себе голову. Вообще убрал этот внутренний цикл. Стало некрасивей, но это оказался самый быстрый вариант.


Цитата
Попрбуй использовать для сравнения наименьший и наибольший каналы

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

Имитировал наихудшую ситуацию, когда типа искало и ничего не смогло найти. 1000 картинок за 6 сотых секунды. Чего выпендриваться - достойная скорость.

Искало по всем пикселям 500х23 * 1000 картинок = 6 сотых сек..

Грубо говоря полный перевод на СИ, увеличил скорость в 2 раза. А тот внутренний цикл, хрен его знает. Там и ридмем и сравнение и цикл. На чём-то ускоряется, на чём-то замедляется. Выкинул цикл и всех делов.

Автор: sutra 19.12.2018, 0:09

Выбросил из кода if math.abs(sg[2]-sl[2])>cdev then return 0 end
Сделал код ещё некрасивей, но ещё быстрее на 30%. А это очень прилично. В "боевых" условиях, на "живых" картинках, что-то мне подсказывает поиск будет мгновенным.

Автор: sutra 21.12.2018, 0:03

Код
log "clear" log "mode compact"
local ffi=require "ffi"
local n=ffi.new("uint8_t[3]")
local m=ffi.new("uint8_t")
local s=""
m=tonumber(r1)
log(m)                -- nil
log(type(n[0]))       -- number
--n[0]=tonumber(r1)   -- если разремарить будет ошибка конвертирования
stop_script()

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

Автор: sutra 21.12.2018, 0:21

Непонятно почему при первом варианте с переменной m нет ошибки.

По логике типа её адрес не определён и следовательно nil, а как тогда хранится её адрес в памяти? Что-то я запутался.

Вроде понял, извините, затупил.

Автор: sutra 21.12.2018, 1:21

Код
--lua
local ffi=require "ffi"
log "clear" log "mode compact"
local n=ffi.new("uint32_t[3]")
local x,y,z=ffi.new("uint32_t"),ffi.new("uint32_t"),ffi.new("uint32_t")
x,y,z=0,0,0
tmc=os.clock()
repeat
  x=x+1
  repeat
    y=y+1
    if y>x then z=1 else z=2 end
  until y>100000000
until x>100000000
log(os.clock()-tmc)
tmc=os.clock()
repeat
  n[0]=n[0]+1
  repeat
    n[1]=n[1]+1
    if n[1]>n[0] then n[2]=1 else n[2]=2 end
  until n[1]>100000000
until n[0]>100000000
log(os.clock()-tmc)
stop_script()

Похоже я жестоко ошибся и нельзя делать массивы, придётся переделывать свои функции. Дарить более 100% скорости - грех.

Автор: sutra 21.12.2018, 2:01

Дарк, чего-то я вообще ничего не понимаю. Может я чего не то делаю? Вот тестани этот код. У меня получается медленнее на СИ-шных, на массиве разница вообще очевидная.

Код
log "clear" log "mode compact"
do
local n=ffi.new("uint32_t[3]")
local x,y,z=ffi.new("uint32_t"),ffi.new("uint32_t"),ffi.new("uint32_t")
x,y,z=0,0,0
tmc=os.clock()
repeat
  x=x+1
  repeat
    y=y+1
    if y>x then z=1 else z=2 end
  until y>100000000
until x>100000000
log(os.clock()-tmc)
tmc=os.clock()
repeat
  n[0]=n[0]+1
  repeat
    n[1]=n[1]+1
    if n[1]>n[0] then n[2]=1 else n[2]=2 end
  until n[1]>100000000
until n[0]>100000000
log(os.clock()-tmc)
end

do
local n={}
n[1],n[2],n[3]=0,0,0
local x,y,z=0,0,0
tmc=os.clock()
repeat
  x=x+1
  repeat
    y=y+1
    if y>x then z=1 else z=2 end
  until y>100000000
until x>100000000
log(os.clock()-tmc)
tmc=os.clock()
repeat
  n[1]=n[1]+1
  repeat
    n[2]=n[2]+1
    if n[2]>n[1] then n[3]=1 else n[3]=2 end
  until n[2]>100000000
until n[1]>100000000
log(os.clock()-tmc)
end
stop_script()



Понятно только одно, массивы однозначно медленнее!

Cirus, а у тебя как? Тоже медленнее?

Может нельзя использовать константы используя СИ??

Автор: DarkMaster 21.12.2018, 2:04

Цитата
local m=ffi.new("uint8_t")

Там какие-то грехи водятся за этой конструкций. Оно вроде валидная конструкция, все дела. Вот только там при переполнении переменной начинает писать в соседние байты. То ли проверок просто нет, то ли сама конструкция не корректная я не знаю. Надо посмотреть биндинги какие-нибудь, как там реализуют. Мне не горело, я просто массивы объявлял.

0.50599999999395
1.1109999999753
0.50699999998324
0.76400000002468

Там кстати после скольки-то нулей циклов начинает расти время не прямолинейно. По крайней мере в for.

Автор: sutra 21.12.2018, 2:10

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

Автор: cirus 21.12.2018, 2:11

Раз уж тесты на скорость, зачем repeat, когда есть while.

код
Код
--lua
local ffi=require "ffi"
log "clear" log "mode compact"
local n=ffi.new("uint32_t[3]")
local x,y,z=ffi.new("uint32_t"),ffi.new("uint32_t"),ffi.new("uint32_t")
x,y,z=0,0,0
tmc=os.clock()
repeat
  x=x+1
  repeat
    y=y+1
    if y>x then z=1 else z=2 end
  until y>100000000
until x>100000000
log(os.clock()-tmc)

x,y,z=0,0,0
tmc=os.clock()
while x<=100000000 do
    x=x+1
    while y<=100000000 do
        y=y+1
        if y>x then z=1 else z=2 end
    end
end
log(os.clock()-tmc)
stop_script()

Автор: sutra 21.12.2018, 2:13

Но от массива надо однозначно избавляться. На СИ - 100% потери - это ни в какие ворота не лезет. Я стараюсь выжать крохи, а тут такой костыль...

Цитата
Раз уж тесты на скорость, зачем repeat, когда есть while.

Слушай думал на эту тему, но никак не думал что и тут костыли.

Автор: DarkMaster 21.12.2018, 2:13

Цитата
У меня получается медленнее на СИ-шных, на массиве разница вообще очевидная.

Я над этим на самом деле очень долго голову ломал. Так ничего умного и не понял. Вообще судя по докам там должно быть промежуточное приведение к double, что существенно должно замедлять скорость работы. Однако в тех тестах, что я тут выкладывал получилось совсем не так. Думаю, просто нужно соблюдать типизацию, если хочется скорости. Т.е. все операции производить между одинаковыми типами. Кстати ты проводишь операции над unsigned int 32, который по тестам был самым невероятно тормознутым. Убирай unsigned, если пролазит максимальное значение. Там даже int 64 был шустрее(или столько же?), чем unsigned int 32. Если значения позволяют, то уменьшай до 8/16 бит.

Автор: sutra 21.12.2018, 2:19

Спасибо Cirus. Ладно, переделаем, ну блин, я выжму до последней капли - будет 10 махов.

Слушай Дарк, у меня наоборот на беззнаковых быстрее. Здесь 32 бита, просто чтобы "влезли" циклы. Но на самом деле я пробовал ВСЕ типы. ПРИНЦИПИАЛЬНОГО выигрыша нет. А здесь то 100%!!!

Принцип я понял. Кстати я ведь тестировал кое-что и прироста тоже не обнаружил между СИ и LUA. Там реальный прирост при вызове ридмема, так сказать родное на родном работает, а на остальном надо действительно просто смотреть, ни хрена не понятно.

Автор: DarkMaster 21.12.2018, 2:21

https://forum.uokit.com/index.php?showtopic=69255&st=120#
В синтетике одназначно есть разница. Возможно if'ы все тормозят ибо хз как их там реализовывали, может приведение идет.

Автор: sutra 21.12.2018, 2:37

Огромное спасибо. Две пилюли есть, вместо репита вайл и вместо массива - переменные. Прирост будет супер.

Цитата
Возможно if'ы все тормозят ибо хз как их там реализовывали

Да, там действительно не совсем понятно, наверняка есть приведение типов. Только на своём финде я прирост получил. Надо проверять каждый оператор. Живой пример подкинул Cirus.


В рядовом случае семь раз наплевать, но при поиске картинок миллионы пикселей ворочать приходится, там надо делать всё предельно аккуратно.

Кстати, про типы. На вайле пока не проверял, но на репите, если поставить вместо > ==, то будет бесконечный цикл, видимо там не целочисленное значение получается.

А вот на вайле - целочисленный индекс.

Возможно из-за этого репит так тормозит, потому что делают то одно и то же. Короче костылей тут хватает, надо проверять ну абсолютно ВСЁ. Это братцы не Паскаль.

Ещё раз парни спасибо, за науку.

Автор: sutra 21.12.2018, 2:57

Переделал свою функцию поиска на вайл - прирост НУЛЬ, там сравнение с переменными и тормозов нет.

Так что с константами надо поаккуратнее.

Автор: DarkMaster 21.12.2018, 3:05

в double отведено 52 бита под целые. Аккуратнее с нулями.

Автор: sutra 21.12.2018, 3:05

Убрал из функции массивы, в ридмем читаю в переменные. Прирост скорости 11%.

Автор: DarkMaster 21.12.2018, 12:01

А ты стариной не тряхнешь и не перепишешь этот кусок на асме в итоге?) Скорость будет существенно выше smile.gif Кстати в этой шутке только доля шутки.

Автор: sutra 21.12.2018, 16:57

Цитата
А ты стариной не тряхнешь и не перепишешь этот кусок на асме в итоге?)

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


Кстати, про массивы и for-ы. Тычусь в другой своей функции и не поверишь, на массивах и форах работает быстрее, чем на переменных и вайлах. Ни хрена я не понимаю. Надо знать всю архитектуру ОТ и ДО. А наугад и результат соответствующий. Одна какая-нибудь переменная не того типа может "загубить" всё.

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

Автор: DarkMaster 21.12.2018, 17:20

Цитата
Но я наверное плюну на мелочи

Я все-таки надеюсь, что допилишь поиск по мин/макс каналу и точность =)

Автор: sutra 21.12.2018, 17:37

Цитата
Я все-таки надеюсь, что допилишь поиск по мин/макс каналу и точность

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

Автор: DarkMaster 21.12.2018, 20:19

Цитата
Да ну её эту точность.

Просто сейчас получается есть два оператора и оба калеченные и не взаимозаменяемые.

Автор: sutra 22.12.2018, 13:03

rmem("unsigned char*",ind)[0]
Дарк, а что означает нуль в квадратных скобках? Хендл Пилота?

Автор: sutra 22.12.2018, 13:18

Собственно возник вопрос такого плана, а можно не один байт читать, а скажем сколько надо. Ну типа затолкать сразу в структуру все байты строки пикселей. Ну по принципу работы move.

Иначе говоря, можно вместо "unsigned char*" использовать свою структуру? Ведь можем же считать 2 байта, если нарисовать например "uint_16t"

Автор: DarkMaster 22.12.2018, 13:19

Цитата
Дарк, а что означает нуль в квадратных скобках? Хендл Пилота?

Оно читает в данном случае, как _ссылку_ на массив. Ноль обозначает номер элемента.
А зачем их вообще куда-то толкать? Мы же их не копируем. Читать то по сути можно сколько угодно, но смысл не ясен.

Автор: sutra 22.12.2018, 13:45

Цитата
Ноль обозначает номер элемента

Отлично, именно это и хотел спросить, и именно так и думал. Если есть своя структура, ну например ffi.cdef[[typedef struct{uint8_t red,green,blue;}rgb]] , то мы можем в ридмеме использовать её? И сразу иметь все 3 канала?


Грубо говоря в идеале заставить ридмем считывать столько байт, сколько надо.

То есть есть структура из 3-х байт. Я объявляю допустим 10 элементов этой структуры и чтобы сразу поиметь 30 байт, которые ровно лягут во все 10 элементов.

Я правильно понял что вот эту хрень - s[7]=rmem("unsigned char*",ind+1)[0] я могу заменить на эту - s[7]=rmem("unsigned char*",ind)[1] ??

На последний вопрос ответ получен, можно.

Автор: DarkMaster 22.12.2018, 13:59

обычно в таких случаях используют массив char'ов.
вообще в данном случае мы читаем через cast(явное приведение типов). В данном случае хз как все это делать правильно.

Поясни, что именно ты хочешь сделать? Сравнить два длинных участка памяти? Скопировать кусок памяти? Если скопировать, то зачем?

Автор: sutra 22.12.2018, 14:08

rr=rmem("rgb*",p)[0] РАБОТАЕТ!! Сразу читает в СИ структуру все 3 канала. Да хотел убрать один цикл, тормозят эти циклы, хотел сразу считать все пиксели в массив СИ-шный (естественно только для одной строки пикселей).

Автор: DarkMaster 22.12.2018, 14:43

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

Автор: sutra 22.12.2018, 15:15

Дольше в 2 раза читает структуру ридмем. Не поленился, опять всё шаг за шагом протестировал. Пока понятно следующее. Ридмем - это самый быстрый шаг во всей цепочке анализа, и ему фиолетово что с нулевого, что не с нулевого индекса читать. Теперь далее. Сам по себе цикл for выполняется в 3 раза быстрее, чем while. Но загвоздка в том, как индекс цикла используется внутри цикла. Вот на этот вопрос у меня пока нет однозначного ответа, но он обязательно будет. Тормоз - это кишки внутри цикла и от типа переменных внутри его тормоза могут увеличиваться аж в 4 РАЗА. Вот я и пытаю пока, как эти типы работают внутри.

Автор: sutra 22.12.2018, 15:28

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

Автор: DarkMaster 22.12.2018, 15:55

дай код

Автор: sutra 22.12.2018, 17:53

Цитата
дай код

Да погоди Дарк, я вообще ничего не понимаю, сейчас ещё раз всё по новой проверю. Ну вот проверял ведь, фор работал в 3 раза быстрее вайла. А в моей функции вайлы работают на 15% быстрее форов, как так может быть, не знаю. Сейчас проверю ещё влияние if в обоих типах циклов.

Автор: sutra 22.12.2018, 18:12

Код
log "clear" log "mode compact"
tmc=os.clock()
for i=1,200000000 do end
log(os.clock()-tmc)

tmc=os.clock()
i=1
while i<=200000000 do i=i+1 end
log(os.clock()-tmc)

tmc=os.clock()
for i=1,200000000 do a=i end
log(os.clock()-tmc)

tmc=os.clock()
i=1
while i<=200000000 do i=i+1 a=i end
log(os.clock()-tmc)

tmc=os.clock()
for i=1,200000000 do if i>100 then a=i else a=0 end end
log(os.clock()-tmc)

tmc=os.clock()
i=1
while i<=200000000 do if i>100 then a=i else a=0 end  i=i+1  end
log(os.clock()-tmc)

stop_script()

If действительно начинает сильно затормаживать цикл, но всё равно for быстрее, так что я ничего не понимаю.

Автор: DarkMaster 22.12.2018, 18:21

ты не пробовал не переменные использовать в ифах, а напрямую читать память?

Автор: sutra 22.12.2018, 18:48

Цитата
ты не пробовал не переменные использовать в ифах, а напрямую читать память?

Не пробовал, но думал, но ведь это всё равно будет делать lua и значит будет приведение типов.


У меня тут десятки разных вариантов. Вот тебе чисто для примера, может я чего-то просто не вижу.
Код
--lua
local ffi=require "ffi"                                                        -- Использование модуля ffi для использования СИ структур
local rmem=ffi.cast                                                            -- Использование функции чтения из памяти модуля ffi
ffi.cdef[[typedef struct{uint16_t x,y; uint8_t red,green,blue;}xyrgb]]         -- Определение структуры массива чтения данных из памяти образа картинки
local function FindMemRGBpf(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)         -- ПОИСК ПИКСЕЛЕЙ ПО ЗНАЧЕНИЯМ RGB В ОБЛАСТИ ПАМЯТИ
-- addr,len : адрес в памяти, длина строки в памяти (то, что даёт getimage)
-- scrX1,scrY1 : координаты верхнего левого угла образа в памяти, должны быть аналогичны координатам getimage
-- fx1,fy1,fx2,fy2 : координаты поиска пикселей, абсолютные относительно рабочего окна. Должны быть внутри диапазона координат образа в памяти.
-- usl : ОДНО строковое условие поиска "R(10-255) G(70-100) B(50) R-G[50 200] R-B[-40 -20] G-B[15]".
-- numf : максимальное количество искомых пикселей
  local n=math.min(numf,(fx2-fx1+1)*(fy2-fy1+1))            -- Определение максимальной размерности возвращаемого функцией СИ массива найденных пикселей
  local arr=ffi.new("xyrgb[?]",n)                        -- Инициализация СИ массива искомых пикселей (используя ранее описанную структуру)
  local r1,r2=usl:match("R%((%d+)%-*(%d*)")
  local g1,g2=usl:match("G%((%d+)%-*(%d*)")
  local b1,b2=usl:match("B%((%d+)%-*(%d*)")
  local RG1,RG2=usl:match("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local RB1,RB2=usl:match("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local GB1,GB2=usl:match("G%-B%[(%-*%d+)%s*(%-*%d*)")
  local r,g,b,cr1,cr2,cg1,cg2,cb1,cb2=ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t"),
        ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t")
  local cRG1,cRG2,cRB1,cRB2,cGB1,cGB2,k=ffi.new("int16_t"),ffi.new("int16_t"),ffi.new("int16_t"),ffi.new("int16_t"),
                ffi.new("int16_t"),ffi.new("int16_t"),ffi.new("int16_t")
  if r1==nil then  cr1,cr2=0,255
    else  cr1=tonumber(r1)  if r2=="" then  cr2=cr1  else  cr2=tonumber(r2)  end
  end
  if g1==nil then  cg1,cg2=0,255
    else  cg1=tonumber(g1)  if g2=="" then  cg2=cg1  else  cg2=tonumber(g2)  end
  end
  if b1==nil then  cb1,cb2=0,255
    else  cb1=tonumber(b1)  if b2=="" then  cb2=cb1  else  cb2=tonumber(b2)  end
  end
  if RG1==nil then  cRG1,cRG2=-255,255
    else  cRG1=tonumber(RG1)  if RG2=="" then  cRG2=255  else  cRG2=tonumber(RG2)  end
  end
  if RB1==nil then  cRB1,cRB2=-255,255
    else  cRB1=tonumber(RB1)  if RB2=="" then  cRB2=255  else  cRB2=tonumber(RB2)  end
  end
  if GB1==nil then  cGB1,cGB2=-255,255
    else  cGB1=tonumber(GB1)  if GB2=="" then  cGB2=255  else  cGB2=tonumber(GB2)  end
  end
  local indY,ind,caddr,clen,cscrX1,cscrY1,cfx1,cfx2,cfy1,cfy2=ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),
                ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t")
  k,caddr,clen,cscrX1,cscrY1,cfx1,cfx2,cfy1,cfy2=-1,addr,len,scrX1,scrY1,fx1,fx2,fy1,fy2
  for i=cfy1,cfy2 do
    indY=caddr+(i-cscrY1)*clen
    for j=cfx1,cfx2 do
      ind=indY+(j-cscrX1)*3
      b=rmem("unsigned char*",ind)[0]
      g=rmem("unsigned char*",ind)[1]
      r=rmem("unsigned char*",ind)[2]
      if r>=cr1 and r<=cr2 and g>=cg1 and g<=cg2 and b>=cb1 and b<=cb2 and r-g>=cRG1 and r-g<=cRG2 and r-b>=cRB1 and r-b<=cRB2 and g-b>=cGB1 and g-b<=cGB2 then
        k=k+1 arr[k].x,arr[k].y,arr[k].red,arr[k].green,arr[k].blue=j,i,r,g,b
        if numf-1==k then return k,arr  end
      end
    end
  end
  return k,arr
end----------------------------------------------------------------------------
local function FindMemRGBpw(addr,len,scrX1,scrY1,fx1,fy1,fx2,fy2,usl,numf)         -- ПОИСК ПИКСЕЛЕЙ ПО ЗНАЧЕНИЯМ RGB В ОБЛАСТИ ПАМЯТИ
-- addr,len : адрес в памяти, длина строки в памяти (то, что даёт getimage)
-- scrX1,scrY1 : координаты верхнего левого угла образа в памяти, должны быть аналогичны координатам getimage
-- fx1,fy1,fx2,fy2 : координаты поиска пикселей, абсолютные относительно рабочего окна. Должны быть внутри диапазона координат образа в памяти.
-- usl : ОДНО строковое условие поиска "R(10-255) G(70-100) B(50) R-G[50 200] R-B[-40 -20] G-B[15]".
-- numf : максимальное количество искомых пикселей
  local n=math.min(numf,(fx2-fx1+1)*(fy2-fy1+1))                         -- Определение максимальной размерности возвращаемого функцией СИ массива найденных пикселей
  local arr=ffi.new("xyrgb[?]",n)                                        -- Инициализация СИ массива искомых пикселей (используя ранее описанную структуру)
  local r1,r2=usl:match("R%((%d+)%-*(%d*)")
  local g1,g2=usl:match("G%((%d+)%-*(%d*)")
  local b1,b2=usl:match("B%((%d+)%-*(%d*)")
  local RG1,RG2=usl:match("R%-G%[(%-*%d+)%s*(%-*%d*)")
  local RB1,RB2=usl:match("R%-B%[(%-*%d+)%s*(%-*%d*)")
  local GB1,GB2=usl:match("G%-B%[(%-*%d+)%s*(%-*%d*)")
  local r,g,b,cr1,cr2,cg1,cg2,cb1,cb2=ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t"),
            ffi.new("uint8_t"),ffi.new("uint8_t"),ffi.new("uint8_t")
  local cRG1,cRG2,cRB1,cRB2,cGB1,cGB2,k=ffi.new("int16_t"),ffi.new("int16_t"),ffi.new("int16_t"),ffi.new("int16_t"),
                ffi.new("int16_t"),ffi.new("int16_t"),ffi.new("int16_t")
  if r1==nil then  cr1,cr2=0,255
    else  cr1=tonumber(r1)  if r2=="" then  cr2=cr1  else  cr2=tonumber(r2)  end
  end
  if g1==nil then  cg1,cg2=0,255
    else  cg1=tonumber(g1)  if g2=="" then  cg2=cg1  else  cg2=tonumber(g2)  end
  end
  if b1==nil then  cb1,cb2=0,255
    else  cb1=tonumber(b1)  if b2=="" then  cb2=cb1  else  cb2=tonumber(b2)  end
  end
  if RG1==nil then  cRG1,cRG2=-255,255
    else  cRG1=tonumber(RG1)  if RG2=="" then  cRG2=255  else  cRG2=tonumber(RG2)  end
  end
  if RB1==nil then  cRB1,cRB2=-255,255
    else  cRB1=tonumber(RB1)  if RB2=="" then  cRB2=255  else  cRB2=tonumber(RB2)  end
  end
  if GB1==nil then  cGB1,cGB2=-255,255
    else  cGB1=tonumber(GB1)  if GB2=="" then  cGB2=255  else  cGB2=tonumber(GB2)  end
  end
  local i,j,indY,ind,caddr,clen,cscrX1,cscrY1,cfx1,cfx2,cfy1,cfy2=ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),
                ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t"),ffi.new("uint16_t")
  i,k,caddr,clen,cscrX1,cscrY1,cfx1,cfx2,cfy1,cfy2=fy1,-1,addr,len,scrX1,scrY1,fx1,fx2,fy1,fy2
  while i<=cfy2 do
    indY,j=caddr+(i-cscrY1)*clen,cfx1
    while j<=cfx2 do
      ind=indY+(j-cscrX1)*3
      b=rmem("unsigned char*",ind)[0]
      g=rmem("unsigned char*",ind)[1]
      r=rmem("unsigned char*",ind)[2]
      if r>=cr1 and r<=cr2 and g>=cg1 and g<=cg2 and b>=cb1 and b<=cb2 and r-g>=cRG1 and r-g<=cRG2 and r-b>=cRB1 and r-b<=cRB2 and g-b>=cGB1 and g-b<=cGB2 then
        k=k+1 arr[k].x,arr[k].y,arr[k].red,arr[k].green,arr[k].blue=j,i,r,g,b
        if numf-1==k then return k,arr  end
      end
      j=j+1
    end
    i=i+1
  end
  return k,arr
end----------------------------------------------------------------------------
log "clear" log "mode compact"
-- сделать окно рабочим
local p,_,_,l=getimage(0,0,999,999,ok[1][1])

tmc=os.clock()
for jj=1,1000 do
  k,arr=FindMemRGBpf(p,l,0,0, 0,0,999,999,"R(251)G(112)",2)
end
log(os.clock()-tmc)

tmc=os.clock()
for jj=1,1000 do
  k,arr=FindMemRGBpw(p,l,0,0, 0,0,999,999,"R(251)G(112)",2)
end
log(os.clock()-tmc)
tmc=os.clock()
for jj=1,500 do
  k,arr=FindMemRGBpf(p,l,0,0, 0,0,999,999,"R-G[139 139]R-B[249 249]",2)
end
log(os.clock()-tmc)

tmc=os.clock()
for jj=1,500 do
  k,arr=FindMemRGBpw(p,l,0,0, 0,0,999,999,"R-G[139 139]R-B[249 249]",2)
end
log(os.clock()-tmc)

deleteimage(p)
log(k)
if k~=-1 then  log(arr[k].x,arr[k].y,arr[k].red,arr[k].green,arr[k].blue)  end
stop_script()


Дарк, подправь, что бы плюсиком код разворачивался. А то страничку испоганило.

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

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

Автор: cirus 22.12.2018, 19:12

А это как объяснить?:

Код
--lua
log "clear" log "mode compact"

local a, tmc
tmc=os.clock()
for i=1,200000000 do if i>56 then a=i else a=0 end end
log(os.clock()-tmc)

tmc=os.clock()
for i=1,200000000 do if i>57 then a=i else a=0 end end
log(os.clock()-tmc)
stop_script()

log:
Цитата
0.088999999999942
0.89200000000005

Автор: sutra 22.12.2018, 19:14

Вот прикол, скопировал свою хрень на новую вкладку скриптов и вторая часть скрипта стала работать почти в 2 раза быстрее, наверное Пилот пора перегружать. Ничего совсем не понимаю.

Код
0.11799999998766
1.0469999999914

Я вообще ничего уже не понимаю.

Автор: cirus 22.12.2018, 19:15

Цитата
скопировал свою хрень на новую вкладку скриптов и вторая часть скрипта стала работать почти в 2 раза быстрее

Когда было такое, исправлялось. Видимо, ещё где-то что-то осталось.

Автор: sutra 22.12.2018, 19:26

Код
--tmc=os.clock()
--for jj=1,1000 do
--  k,arr=FindMemRGBpf(p,l,0,0, 0,0,999,999,"R(251)G(112)",2)
--end
--log(os.clock()-tmc)

--tmc=os.clock()
--for jj=1,1000 do
--  k,arr=FindMemRGBpw(p,l,0,0, 0,0,999,999,"R(251)G(112)",2)
--end
--log(os.clock()-tmc)
tmc=os.clock()
for jj=1,500 do
  k,arr=FindMemRGBpf(p,l,0,0, 0,0,999,999,"R-G[139 139]R-B[249 249]",2)
end
log(os.clock()-tmc)

tmc=os.clock()
for jj=1,500 do
  k,arr=FindMemRGBpw(p,l,0,0, 0,0,999,999,"R-G[139 139]R-B[249 249]",2)
log(os.clock()-tmc)
end

Попробуйте с заремаренной и разремаренной первой частью. Это у всех такая разница или только у меня.



Цитата
Когда было такое, исправлялось. Видимо, ещё где-то что-то осталось.

У меня причина в первой части скрипта, при заремаренной быстрее почти в 2 раза. Что-то тут нечисто. Или косяк в функции, ну или я не знаю...


Наверно потому что объявил их от лени тупо некорректно..

Автор: sutra 22.12.2018, 19:38

Ремарка первого блока влияет на 3-й блок, ремарка 2-го блока влияет на 4-й блок. Мистика какая-то.

Ну-с, господа, что скажете? Жду ваших комментариев.

Автор: sutra 22.12.2018, 19:50

Вы уж извините меня, наверное я достал уже всех со своими функциями. Но вдруг поможет выявить какие-нибудь косяки.

Автор: DarkMaster 22.12.2018, 19:53

Цитата
Не пробовал, но думал, но ведь это всё равно будет делать lua и значит будет приведение типов.

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

Автор: sutra 22.12.2018, 19:57

Дарк, ты пример Cirus-а смотрел? какие ключи? Тут без ключей хватает загадок.

Автор: DarkMaster 22.12.2018, 20:07

a runtime error.
114: attempt to index global 'ok' (a nil value)

Автор: sutra 22.12.2018, 20:16

Цитата
114: attempt to index global 'ok' (a nil value)

Ну так привяжи рабочее окно. У меня то своё.


Лично меня очень сильно интересует вопрос, почему исполнение предыдущего кода влияет на скорость выполнения последующего.

Автор: DarkMaster 22.12.2018, 20:16

Цитата
0.088999999999942
0.89200000000005

Хочу заметить, что подобная разница наблюдается только при увеличении числа выше чем 56. Хз как так... Может быть какие-то различные алгоритмы сложения.

Автор: sutra 22.12.2018, 20:19

Пробовал ставить задержку, пробовал другие переменные цикла - результат тот же.

Цитата
Хочу заметить

Я тоже это заметил. До 56 быстро, но растёт при увеличении, после 56, якорь. Причина вообще непонятна, что за хитрое такое значение 56, ну я бы понял если бы например 127...


Хотя насчёт растёт может мне показалось, разброс всё равно большой.

Автор: DarkMaster 22.12.2018, 20:21

Цитата
0.088999999999942
0.89200000000005

Хочу заметить, что подобная разница наблюдается только при увеличении числа выше чем 56. Хз как так... Может быть какие-то различные алгоритмы сложения.


Не помогла привязка. Какой модуль я хз. ffi подгружает норм.
Не найден указанный модуль

Автор: sutra 22.12.2018, 20:32

Цитата
Не помогла привязка

Ну я не знаю, сделай без хендла, какая разница. Вроде там ничего лишнего.


Круто, ткнул привязку на другое окно, ровно в 3 раза быстрее отработало.

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

Автор: DarkMaster 22.12.2018, 20:32

if r>=cr1 and r<=cr2 and g>=cg1 and g<=cg2 and b>=cb1 and b<=cb2 and r-g>=cRG1 and r-g<=cRG2 and r-b>=cRB1 and r-b<=cRB2 and g-b>=cGB1 and g-b<=cGB2 then
53 строка +/-
вот на этом сыпит про модуль

Автор: sutra 22.12.2018, 20:38

Значения ридмема анализируются.

У меня тоже на большинстве окон не работает. Работает на графических окнах только.

Автор: DarkMaster 22.12.2018, 20:43

jit.off()
В шапку и все стройно по времени получается. Динамическая компиляция оптимизирует коряво. Но без оптимизации получается мегатормоз (два нуля в циклах сразу убирай).

Автор: sutra 22.12.2018, 20:51

Цитата
Но без оптимизации получается мегатормоз

Ну и смысл? Я тут за скорость мыкаюсь, а ты советуешь 2 нуля убрать. Нет - это не наш путь.


Насколько я пока понимаю ситуацию - это косяк в FOR-ах. Не велика потеря, перейдём на вайлы, благо получается в итоге на вайлах быстрее.

Просто тестировать теперь буду не на форах, вот и всё.

Автор: DarkMaster 22.12.2018, 20:53

Цитата
Ну и смысл?

Вроде причину было желание узнать. Я ее нашел. То, что это по большому счету тупик/слепые эксперименты для обхода - это уже вопрос второй. Единственное, что могу предложить из конструктивного - написать разрабам, подозреваю, что им будет интересно подобное поведение и косяк будет вылизан. Бороться же в рамках пилота только вслепую.

Автор: sutra 22.12.2018, 21:05

Цитата
Вроде причину было желание узнать

Ну конечно есть желание. Узнали. Я точно никому ничего писать не стану, кто я такой. Бороться в рамках Пилота, тут я тоже на задворках, тут у Кнайта должна голова болеть. Лишь бы скрипт в конечном итоге не падал, надеюсь не должен. Во всяком случае данный вариант моего файнда работает уже больше месяца, не менее 2 тысяч вызовов в сутки (вызывается параллельным скриптом из Пилотовского) и пока всё нормуль.


Вопрос опять же почему не ко всем окнам вяжется, ну тут я тоже не сильно расстроен, к тому, к чему мне надо вяжется.

Автор: DarkMaster 22.12.2018, 21:18

Цитата
Я точно никому ничего писать не стану, кто я такой.

А я кто такой, что по пилоту баги пишу?) Права ровно такие же птичьи. Это фришные и опенсорсные принципы. Ценность репорта не определяется статусом.
Цитата
Бороться в рамках Пилота, тут я тоже на задворках, тут у Кнайта должна голова болеть.

У кнайта может голова болеть по поводу финдов, но никак не по поводу jit оптимизации. Тут явно не по адресу. Переписывать jit исходники это нужно очень хорошо шарить не только в целом, но и в конкретном проекте. Это очень глубокие знания и их касательно lua и компиляции просто нет. Их в принципе достаточно может человек у 3-5 в мире, кто непосредственно разработкой занимается. Более того, я, например, категорически против внесения каких-либо изменений в исходники lua. Потом при апдейтах можно будет вешаться, про совместимость с модулямии биндингами и возможные скрытые проблемы вообще молчу.
Цитата
Вопрос опять же почему не ко всем окнам вяжется, ну тут я тоже не сильно расстроен, к тому, к чему мне надо вяжется.

Скорее всего это малевич. К родительскому вероятно нужно.

Автор: sutra 22.12.2018, 21:45

Цитата
К родительскому вероятно нужно

Да, я тоже так подумал, проверять было лень. Ладно, Дарк, спасибо за советы, за конструктивную критику. Для себя я примерно понял что к чему, обойти чего-нибудь, так не в первый раз, всю жизнь методом тыка. Технологии новые, а косяки как были, так и остались. Мне тоже спасибо, rolleyes.gif косяки нахожу, может кому пригодится, чтобы на те же грабли не наступать.


Вот теперь точно ставлю точку, надоело одно по одному. Вроде вопросов больше возникнуть не должно, ну возникнут - спрошу. Так что всех с наступающим Новым годом и чтобы ваши скрипты работали как часы и Пилот работал как атомные часы!!

Автор: DarkMaster 22.12.2018, 21:58

Цитата
Да, я тоже так подумал, проверять было лень

Ты не поверишь biggrin.gif
Цитата
сю жизнь методом тыка. Технологии новые, а косяки как были, так и остались.

И никогда это не изменится. Можно не пытаться. Можно минимизировать подобные вещи, но это нужно сидеть на каких-то очень узкоспециализированных железках и писать к ним прошивки. Там инертность побольше - нужно чтобы работало, а не новый прикольный фреймворк вкорячить.
Цитата
Мне тоже спасибо, rolleyes.gif косяки нахожу, может кому пригодится, чтобы на те же грабли не наступать.

Я все равно надеюсь на полноценную замену финду в твоем исполнении =) Мало кто так дотошно будет изучать варианты и тестировать скорость.

Автор: sutra 22.12.2018, 22:29

Цитата
Мало кто так дотошно будет изучать варианты и тестировать скорость

Точно, просто в точку. Именно дотошно - это скорее даже минус моей натуры, хотя не скрою, благодаря этой дотошности, иногда получалось принимать неординарные решения (не только в компьютерах), которые давали супер результат и мне всё прощалось, но такое бывает 1 раз на 100 случаев, в большинстве своём, все всегда требовали результат как можно быстрее и любой ценой. Типа "где бл...я, быстро бл...я".


Просто я очень ленивый. Лень - двигатель прогресса. Мне настолько лень что-то делать одно и тоже даже дважды, не говоря уж про большее количество повторений, что я поневоле стал программировать. Когда в своё время я купил программируемый калькулятор МК-61, потом МК-52 (вроде ещё помню модификации) и сделал за 15 минут и пошёл гулять, то, что все делали 2 пары - конечно это было круто. Вот и на проект Пилота вышел тоже исключительно из-за лени. Хотя если мне интересно, я могу десяток часов, хоть до утра просидеть.

Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)