1

Тема: AHK: Аналог PixelChecksum

Столкнулся с проблемой - нужно знать, когда в одной области изменились цвета пикселей.
В интернете нашел только для AutoIt такую команду - http://autoit-script.ru/autoit3_docs/fu … ecksum.htm

Конечно, можно сделать "дуболомным" методом так (координаты взяты случайными):

pixelgetcolor, color1, 10, 10
pixelgetcolor, color2, 11, 11
pixelgetcolor, color3, 12, 12
pixelgetcolor, color4, 22, 22
pixelgetcolor, color5, 30, 30

F1::
pixelgetcolor, color11, 10, 10
pixelgetcolor, color22, 11, 11
pixelgetcolor, color33, 12, 12
pixelgetcolor, color44, 22, 22
pixelgetcolor, color55, 30, 30

if (color11 != color1 || color22 != color2 || color33 != color3 || color44 != color4 || color55 != color5)
MsgBox, Область изменилась!

if (color11 = color1 && color22 = color2 && color33 = color3 && color44 = color4 && color55 = color5)
MsgBox, Область НЕ изменилась!

Return

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

2 (изменено: serzh82saratov, 2014-08-21 10:36:42)

Re: AHK: Аналог PixelChecksum

Можно сравнивать как строки, без Аеро довольно быстро работает:


SetBatchLines -1 
CoordMode, Pixel, Screen
DllCall("dwmapi\DwmEnableComposition", "UInt", 0) 
res1 := PixelChecksum(0, 0, 111, 111)
MsgBox Результат готов.

1::
    If (PixelChecksum(0, 0, 111, 111) = res1)
        MsgBox, Область НЕ изменилась!
    Else
        MsgBox, Область изменилась!
    Return

PixelChecksum(x1, y1, x2, y2) {
    Loop % y2-y1+1
    { 
        y := y1+A_Index-1
        Loop % x2-x1+1
        {
            PixelGetColor, c, x1+A_Index-1, y 
            sum .= c "|" 
        }
    }      
    Return sum
}  

Хотя возможно что через GDIP можно правильнее сделать, не знаю.

Вы ради интереса сравните время получения результатов на autoit и анк.

Есть такой вариант, но у меня реагирует не на все изменения в окне.

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

3 (изменено: Странникх, 2014-08-22 20:25:54)

Re: AHK: Аналог PixelChecksum

Данный вариант медленнее. Он ведь сравнивает целую строчку.

Вот если бы скажем он сравнивал, например, так (y, x): 20, 5 -> 20, 10 -> 20, 15 -> 20, 20 , то было бы намного быстрее. Я не знаю как кому что нужно, может кому и нужно сравнивение чистой линии, но для моего скрипта - я сравниваю разные пиксели в разных координатах одной области. Беру около 3-6 пикселей, чтобы результат поиска был быстрее и довольствуюсь этим.

Однако у меня опять таки пиксели ищутся все сразу и сравниваются также, а в Вашем варианте я вижу такую схему:
Ищется первый пиксель -> сравнивается с запомненным пикселем -> 1) если цвет пикселя равен запомненному, то перейти ко второму поиску пикселя. 2) если не равен запомненную, то вывести сообщение об ошибке. С точки зрения быстродействия этот вариант больше подходит, но как "впихнуть" в Ваш код я опять не имею представления.. во всяком случае пока что, ибо Ваш код выглядит не понятно и сложно для меня.

4 (изменено: Alectric, 2014-08-24 08:43:23)

Re: AHK: Аналог PixelChecksum

Попробуй так (на основе serzh82saratov):

#SingleInstance,force
SetBatchLines -1
CoordMode,tooltip,Screen
CoordMode,Pixel,Screen
;DllCall("dwmapi\DwmEnableComposition", "UInt", 0)


x1=400
x2=400
y1=600
y2=500
coef=5  ; coef - сколько точек проверять на всей области
res1:=PixelChecksum(x1,x2,y1,y2,coef)

loop
{
  sleep,30
  If (PixelChecksum(x1,x2,y1,y2,coef)=res1)
    tooltip,Область НЕ изменилась!
  Else
  {
    tooltip,`nИзменилась!`n_
    sleep,2000
    res1:=PixelChecksum(x1,x2,y1,y2,coef)
  }
}
Return

PixelChecksum(x1,y1,x2,y2,coef)  ; coef - сколько точек проверять на всей области
{
  xc:=Round((x2-x1)/coef)
  yc:=Round((y2-y1)/coef)
  if xc<1
    xc=1
  if yc<1
    yc=1
  yy:=xx:=0
  Loop
  {
    if (yy>y2-y1)
      break
    y:=y1+yy
    Loop
    {
      if (xx>x2-x1)
        break
      tooltip,%xx%,% x1+xx+3,% y+3,3
      PixelGetColor,c,x1+xx,y
      sum.=c
      xx+=xc
    }
    yy+=yc
    xx=0
  }
  yy=0
  Return sum
}

Убери "tooltip" из функции и можно работать.

Win 10 x64
AHK v1.1.33.02
                       Справка тебе в помощь.

5

Re: AHK: Аналог PixelChecksum

Вот если бы скажем он сравнивал, например, так (y, x): 20, 5 -> 20, 10 -> 20, 15 -> 20, 20 , то было бы намного быстрее.

Ну тогда просто передавайте свои координаты:


coords := [[311,44],[484,80],[591,175],[591,292],[482,387]
        ,[306,424],[127,387],[20,292],[22,175],[131,80]] 
        
res := PixelChecksum(coords)
MsgBox % res 

1::
    If (PixelChecksum(coords) = res)
        MsgBox, Область НЕ изменилась!
    Else
        MsgBox, Область изменилась!
    Return

PixelChecksum(coords) {
    For k, v in coords
    {
        PixelGetColor, c, v[1], v[2]
        sum .= c "|"
    }
    Return sum
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

6 (изменено: Irbis, 2014-08-23 20:50:28)

Re: AHK: Аналог PixelChecksum

Заинтересовала тема, тем более подобные вопросы возникают регулярно. В результате получилось так:
Процедура PixelCheck() работает в 2х режимах - задание точек или проверка ранее заданных. Она хранит в локальных массивах наборы точек и цветовые значения, так что координаты каждый раз передавать не нужно. Наборов может быть любое количество, как и проверяемых точек в наборе, задаются они так:

PixelCheck(N, X1,Y1, X2, Y2, ...)

где N - номер набора (слота), X1 Y1 и т.д. - координаты 1ой и последующих точек.
В таком случае проверка точек на совпадение будет такой:

if PixelCheck(N)
{
; Не изменились
}
else
{
; Изменились
}

И небольшой код для демонстации. При запуске в слот №1 сохраняются координаты и цвет одной точки (50,16), в слот №2 координаты и цвет двух других точек. По клавишам F1 и F2 появляются сообщения о состоянии проверки.

SetBatchLines -1
CoordMode, Pixel
PixelCheck(1, 50,16)
PixelCheck(2, 1100,240, 910,150)
Return

F1::
MsgBox % PixelCheck(1) ? "Не изменилось (1)" : "Изменилось (1)"
Return

F2::
MsgBox % PixelCheck(2) ? "Не изменилось (2)" : "Изменилось (2)"
Return

PixelCheck(P*)
{
   Static X:=[], Y:=[], C:=[], N:=[]
   Slot := P[1]
   if P.MaxIndex() > 1 && N[Slot] := P.MaxIndex()>>1 
      Loop % N[Slot] {
         PixelGetColor, Ctmp, X[(Slot<<4)+A_index] := P[A_Index<<1], Y[(Slot<<4)+A_index] := P[(A_Index<<1)+1]
         C[(Slot<<4)+A_index] := Ctmp
      }
   else
   Loop % N[Slot] {
      PixelGetColor, Ctmp, X[(Slot<<4)+A_index], Y[(Slot<<4)+A_index]
      if (Ctmp != C[(Slot<<4)+A_index])
         Return 0
   }  
   Return 1
}

Небольшое ограничение - для чуть большего быстродействия массивы для Х,Y и С(color, цвет) сделаны непрерывными, т.е. все координаты и цвета хранятся по порядку. На практике это означает, для одного слота может быть задано не более 16 точек. Если надо больше, например проверять 32 точки, то Slot<<4 надо заменить массово на Slot<<5.

7

Re: AHK: Аналог PixelChecksum

Гениальное воплощение. Огромное спасибо!

Один вопрос - они по очереди сравниваются или одновременно?

PixelCheck(2, 1100,240, 910,150)

8

Re: AHK: Аналог PixelChecksum

Пожалуйста. )
Непонятно, что подразумевается под "одновременно" - если это относится к алгоритму из поста #3, то сравнение всех точек не требуется. При несовпадении цвета в координатах 1100,240 функция PixelCheck сразу вернет 0, вторая пара координат проверяться не будет.

9

Re: AHK: Аналог PixelChecksum

При несовпадении цвета в координатах 1100,240 функция PixelCheck сразу вернет 0, вторая пара координат проверяться не будет.

Именно это и хотел узнать.

10

Re: AHK: Аналог PixelChecksum

Немного модернизировал функцию PixelCheck().
Размер слота вычисляется один раз при вызове функции (Pos := Slot << 8)
Сделал по умолчанию размер одного слота на 256 точек, так как даже для 20 слотов размер необходимой памяти будет порядка ~5килобайт для каждой координаты, что несущественно для современных объемов оперативной памяти.
Вынес получение цвета (PixelGetColor) за пределы функции, для облегчения последующих модификаций, если такие потребуются. )

PixelCheck(P*)
{
   Static X:=[], Y:=[], C:=[], N:=[]
   Slot := P[1], Pos:= Slot << 8
   if P.MaxIndex() > 1 && N[Slot] := P.MaxIndex()>>1 
      Loop % N[Slot]
         C[Pos+A_index]:=PGColor(X[Pos+A_index]:=P[A_Index<<1],Y[Pos+A_index]:=P[(A_Index<<1)+1])
   else
   Loop % N[Slot]
      if (PGColor(X[Pos+A_index], Y[Pos+A_index]) != C[Pos+A_index])
         Return 0
   Return 1
}

PGColor(x,y)
{
   PixelGetColor, c, x, y
   Return c
}

11 (изменено: Malcev, 2014-08-27 02:03:02)

Re: AHK: Аналог PixelChecksum

serzh82saratov пишет:

Можно сравнивать как строки, без Аеро довольно быстро работает:


SetBatchLines -1 
CoordMode, Pixel, Screen
DllCall("dwmapi\DwmEnableComposition", "UInt", 0) 
res1 := PixelChecksum(0, 0, 111, 111)
MsgBox Результат готов.

1::
    If (PixelChecksum(0, 0, 111, 111) = res1)
        MsgBox, Область НЕ изменилась!
    Else
        MsgBox, Область изменилась!
    Return

PixelChecksum(x1, y1, x2, y2) {
    Loop % y2-y1+1
    { 
        y := y1+A_Index-1
        Loop % x2-x1+1
        {
            PixelGetColor, c, x1+A_Index-1, y 
            sum .= c "|" 
        }
    }      
    Return sum
}  

Хотя возможно что через GDIP можно правильнее сделать, не знаю.

Вы ради интереса сравните время получения результатов на autoit и анк.

Есть такой вариант, но у меня реагирует не на все изменения в окне.

У меня с офф.форума тоже не реагирует.
А твой скрипт обрабатывает за 2 секунды, раньше кустарным методом я тратил 9. Респект!
Вот кто бы из разбирающихся в Gdip поправил бы этот код для сравнения скоростей.

; Example - Wait for a Screen Region to change
ChkSum := PixelChecksum( 0,0,10,10 )
While % ( ChkSum = PixelChecksum( 0,0,10,10 ) )
  Sleep, 100
MsgBox, Screen Region Change Detected!
Return

PixelCheckSum( X, Y, W, H, Title ) {
 hWn := WinExist( Title ), hDC := DllCall( "GetDC", UInt,hWn )
 mDC := DllCall( "CreateCompatibleDC", UInt,hDC )
 NumPut( VarSetCapacity(BI,40,0),BI ), NumPut( W,BI,4 ) , NumPut( H,BI,8 )
 NumPut( 32,NumPut( 1,BI,12,"UShort" ),0,"UShort" )     , NumPut( 0,BI,16 )
 hBM := DllCall( "CreateDIBSection", UInt,mDC, UInt,&BI , Int,0, UIntP,pB, Int,0,Int,0 )
 oBM := DllCall( "SelectObject", UInt,mDC, UInt,hBM )   , Rop := 0x40000000|0x00CC0020
 DllCall( "BitBlt", UInt,mDC, Int,0,Int,0, Int,W,Int,H, UInt,hDC, Int,X,Int,Y, UInt,Rop )
 DllCall( "shlwapi\HashData", UInt,pB, UInt,W*H*4, Int64P,Hash, UInt,8 )
 VarSetCapacity(HH,16,0), DllCall( "msvcrt\sprintf", Str,HH, Str,"%016I64X",UInt64,Hash )
 DllCall( "DeleteObject", UInt,hBM ), DllCall( "DeleteObject", UInt,oBM )
 DllCall( "DeleteDC", UInt,mDC ), DllCall( "ReleaseDC", UInt,hWn, UInt,hDC )
Return HH
}

12 (изменено: Malcev, 2014-08-31 22:30:21)

Re: AHK: Аналог PixelChecksum

Оказывается скрипт рабочий. Срабатывает моментально.
Правда только для 32-бит ahk.
Кто подскажет, как его перевести для 64?
И вообще, как это делается? Может сделать faq?
Пока понял только, что UInt надо менять на Ptr.
Но все-равно не работает.

13 (изменено: Malcev, 2014-09-01 11:47:52)

Re: AHK: Аналог PixelChecksum

Автор этой функции - SKAN переделал ее под x64.
Хороший подарок на День знаний

; Example - Wait for a Screen Region to change

ChkSum := PixelChecksum( 0,0,32,32 )

While % ( ChkSum = PixelChecksum( 0,0,32,32 ) )
   Sleep, 100
MsgBox, Screen Region Change Detected!

/*   __    __  __          __ __       __    __                 _       __                  
    / /_  / /_/ /_____  _ / // /____ _/ /_  / /________________(_)___  / /_ ____  _______
   / __ \/ __/ __/ __ \(_) // // __ '/ __ \/ //_/ ___/ ___/ __/ / __ \/ __// __ \/ __/ _ \
  / / / / /_/ /_/ /_/ / / // // /_/ / / / / ,< (__  ) /__/ / / / /_/ / /__/ /_/ / / / // /
 /_/ /_/\__/\__/ .___(_) // / \__,_/_/ /_/_/|_/____/\___/_/ /_/ .___/\__(_)____/_/  \__ /  
              /_/     /_//_/                                 /_/                   (___/  
 
 http://ahkscript.org/boards/viewtopic.php?&t=4431
__________________________________________________________________________________________
*/

PixelCheckSum( X, Y, W, H, Title := "" ) { ;               By SKAN,   http://goo.gl/X5dfvn
;                                                          CD:08/Jun/2009 | MD:01/Sep/2014

  Static DIBSECTION, SRCCOPY := 0x00CC0020, CAPTUREBLT := 0x40000000, BPP := 32
  Local hWnd, hDC, mDC, hBM, oBM, nSize, pBITMAPINFOHEADER, ppvBits := 0
 
  If not VarSetCapacity( DIBSECTION )
         VarSetCapacity( DIBSECTION, 104, 0 )
 
  pBITMAPINFOHEADER := &DIBSECTION + ( A_PtrSize = 4 ? 24 : 32 )
 
  NumPut(  40, pBITMAPINFOHEADER +  0, "UInt"   )
  NumPut(   W, pBITMAPINFOHEADER +  4, "UInt"   )
  NumPut(   H, pBITMAPINFOHEADER +  8, "UInt"   )
  NumPut(   1, pBITMAPINFOHEADER + 12, "UShort" )
  NumPut( BPP, pBITMAPINFOHEADER + 14, "UShort" )

  hWnd  := WinExist( Title )
  hDC   := DllCall( "GetDC", "Ptr",hWnd, "UPtr" )
  mDC   := DllCall( "CreateCompatibleDC", UInt,hDC, "UPtr" )

  hBM   := DllCall( "CreateDIBSection", "Ptr", mDC, "Ptr", pBITMAPINFOHEADER, "Int",0
                                      , "PtrP",ppvBits, "Ptr",0, "Int",0, "UPtr" )
 
  oBM   := DllCall( "SelectObject", "Ptr",mDC, "Ptr",hBM, "UPtr" )
 
  DllCall( "BitBlt", "Ptr",mDC, "Int",0, "Int",0, "Int",W, "Int",H, "Ptr",hDC
                   , "Int",X, "Int",Y, "UInt",SRCCOPY | CAPTUREBLT )

  DllCall( "SelectObject", "Ptr",mDC, "Ptr",oBM )
  DllCall( "DeleteDC",  "Ptr",mDC )
  DllCall( "ReleaseDC", "Ptr",hWnd, "Ptr",hDC )

  DllCall( "GetObject", "Ptr",hBM, "Int",( A_PtrSize = 4 ? 84 : 104 ), "Ptr",&DIBSECTION )
  nSize := NumGet( pBITMAPINFOHEADER + 20, "UInt" )
 
Return DllCall( "NTDLL\RtlComputeCrc32", "UInt",0, "Ptr",ppvBits, "UInt",nSize, "UInt" )
     , DllCall( "DeleteObject", "Ptr",hBM )    
}

http://ahkscript.org/boards/viewtopic.php?&t=4431