1

Тема: AHK: Одновременный поиск нескольких пикселей

Здравствуйте.
Не мог бы кто подсказать как сделать так что бы PixelSearch искал несколько разных пикселей в одной и той же области.

Имеется код:

+ открыть спойлер
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.




#Persistent
SetBatchLines, -1  
SetTimer, S1, 0
Pause

*~XButton2::
Loop
	{
S1:
MouseGetPos, xpos, ypos
zX1:=xpos-5,zX2:=xpos+5,zY1:=ypos-5,zY2:=ypos+5
PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000001, 4, Fast RGB
PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000002, 2, Fast RGB
PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000003, 1, Fast RGB

if !ErrorLevel
{
;Sleep, 10
;MouseMove, VarX, VarY
;moveAmount := (moveAmount = 2) ? 3 : 0
;mouseXY(moveAmount,1000)
MouseClick ,, ;	VarX, VarY,, 0
SetTimer, S1, Off
SetTimer, S2, -50
}
	If !GetKeyState("XButton2", "P")
		         Break
   }
Return
mouseXY(VarX,VarY)
{
DllCall("mouse_event",int,1,int,x,int,y,uint,0,uint,0)
}

End::ExitApp 

S2:
SetTimer, S1, On 
Return

Цвета взяты просто для примера:

PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000001, 4, Fast RGB
PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000002, 2, Fast RGB
PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000003, 1, Fast RGB

Это совершенно разные цвета и "подбор тонна" сюда не подходит. (0-255 перед фаст)

Но в данном случае ищет только последнюю строчку PixelSearch, а нужно что бы искало все 3 варианта одновременно.
Есть мысль по поводу If и Else, но не понимаю как это реализовать, да и кажется что это будет малоэффективно так как на перебор условий уйдёт слишком много времени я полагаю.

Может быть есть другой вариант?

Если нет то можно небольшой пример с If Else и PixelSearch?

Спасибо!

2

Re: AHK: Одновременный поиск нескольких пикселей

Я код не запускал, но с виду всё правильно. Просто вот здесь

PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000001, 4, Fast RGB
PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000002, 2, Fast RGB
PixelSearch, VarX, VarY, zX1, zY1, zX2, zY2, 0x000003, 1, Fast RGB

Вы сохраняете значения в одни и те же переменные три раза подряд. То есть каждый последующий проход "затирает" предыдущий. Логично предложить так:


PixelSearch, VarX_1, VarY_1 zX1, zY1, zX2, zY2, 0x000001, 4, Fast RGB
PixelSearch, VarX_2, VarY_2, zX1, zY1, zX2, zY2, 0x000002, 2, Fast RGB
PixelSearch, VarX_3, VarY_3, zX1, zY1, zX2, zY2, 0x000003, 1, Fast RGB

3

Re: AHK: Одновременный поиск нескольких пикселей

Много времени уходит на тройной PixelSearch, потому что каждый раз команда делает новый снимок экрана и ищет "с нуля".
Есть функции для замены PixelSearch, которые будут работать в три раза (в данном случае) быстрее. Поищите на форуме, если интересно.

4

Re: AHK: Одновременный поиск нескольких пикселей

stealzy извините, речь идёт о GDI+ (GDIP)?

ypppu спасибо я понял и исправил "это недоразумение", но при вводе даже второй "переменной" код начинает работать некорректно, я не говорю уже о 3-ей и 4-ой... При попытке найти 2-ой совершенно другой цвет, мышь начинает кликать на все возможные цвета, в чем может быть проблема?

Приблизительный код: (новый)

+ открыть спойлер
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.




#Persistent
SetBatchLines, -1  
SetTimer, S1, 0
Pause

*~XButton2::
Loop
	{
S1:
MouseGetPos, xpos, ypos
zX1:=xpos-5,zX2:=xpos+5,zY1:=ypos-5,zY2:=ypos+5
PixelSearch, VarX_1, VarY_1, zX1, zY1, zX2, zY2, 0x000001, 4, Fast RGB
PixelSearch, VarX_2, VarY_2, zX1, zY1, zX2, zY2, 0x000002, 2, Fast RGB

if !ErrorLevel
{
;Sleep, 10
;MouseMove, VarX, VarY
;moveAmount := (moveAmount = 2) ? 3 : 0
;mouseXY(moveAmount,1000)
MouseClick ,, ;	VarX_1, VarY_1,, 0
MouseClick ,, ;	VarX_2, VarY_2,, 0
SetTimer, S1, Off
SetTimer, S2, -50
}
	If !GetKeyState("XButton2", "P")
		         Break
   }
Return
mouseXY(VarX,VarY)
{
DllCall("mouse_event",int,1,int,x,int,y,uint,0,uint,0)
}

End::ExitApp 

S2:
SetTimer, S1, On 
Return

5

Re: AHK: Одновременный поиск нескольких пикселей

stealzy пишет:

Есть функции для замены PixelSearch, которые будут работать в три раза (в данном случае) быстрее. Поищите на форуме, если интересно.

Искал PixelSearch одновремен*, не нашёл. По каким словам?

6 (изменено: isxodnik, 2022-04-12 07:44:02)

Re: AHK: Одновременный поиск нескольких пикселей

Или сформулирую точнее:
как выполнить несколько (в моём случае 25) PixelSearch по одному скриншоту?
или иным способом снизить время выполнения нескольких PixelSearch до приемлемых (десятки миллисекунд) величин?

или, если вы ТОЧНО знаете, что в АНК это невозможно, дайте мне знать, пожалуйста.

Заодно - то же самое для PixelGetColor.

7

Re: AHK: Одновременный поиск нескольких пикселей

Если нужно много раз искать цвет на одном скриншоте, попробуйте такое:

color1 := 0x123456
color2 := 0xabcdef

FastPixel := new FastPixelSearch(0, 0, A_ScreenWidth, A_ScreenHeight)
res1 := FastPixel.Search(color1)
res2 := FastPixel.Search(color2)

if !res1
   MsgBox, Color %color1% not found
else
   MsgBox, % "x: " . res1.x . "`ny: " . res1.y

if !res2
   MsgBox, Color %color2% not found
else
   MsgBox, % "x: " . res2.x . "`ny: " . res2.y

class FastPixelSearch
{
   __New(x, y, w, h) {
      this.hBM := this.Api.HBitmapFromScreen(x, y, w, h, pvBits)
      this.pvBits := pvBits
      this.w := w
      this.size := w*h
   }
   
   Search(colorRGB) {
      static bin := 0
      (!bin && bin := this.Api.GetBin())
      (!(colorRGB >> 24) && colorRGB |= 0xFF000000)
      byte := DllCall(bin, "ptr", this.pvBits, "UInt", this.size, "UInt", colorRGB, "Int")
      if (byte == this.pvBits + this.size * 4)
         Return false
      offset := (byte - this.pvBits)//4
      Return {x: mod(offset, this.w), y: offset//this.w}
   }
   
   class Api
   {
      GetBin() {
         static PAGE_EXECUTE_READWRITE := 0x40, CRYPT_STRING_BASE64 := 0x1
         ; C source code - https://godbolt.org/z/oYx39nr5s
         code := A_PtrSize = 8 ? "idJIjQSRSDnBcw9EOQF1BInI6wZIg8EE6+zD"
                               : "VYnli1UIi0UMi00QjQSCOcJzDTkKdQSJ0OsFg8IE6+9dww=="
         size := StrLen( RTrim(code, "=") )*3//4
         bin := DllCall("GlobalAlloc", "UInt", 0, "Ptr", size, "Ptr")
         DllCall("VirtualProtect", "Ptr", bin, "Ptr", size, "UInt", PAGE_EXECUTE_READWRITE, "UIntP", old:=0)
         DllCall("crypt32\CryptStringToBinary", "Str", code, "UInt", 0, "UInt", CRYPT_STRING_BASE64
                                              , "Ptr", bin, "UIntP", size, "Ptr", 0, "Ptr", 0)
         Return bin
      }
      
      HBitmapFromScreen(X, Y, W, H, ByRef pvBits) {
         static rop := (SRCCOPY := 0x00CC0020) | (CAPTUREBLT := 0x40000000)
         hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
         hBM := this.CreateDIBSection(W, H, hDC, pvBits)
         hMDC := DllCall("CreateCompatibleDC", "Ptr", hDC, "Ptr")
         hObj := DllCall("SelectObject", "Ptr", hMDC, "Ptr", hBM, "Ptr")
         DllCall("BitBlt", "Ptr", hMDC, "Int", 0, "Int", 0, "Int", W, "Int", H
                         , "Ptr", hDC, "Int", X, "Int", Y, "UInt", rop)
         DllCall("SelectObject", "Ptr", hMDC, "Ptr", hObj, "Ptr")
         DllCall("DeleteDC", "Ptr", hMDC)
         DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
         Return hBM
      }

      CreateDIBSection(w, h, hDC, ByRef pvBits) {
         VarSetCapacity(BITMAPINFO, 40, 0)
         NumPut(40, BITMAPINFO,  0)
         NumPut( w, BITMAPINFO,  4)
         NumPut(-h, BITMAPINFO,  8)
         NumPut( 1, BITMAPINFO, 12)
         NumPut(32, BITMAPINFO, 14)
         hBM := DllCall("CreateDIBSection", "Ptr", hDC, "Ptr", &BITMAPINFO, "UInt", 0
                                          , "PtrP", pvBits, "Ptr", 0, "UInt", 0, "Ptr")
         return hBM
      }
   }
   
   __Delete() {
      DllCall("DeleteObject", "Ptr", this.hBM)
   }
}

Скриншот здесь берётся один раз, когда выполняется строка:

FastPixel := new FastPixelSearch(0, 0, A_ScreenWidth, A_ScreenHeight)
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder