1 (изменено: NektoN95, 2015-08-03 09:28:46)

Тема: AHK: Не разрывается цикл

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

#NoEnv
Process Priority,,High 
SetBatchLines -1

;-----------------------------------------------------------------
RcrdInMssv(x1,y1,x2,y2,FndClr)                                        ;x1,y1,x2,y2 - границы считываемого изображения, FndClr - искомый цвет
{
    local i, thspxx, thspxy, clr
    %FndClr% := Object()                                            ;обьявляем массив в который будем считывать изображение по имени искомого цвета
        loop
        {
            i := %A_index%                                            ;задаем переменную в которой будет храниться номер строки пикселов (будет использоваться для нумерования ячеек массива)
            ThsPxY := i + y1 - 1                                    ;определяем y-координату пиксела, который будем "читать"
            msgbox % thspxy " - " y2
            if (thspxy > y2)                                        ;если номер текущей строки больше, чем номер последней строки подлежащей анализу
                break                                                ;разорвать цикл
            else                                                    ;иначе
            {
                loop
                {
                    ThsPxX := a_index + x1 - 1                        ;определяем x-координату пиксела, который будем "читать"    
                    if (thspxx > x2)                                ;если номер текущего столбца больше, чем номер последнего столбца подлежащего анализу
                        break                                        ;разорвать цикл
                    else                                            ;иначе
                    {
                        
                        PixelGetColor, clr, %ThsPxX%, %ThsPxY%        ;получаем цвет текущего пиксела
                        if (FndClr = clr)                                ;если он соответствует искомому
                        %FndClr%[i, a_index] := 1                    ;записываем в массив 1
                        else                                        ;иначе
                        %FndClr%[i, a_index] := 0                    ;записываем 0
                    }
                }
            }
        }
}
;-----------------------------------------------------------------
RdStrng(StrngNmbr, MssvNm)
{
local rtrnvr
    Loop
    {
        if (%MssvNm%[%StrngNmbr%, %a_index%] = "")
        break
        rtrnvr := %rtrnvr% "." %MssvNm%[%StrngNmbr%, %a_index%]
    }
    return := rtrnvr
}
;------------------------------------------------------------------

RcrdInMssv(36,44,70,46,0xff0000)
mstxt := RdStrng(1, 0xff0000)
msgbox, %mstxt%

2

Re: AHK: Не разрывается цикл

Посмотрите чем занимается скрипт - lines most recently executed. Если всё происходит быстро, вставьте временные задержки (Sleep) и для контроля можно ещё MsgBox.

3 (изменено: NektoN95, 2015-08-02 22:15:55)

Re: AHK: Не разрывается цикл

Посмотрите чем занимается скрипт

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

P.S. Добавил коментарии что бы было понятнее.

4

Re: AHK: Не разрывается цикл

Сравнение надо заносить в скобки:

if (thspxx > x2)

5 (изменено: NektoN95, 2015-08-03 09:33:31)

Re: AHK: Не разрывается цикл

Заносил, как зацикливался, так и зацикливается Ток теперь не на 2м цикле, а на первом - значение текущего пиксела по Y (ThsPxY) не высчитывается.

P.S. Кинул полную на данный момент версию скрипта.

6

Re: AHK: Не разрывается цикл

Мой совет не помог?

7 (изменено: Irbis, 2015-08-04 01:30:43)

Re: AHK: Не разрывается цикл

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

#NoEnv
Process Priority,,High 
SetBatchLines -1

RcrdInMssv(36,44,39,48,0xff0000)
mstxt := RdStrng(1, 0xff0000)
msgbox, %mstxt%

;-----------------------------------------------------------------
RcrdInMssv(x1,y1,x2,y2,FndClr){
   local x, y, clr
   x1--, y1--
   %FndClr% := Object(), y:=y2-y1
   while y {
      x:=x2-x1
      while x {
         PixelGetColor, clr, x1+x, y1+y
         %FndClr%[x, y] := (FndClr = clr), x--
      } y--
   }
}
;-----------------------------------------------------------------
RdStrng(StrngNmbr, MssvNm){
local rtrnvr
    Loop % %MssvNm%.MaxIndex()
        rtrnvr .= %MssvNm%[A_Index, StrngNmbr]
    return % rtrnvr
}

По большому счету, для больших площадей PixelGetColor мало подходит ввиду очень медленной работы, рекомендую обратить взор в сторону бибилиотеки Gdip.

8

Re: AHK: Не разрывается цикл

При присвоении и так присваивается значение переменной (знаки процента не нужны).
Неправильно:

loop
   msgbox % i := %A_index%

Правильно:

loop
   msgbox % i := A_index

9 (изменено: NektoN95, 2015-08-03 19:54:19)

Re: AHK: Не разрывается цикл

Спасибо, только вот маленькая проблемка в этой строке:

Loop % %MssvNm%.MaxIndex()

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

Loop % %MssvNm%.%StrngNmbr%.MaxIndex()

но он ошибку пишет. Не подскажите, как написать правильно?

рекомендую обратить взор в сторону бибилиотеки Gdip.

Спасибо, обязательно.

И кстати, новую команду не обязательно писать с новой строки, достаточно через запятую написать?

10

Re: AHK: Не разрывается цикл

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

MaxIndex() возвращает количество столбцов. Ошибка была в функции чтения из массива - так как данные заносятся в виде [x, y], то для чтения строки A_Index должен быть первым, а второй индекс будет постоянным. Исправил в скрипте из #7:

rtrnvr .= %MssvNm%[A_Index, StrngNmbr]

И кстати, новую команду не обязательно писать с новой строки, достаточно через запятую написать?

Это уж как удобней/привычней. Автор AHK указывает, что однотипные операции (например присвоение переменным) дают в таком случае ускорение до 35%. Команды в привычном для АНК контексте (MsgBox, Sleep и пр.) вы так не запишете, а вот выражения и функции - пожалуйста.

11 (изменено: NektoN95, 2015-08-04 03:49:16)

Re: AHK: Не разрывается цикл

Irbis, спасибо. И вот еще что... Адаптировал скрипт под gdip

#NoEnv
#include Gdip_All.ahk
Process Priority,,High 
SetBatchLines -1
pToken := GDIP_StartUp()

F1::
RcrdInMssv(36,44,200,48,0xff0000)
msgbox, % RdStrng(1, 0xff0000)
return


Esc::
GDIP_DisposeImage(pBitMap)
GDIP_Shutdown(pToken)
ExitApp

;-----------------------------------------------------------------
RcrdInMssv(x1,y1,x2,y2,FndClr){
   local x, y, clr
   pBitMap := GDIP_BitmapFromScreen()
   x1--, y1--
   %FndClr% := Object(), y:=y2-y1
   while y {
      x:=x2-x1
      while x {
         clr := DEC2HEX(GDIP_GetPixel(pbitmap, x1+x, y1+y), "true")
         msgbox, % FndClr " " clr " " (FndClr = clr)
         %FndClr%[x, y] := (FndClr = clr), x--
      } y--
   }
}
;-----------------------------------------------------------------
RdStrng(StrngNmbr, MssvNm){
local rtrnvr
    Loop % %MssvNm%.MaxIndex()
        rtrnvr .= %MssvNm%[A_Index, StrngNmbr]
    return % rtrnvr
}
;-----------------------------------------------------------------
DEC2HEX(DEC, RARGB="false") {
    SetFormat, IntegerFast, hex
    RGB += DEC ;Converts the decimal to hexidecimal
    if(RARGB=="true")
        RGB := RGB & 0x00ffffff
    return RGB
}

Возникла проблемка: функция DEC2HEX (не моя) переводит скрипт в 16-рич. систему счисления. По завершении этой функции надо бы переводить скрипт обратно в десятичку, иначе результат сравнения (FndClr = clr) тоже записывается как 0x0 или 0x1, что как-бе не есть гуд. Но тогда результат функции DEC2HEX то же переводится в десятичку, что как-бе тоже не есть гуд, так-как в таком разе сравнение (FndClr = clr) вообще происходит с ошибкой, так как системы счисления разные. Как бы так зафиксировать в 16-ричной форме значение, возвращаемое DEC2HEX? Может можно как-то превратить переменную RGB из числовой в строковую, что-бы SetFormat её не затронул (хотя я не заметил, что бы переменные в ahk делились на типы)? Или еще как то?

12 (изменено: NektoN95, 2015-08-04 05:52:11)

Re: AHK: Не разрывается цикл

Обошел вышеназванную проблему таким манером

DEC2HEX(DEC, RARGB="false") {
    SetFormat, IntegerFast, hex
    RGB += DEC ;Converts the decimal to hexidecimal
    if(RARGB=="true")
        RGB := RGB & 0x00ffffff
    StringReplace, rgb, rgb, 0x
    SetFormat, IntegerFast, D
    rgb := "0x"RGB
    return RGB
}
}

Однако все же интересно, как это укоротить, так что вопрос не снимается.
И да, вот еще что, вы говорите MaxIndex() возвращает количество столбцов, а как получить количество строк таким-же манером?

13

Re: AHK: Не разрывается цикл

var := 16777215
MsgBox, % Format("{:#x}", var)
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14

Re: AHK: Не разрывается цикл

Заменил DEC2HEX новой функцией:

ARGBdec2RGBhex(var){
var := Format("{:#x}", var)
StringTrimLeft, var, var, 4
return % "0x"var
}

15

Re: AHK: Не разрывается цикл

var := 4294967295
MsgBox, % Format("{:#x}", var & 0xFFFFFF)
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

16 (изменено: NektoN95, 2015-08-04 13:54:43)

Re: AHK: Не разрывается цикл

var := 4294967295
MsgBox, % Format("{:#x}", var & 0xFFFFFF)

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

Loop % %MssvNm%.MaxIndex()

17

Re: AHK: Не разрывается цикл

%MssvNm%[1].MaxIndex()
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18 (изменено: NektoN95, 2015-08-04 17:50:04)

Re: AHK: Не разрывается цикл

Спасибо. Нусс... на этом всё, тему закрывать можно.

Update: Хотя не, потропился: применял её к массиву - возвращает пустое значение. Вот код:

#NoEnv
#include Gdip_All.ahk
Process Priority,,High 
SetBatchLines -1
pToken := GDIP_StartUp()

RcrdInMssv(23,30,236,37,0xff0000)
MsgBox % 0xff0000[1].MaxIndex()
return

RcrdInMssv(x1,y1,x2,y2,FndClr){
   local x, y, clr
   pBitMap := GDIP_BitmapFromScreen()
   x1--, y1--
   %FndClr% := Object(), y:=y2-y1
   while y {
      x:=x2-x1
      while x {
         clr := GDIP_GetPixel(pbitmap, x1+x, y1+y)
         clr := Format("{:#x}", clr & 0xFFFFFF)
         %FndClr%[x, y] := (FndClr = clr), x--
      } y--
   }
}

19

Re: AHK: Не разрывается цикл

Уф, наворотили сорок бочек арестантов. Вам бы попроще что-нибудь написать для начала. Попозже посмотрю.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

20 (изменено: Irbis, 2015-08-04 23:01:21)

Re: AHK: Не разрывается цикл

Причина в том, что с таким названием массива возвращает пустое значение. Некорректно принимает AHK числовое название объекта, пусть и начинается на "0x..". Добавь литеры вначале, так работает:

MsgBox % Arr0xff0000[1].MaxIndex()

И в функции везде смени  %FndClr% на Arr%FndClr%.
Можно просто любой незначащий символ, например $0xff0000[1] или _0xff0000[1].

21

Re: AHK: Не разрывается цикл

Irbis пишет:

По большому счету, для больших площадей PixelGetColor мало подходит ввиду очень медленной работы, рекомендую обратить взор в сторону бибилиотеки Gdip.

А насколько примерно быстрее, и в 18 посте на этот счёт всё правильно?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

22 (изменено: Irbis, 2015-08-05 11:04:08)

Re: AHK: Не разрывается цикл

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

Насчет правильности кода из #18 большие сомнения.

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

Во-вторых, не знаю откуда ТС позаимствовал пример, но во всех примерах по библиотеке Gdip уборка мусора остается на совести скриптописателя:

Exit:
GDIP_DisposeImage(pBitMap)
Gdip_Shutdown(pToken)
ExitApp

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

;#include Gdip_All.ahk
CoordMode, Mouse
OnExit, Exit
pToken := GDIP_StartUp()
pBitMap := GDIP_BitmapFromScreen()
Loop {
   MouseGetPos, x, y
   ToolTip % Format("{:#x}", GDIP_GetPixel(pbitmap, x, y) & 0xFFFFFF)
   Sleep 10
}
Esc::
Exit:
GDIP_DisposeImage(pBitMap)
Gdip_Shutdown(pToken)
ExitApp

23

Re: AHK: Не разрывается цикл

если брать для одиночной точки, то разницы практически не будет

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

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

24

Re: AHK: Не разрывается цикл

Мне тоже так кажется, даже наоборот - цикл с GDIP_GetPixel проиграет, поскольку крутиться он будет силами интерпретатора АНК, в отличие от написанной на С PixelSearch. Впрочем, никто же не мешает ускорить поиск точки в Bitmap при помощи машинных кодов. в Gdip.Ahk есть функция Gdip_PixelateBitmap, там как раз такой подход. Кмк, для поиска точки код будет относительно проще. (Для того, кто пишет на Asm'е).

25 (изменено: NektoN95, 2015-08-05 13:25:54)

Re: AHK: Не разрывается цикл

Причина в том, что с таким названием массива возвращает пустое значение.

Вон оно как... Спасибо.

во всех примерах по библиотеке Gdip уборка мусора остается на совести скриптописателя

Ну, я как-бе в курсе. В конце концов, это далеко не окончательная версия скрипта.

идея создавать в вызываемой процедуре глобальный массив попахивает авантюрой.

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

снимок экрана делается один раз, дальше обращений к экрану нет.

Ээ..., а какая функция GDI делает снимок?

И да, кстати мне вот тут понадобилось организовать связь между двумя скриптами (к сожалению стабильно они работают только по отдельности). Думаю сделать это через Send\OnMessage, в связи с этим вопрос, как получить идентификатор скрипта, если у него нет окна?

26

Re: AHK: Не разрывается цикл

Irbis пишет:

Мне тоже так кажется, даже наоборот - цикл с GDIP_GetPixel проиграет, поскольку крутиться он будет силами интерпретатора АНК, в отличие от написанной на С PixelSearch. Впрочем, никто же не мешает ускорить поиск точки в Bitmap при помощи машинных кодов. в Gdip.Ahk есть функция Gdip_PixelateBitmap, там как раз такой подход. Кмк, для поиска точки код будет относительно проще. (Для того, кто пишет на Asm'е).

Тут наверное только один YMP пишет. Да и алгоритм наверное проще не придумаешь.

Как оказалось Imagesearch есть, так понял что в функции Gdip_LockedBitsSearch используется машинный код. Аналог PixelSearch не нашёл.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

27

Re: AHK: Не разрывается цикл

NektoN95 пишет:

Ээ..., а какая функция GDI делает снимок?

GDIP_BitmapFromScreen()
Если есть какие-то вопросы по работе с библиотекой, имеется англоязычная справка с примерами.

В конце концов, это далеко не окончательная версия скрипта.

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

А кстати, как удалить массив из памяти?

Массив удаляется, когда удаляется последняя ссылка на него. (Как обычная переменная).

Имя_массива := ""

И да, кстати мне вот тут понадобилось организовать связь между двумя скриптами

На форуме были подобные темы, teadrinker недавно выкладывал вариант взаимодействия нескольких скриптов одновременно.

28 (изменено: NektoN95, 2015-08-05 15:33:06)

Re: AHK: Не разрывается цикл

Сделай вход-выход, основу скрипта

Это безусловно. Собственно, этим я сейчас и занимаюсь)

На форуме были подобные темы, teadrinker недавно выкладывал вариант взаимодействия нескольких скриптов одновременно.

А можно ссылочку? Пробовал искать через google (site:script-coding.com/forum/ взаимодействие скриптов), но чёт без толку. Хотя, возможно у меня шаролупие))

29

Re: AHK: Не разрывается цикл

Простой пример. Как обмениватся сообщениями между скриптами.
Более продвинутый вариант.Асинхронный запуск скриптов.

30

Re: AHK: Не разрывается цикл

NektoN95 пишет:

Ээ..., а какая функция GDI делает снимок?

Ээ..., а как этот вопрос связан с названием данной темы? NektoN95, одна тема — один вопрос, если возникли другие — создавайте новую.
Всем читать правила.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

31

Re: AHK: Не разрывается цикл

teadrinker, на будущее учту.