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

8

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

teadrinker пишет:

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

Здравствуйте! У меня задача похожая, и, думаю, bitmap - это именно то, что мне нужно, но есть пара нюансов:
- мне нужно получать цвет по определённым координатам;
- пока что я смотрю на это всё как баран на новые ворота. Понимание "это класс, а это объект, а dll - это что-то системное" не сильно мне помогает. Вас не затруднит снабдить код комментариями?

9

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

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

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

10

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

По моим замерам один PixelGetColor занимает 15-16 мс. И когда их число уверенно движется к сотне, это становится проблемой. Не разгуляешься.
Жаль, ладно, будем искать.

11

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

Вам нужно на одном и том же скриншоте разные пиксели получать?

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

12

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

Да.

13

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

Попробуйте так:

x := 100 ; координаты области относительно экрана
y := 100
w := 500
h := 500

xPix := 20 ; координаты пикселя внутри области
yPix := 20 ; левый верхний будет xPix := 1, yPix := 1

hBitmap := HBitmapFromScreen(x, y, w, h, pBits)
MsgBox, % pixelColor := GetPixel(pBits, w * 4, xPix, yPix)

HBitmapFromScreen(X, Y, W, H, ByRef pBits := "") {
   hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
   hBM := CreateDIBSection(W, -H, pBits)
   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", SRCCOPY := 0x00CC0020)
   DllCall("SelectObject", "Ptr", hMDC, "Ptr", hObj, "Ptr")
   DllCall("DeleteDC", "Ptr", hMDC)
   DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
   Return hBM
}

CreateDIBSection(w, h, ByRef ppvBits := 0, bpp := 32) {
   hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
   VarSetCapacity(BITMAPINFO, 40, 0)
   NumPut(40 , BITMAPINFO,  0)
   NumPut( w , BITMAPINFO,  4)
   NumPut( h , BITMAPINFO,  8)
   NumPut( 1 , BITMAPINFO, 12)
   NumPut(bpp, BITMAPINFO, 14)
   hBM := DllCall("CreateDIBSection", "Ptr", hDC, "Ptr", &BITMAPINFO, "UInt", 0, "PtrP", ppvBits, "Ptr", 0, "UInt", 0, "Ptr")
   DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
   return hBM
}

GetPixel(pBits, stride, x, y) {
   ; или NumGet(pBits + (x - 1) * 4 + stride * (y - 1), "UInt") & 0xFFFFFF если не нужно форматировать
   Return Format("{:#x}", NumGet(pBits + (x - 1) * 4 + stride * (y - 1), "UInt") & 0xFFFFFF)
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14 (изменено: Qp, 2023-10-11 12:18:17)

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

Спасибо, работает! Но есть проблема: смотрит сквозь изображение, сгенерированное аддоном к игре.
Используя добавление к вашему коду

while (yPix < 82)
{
MouseMove, xPix, yPix, 20
Sleep, 50
pixelColor := GetPixel(pBits, w * 4, xPix, yPix)
FileAppend, %pixelColor%`n, D:\AHK\bitmap\log.txt
yPix++
}

, я вижу, что скрипт проверяет цвет именно по тем координатам, что мне надо, но сиреневый квадратик (0xFF00E9) он не видит, видит то, что за ним.

Post's attachments

bittest.png
bittest.png 2.03 kb, 9 downloads since 2023-10-11 

You don't have the permssions to download the attachments of this post.

15

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

Я по играм не спец, может, коллега Malcev что-то подскажет.

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

16

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

Я подумал, может, в координатах напутал - устроил поиск 100*100:

x := 0 ; координаты области относительно экрана
y := 0
w := 600
h := 100

xPix := 1 ; координаты пикселя внутри области 0xFF00E9
yPix := 1 ; левый верхний будет xPix := 1, yPix := 1

hBitmap := HBitmapFromScreen(x, y, w, h, pBits)

while (xPix < 100)
	{
	FileAppend, `nновый столбец`n, D:\AHK\bitmap\log.txt
	while (yPix < 100)
		{
		pixelColor := GetPixel(pBits, w * 4, xPix, yPix)
		FileAppend, %pixelColor%`n, D:\AHK\bitmap\log.txt
		yPix++
		}
	yPix := 1
	xPix++
	}

- нет, нету. А там, где чёрная полоса, пишет просто 0 вместо 0x000000.

17

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

Попробуйте заменить 0x00CC0020 на 0x40CC0020.

18

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

Извините за долгое молчание, то ездил, то болел.
Заменил. Теперь pixelColor всегда равен 0.