Use GDI+ to do image search?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
980322091
Posts: 10
Joined: 15 Feb 2017, 12:17

Use GDI+ to do image search?

Post by 980322091 » 05 Mar 2017, 23:46

I am using ImageSearch to search a bitmap image in a loop, however it causes my screen lag sometimes. I did some research and found out that I can use GDI+ instead, I just got into ahk and never heard of GDI+, can someone give me a example how it works? and maybe offer me some useful link? Thanks.


980322091
Posts: 10
Joined: 15 Feb 2017, 12:17

Re: Use GDI+ to do image search?

Post by 980322091 » 06 Mar 2017, 14:43

I still need help please.

User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Use GDI+ to do image search?

Post by jeeswg » 08 Mar 2017, 23:54

This is actually pretty fiddly if you're new to Gdip.ahk/Gdip_All.ahk. Plus you need to include an add-on script: Gdip_ImageSearch.ahk.
HTH

Code: Select all

;put Gdip.ahk (or Gdip_All.ahk) and Gdip_ImageSearch.ahk into:
;C:\Program Files\AutoHotkey\Lib

;at GitHub, right-click the Raw button to save the ahk file
;Gdip/Gdip.ahk at master · tariqporter/Gdip · GitHub
;https://github.com/tariqporter/Gdip/blob/master/Gdip.ahk
;Gdip_All.ahk
;https://www.dropbox.com/s/0e9gdfetbfa8v0o/Gdip_All.ahk
;AutoHotkey/Gdip_ImageSearch.ahk at master · MasterFocus/AutoHotkey · GitHub
;https://github.com/MasterFocus/AutoHotkey/blob/master/Functions/Gdip_ImageSearch/Gdip_ImageSearch.ahk

;an example of a regular ImageSearch:
;My first project: How hard/easy it is to develop a script for this? - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?p=131491#p131491

q::
vPathN := A_Desktop "\MyNeedleImage.png"
vPathH := A_Desktop "\MyHaystackImage.png"

vScreen1 := 0
vScreen2 := 0
vScreen3 := A_ScreenWidth
vScreen4 := A_ScreenHeight
vScreen := vScreen1 "|" vScreen2 "|" vScreen3 "|" vScreen4
vPos1 := 0, vPos2 := 0, vPos3 := vScreen3, vPos4 := vScreen4

pToken := Gdip_Startup()
vMode := "s"
;vMode := "f"
if (vMode = "s") ;haystack is screen
	pBitmapH := Gdip_BitmapFromScreen(vScreen, 0x40CC0020)
if (vMode = "f") ;haystack is another image
{
	pBitmapH := Gdip_CreateBitmapFromFile(vPathH)
	Gdip_GetDimensions(pBitmapH, vPos3, vPos4)
	MsgBox, % vPos3 " " vPos4
}
pBitmapN := Gdip_CreateBitmapFromFile(vPathN)
;vRet: 0=not found, 1=found
vRet := Gdip_ImageSearch(pBitmapH, pBitmapN, vPosXY, vPos1, vPos2, vPos3, vPos4)
vPos := InStr(vPosXY, ",")
vPosX := SubStr(vPosXY, 1, vPos-1)
vPosY := SubStr(vPosXY, vPos+1)
Gdip_DisposeImage(pBitmapH)
Gdip_DisposeImage(pBitmapN)
Gdip_Shutdown(pToken)
MsgBox, % vRet " (" vPosXY ")"
;MsgBox, % vPosX " " vPosY
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 12 Mar 2021, 14:03

Sorry for reviving an old post

My %Ret% value always shows as 1 (1 instance found) Even if my needle nor my haystack is visible on screen. What could be the reason for this?

My Haystack and Needle : https://imgur.com/a/AHvHxwm

User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Use GDI+ to do image search?

Post by boiler » 12 Mar 2021, 19:23

It depends on what is in the bitmap for which you provided the pointer when you called the function. Unless you created a bitmap of the whole screen, then it’s not likely that the bitmap being searched contains both instances.

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 13 Mar 2021, 01:43

Im sorry to bother you, im not that advanced in coding. What do you mean when you said "It depends on what is in the bitmap for which you provided the pointer when you called the function"? Am i understanding this right, my haystack and needle are wrong?

And one last question, is the %RET% value (instances found) from the number of times the Needle was found? or the number of times the Haystack was found?

User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Use GDI+ to do image search?

Post by boiler » 13 Mar 2021, 07:28

The bitmap you identify as your haystack doesn’t need to be visible on the screen for GDI+ to search it, unlike AutoHotkey’s built-in ImageSearch command. If you want to search only what’s visible, you can use that. Why did you choose to use GDI+ to search for your image?

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 13 Mar 2021, 09:33

boiler wrote:
13 Mar 2021, 07:28
The bitmap you identify as your haystack doesn’t need to be visible on the screen for GDI+ to search it, unlike AutoHotkey’s built-in ImageSearch command. If you want to search only what’s visible, you can use that. Why did you choose to use GDI+ to search for your image?
I wanted to search for an image even if my application/game is not in focus (behind other windows). My problem is it always shows 1 instance even if that Needle and Haystack is not visible anywhere. Its driving me insane.

thanks again for the reply

User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Use GDI+ to do image search?

Post by boiler » 13 Mar 2021, 09:55

The haystack needs to be captured from your game window, not some separate image that you’ve already saved and are referring to as the haystack. Are you capturing images from your game in real time as new haystacks?

Are you perhaps using an allowable variation so large that you image is always found no matter what?

You should show your script because your question in general cannot be answered since this isn’t how it would work if things were set up properly.

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 13 Mar 2021, 10:31

boiler wrote:
13 Mar 2021, 09:55
The haystack needs to be captured from your game window, not some separate image that you’ve already saved and are referring to as the haystack. Are you capturing images from your game in real time as new haystacks?

Are you perhaps using an allowable variation so large that you image is always found no matter what?

You should show your script because your question in general cannot be answered since this isn’t how it would work if things were set up properly.
Here is my script

Code: Select all

#NoEnv
#SingleInstance Force
SetBatchLines, -1
Process, Priority,, High
SetTitleMatchMode, 3
#Include GDIP.ahk
#Include Gdip_ImageSearch.ahk

;OnExit, EXIT_LABEL



gdipToken := Gdip_Startup()
bmpHaystack := Gdip_CreateBitmapFromFile("IMG/cabal.png")
bmpNeedle := Gdip_CreateBitmapFromFile("IMG/respawn.png")
RET := Gdip_ImageSearch(bmpHaystack,bmpNeedle,LIST,0,0,0,0,0,0xFFFFFF,1,0)
MsgBox, %RET%
;ControlClick, x408 y429, CABAL,, Left,, NA Pos
;Sleep, 1500


*/

EXIT_LABEL:

Gdip_Shutdown(gdipToken)
EXITAPP


User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Use GDI+ to do image search?

Post by boiler » 13 Mar 2021, 13:10

So as I suspected, you are only searching in an image file you already created as the haystack, which is why it always finds one and exactly one image in it. It sounds like you are actually looking to find when that image appears in your game, which means you would have to have the script continuously capture new images from the game window using Gdip_BitmapFromHWND() or similar and perform Gdip_ImageSearch() on the newly captured image as the haystack. Using a static image you captured already has no link to your active game window, so there would be nothing in your script telling it to look there.

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 16 Mar 2021, 05:53

boiler wrote:
13 Mar 2021, 13:10
So as I suspected, you are only searching in an image file you already created as the haystack, which is why it always finds one and exactly one image in it. It sounds like you are actually looking to find when that image appears in your game, which means you would have to have the script continuously capture new images from the game window using Gdip_BitmapFromHWND() or similar and perform Gdip_ImageSearch() on the newly captured image as the haystack. Using a static image you captured already has no link to your active game window, so there would be nothing in your script telling it to look there.
Makes a lot of sense, thank you so much. I'll look into it.

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 16 Mar 2021, 06:20

Thanks so much for the help previously, it almosts works as intended but there's one slight hiccup.

by the way, i'll totally understand if you stop replying cause im asking too many questions dont worry.


here's the code im using in order to run my image detection thing on a certain window. I did what you said and used Gdip_BitmapFromHwnd instead (I changed the function variable in order to just type the title in there instead of the ID). It almost works, I tested it by setting the RET variable to 1 (i changed the current RET to RET1 so the script doesnt get confused) my script, if RET = 1... Ran.

My problem is my %RET% is always 0, even if the needle image is on the window as clear as day. Any reason why that would be? thank you so much in advance once again.

Code: Select all

#NoEnv
#SingleInstance Force
SetBatchLines, -1
Process, Priority,, High
SetTitleMatchMode, 3
#Include GDIP.ahk
#Include Gdip_ImageSearch.ahk

;OnExit, EXIT_LABEL


imgsearch:
gdipToken := Gdip_Startup()
bmpHaystack := Gdip_BitmapFromHWND("CABAL")
bmpNeedle := Gdip_CreateBitmapFromFile("IMG/respawn.png")
RET := Gdip_ImageSearch(bmpHaystack,bmpNeedle,LIST,0,0,0,0,0,0xFFFFFF,1,0)
MsgBox, %RET%

if RET = 0
GoSub, imgsearch

if RET = 1
ControlClick, x408 y429, CABAL,, Left,, NA Pos
Sleep, 1500
Return


*/

EXIT_LABEL:

Gdip_Shutdown(gdipToken)
EXITAPP

User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Use GDI+ to do image search?

Post by boiler » 16 Mar 2021, 06:57

Are you saying you actually changed the code of the Gdip_BitmapFromHwnd() function to use the window title instead of the HWND? Changing the variable name or something like that wouldn’t do it. You’d actually have to change some of the lines of code. It’s easy enough to pass the actual HWND to it, so you should do this and use the original version of the function:

Code: Select all

bmpHaystack := Gdip_BitmapFromHWND(WinExist("CABAL"))
When a function expects an HWND, it’s expected that you grab it in your script, like above, not that you would find it manually and type it in, especially since it changes every time the window is created.

Some other thoughts:

Is there a reason you set the “Trans” parameter to be white? Not that it should hurt in this case, but I’m not sure of the reason to do so here. You might think you need to provide some value, but you don’t. A null value (the default) will mean that no color values will be taken to be transparent. When a default parameter value exists, as does this one, you can just leave it blank to use the default like below. You could have done that for many of the parameters.

Code: Select all

RET := Gdip_ImageSearch(bmpHaystack,bmpNeedle,LIST,0,0,0,0,0,,1,0)

If it still doesn’t work after the above fix for the HWND, I suggest saving the captured bitmap to a file using the appropriate Gdip function so you can see if it’s actually capturing the window correctly.

Using gosub for looping isn’t a great practice, especially when it would be recursive like that. Even goto (which I hate) would be better in this case, but it would be best to use proper looping commands (loop, while, until, break, continue).

I would only perform Gdip_Startup() once in your script, not every time through the loop.

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 16 Mar 2021, 07:34

boiler wrote:
16 Mar 2021, 06:57
Are you saying you actually changed the code of the Gdip_BitmapFromHwnd() function to use the window title instead of the HWND? Changing the variable name or something like that wouldn’t do it. You’d actually have to change some of the lines of code. It’s easy enough to pass the actual HWND to it, so you should do this and use the original version of the function:

Code: Select all

bmpHaystack := Gdip_BitmapFromHWND(WinExist("CABAL"))
When a function expects an HWND, it’s expected that you grab it in your script, like above, not that you would find it manually and type it in, especially since it changes every time the window is created.

Some other thoughts:

Is there a reason you set the “Trans” parameter to be white? Not that it should hurt in this case, but I’m not sure of the reason to do so here. You might think you need to provide some value, but you don’t. A null value (the default) will mean that no color values will be taken to be transparent. When a default parameter value exists, as does this one, you can just leave it blank to use the default like below. You could have done that for many of the parameters.

Code: Select all

RET := Gdip_ImageSearch(bmpHaystack,bmpNeedle,LIST,0,0,0,0,0,,1,0)

If it still doesn’t work after the above fix for the HWND, I suggest saving the captured bitmap to a file using the appropriate Gdip function so you can see if it’s actually capturing the window correctly.

Using gosub for looping isn’t a great practice, especially when it would be recursive like that. Even goto (which I hate) would be better in this case, but it would be best to use proper looping commands (loop, while, until, break, continue).

I would only perform Gdip_Startup() once in your script, not every time through the loop.
Thank you so much for your input, i'll try it out. Hope it'll work this time

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 16 Mar 2021, 08:21

I seem to have a problem which i dont know if it is fixable or not.

The code that you told me to make works, but not on the window that i want it to.
I did the save bitmap to file function. When I use a different window, I get a .png file of whatever the window looks like EXACTLY. but whenever I put CABAL as the window (which is my intended window to use), it just shows the titlebar of the app with a pure white canvas in it.

Im asking if this is a game issue? like an anticheat of some sort or is it just a code error?

(Code works on a different window, "Msgbox success" appears, but with the window that i want it to work on, it doesnt. I already did Run as administrator)

Code: Select all

#NoEnv
#SingleInstance Force
SetBatchLines, -1
Process, Priority,, High
SetTitleMatchMode, 3
#Include GDIP.ahk
#Include Gdip_ImageSearch.ahk

OnExit, EXIT_LABEL

Checkbmp := "Check.png"
gdipToken := Gdip_Startup()
Gdip_SaveBitmapToFile(bmpHaystack, Checkbmp)

Loop
{
bmpHaystack := Gdip_BitmapFromHWND(WinExist("CABAL"))
bmpNeedle := Gdip_CreateBitmapFromFile("IMG/test.png")
RET := Gdip_ImageSearch(bmpHaystack,bmpNeedle,,0,0,0,0,0,0,1,10)
}
Until RET = 1
MsgBox Success

EXIT_LABEL:

Gdip_Shutdown(gdipToken)
EXITAPP

User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Use GDI+ to do image search?

Post by boiler » 16 Mar 2021, 08:31

Try replacing Gdip_BitmapFromHWND() with this version which allows for more graphics rendering approaches to be captured:

Code: Select all

Gdip_BitmapFromHWND(hwnd)
{
	WinGetPos,,, Width, Height, ahk_id %hwnd%
	hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
	RegExMatch(A_OsVersion, "\d+", Version)
	PrintWindow(hwnd, hdc, Version >= 8 ? 2 : 0)
	pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
	SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
	return pBitmap
}

jollyjoe
Posts: 42
Joined: 13 Feb 2021, 18:51

Re: Use GDI+ to do image search?

Post by jollyjoe » 16 Mar 2021, 11:37

Finally! works like a charm.

Thank you so much for your help!

The new Gdip_CreateBitmapFromFile() function fixed it.

Again, thank you so much for your time and patience!

Post Reply

Return to “Ask for Help (v1)”