RAP_ImageSearch - ImageSearch Wrapper V1

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
andymbody
Posts: 942
Joined: 02 Jul 2017, 23:47

RAP_ImageSearch - ImageSearch Wrapper V1

26 Nov 2023, 20:32

In case anyone is interested... I also have a v2 version... will post if requested

RAP_ImageSearch for AHKv1
Updated: 2023-11-26

Purpose:
ImageSearch Wrapper providing the following enhancements
* Supports user-defined wait-period to find image on screen
* Provides optional timeout function, with visual countdown display
* Supports ability to search for multiple images at the same time (in a group)
* Each image within group can have unique search criteria
* Can search in AND/OR modes. More modes are currently being planned.
* Can also return centered x,y (cx, cy)
* Supports verification of ImageFile path on disk (debugging assist)
* Supports all native ImageSearch Options
* Supports Abort search at any time

See code for general syntax

Example script

Code: Select all

#Requires AutoHotkey v1.1.33
#SingleInstance force
#Include RAP_ImageSearch.ahk

;################################################################################
; EXAMPLE - Search using single string path
; 	default options - full screen search, with timeout - search for max of 5 seconds
;################################################################################

		path1 := "test3.png"					; define file path to image
		iSearch := RAPImageSearch(path1, 5)		; begin search, 5 sec timeout
		if (iSearch.Found)						; was image found?
		{
			MouseMove iSearch.X, iSearch.Y		; .X, .Y screen coords of found image
			MsgBox % "Image found at `nx := " . iSearch.x . "`ny := " . iSearch.y
		}
		else
		{
			MsgBox % "Image not found`n" . path1
		}

;################################################################################
; EXAMPLE - Search for multiple images at same time
; 	each image having it's own unique search criteria
;################################################################################

		ip1	:= new ImageProfile("test1.png", "*3 ", 500, 200, 600, 400)		; unique search criteria for each image
		ip2	:= new ImageProfile("test2.png", "*1 ", 200, 200, 300, 300)		; unique search criteria for each image
		ip3	:= new ImageProfile("test3.png")								; or just use defaults

		ig		:= new ImageGroup([ip1,ip2,ip3])		; OR mode			; (0)		OR mode (default - the first image found satifies the search)
;		ig		:= new ImageGroup([ip1,ip2,ip3], "a")	; AND mode			; (1 or a)	AND mode (must find all images in group)
		mode	:= ig.Mode
		iSearch := RAPImageSearch(ig, 10)				; begin search		; unique image options will override any options specified here
		if (iSearch.Found)								; was image found?
		{
			MouseMove iSearch.cx, iSearch.cy				; .CX, .CY - screen coords of center of found image
			msg := ((mode==1) ? "All images" : "At least one image") . " found successfully!"
			msg .= "`nImage found:`n" . iSearch.ImagePath	; this is the image that satisfied the search (last image in array for AND mode)
			MsgBox % msg
		}
		else
		{
			msg := "Failed to find " . ((mode==1) ? "all images in AND mode" : "at least one image in OR mode")
			MsgBox % msg
		}

		ExitApp

;################################################################################
; Include this in main script to enable search aborts
~Esc::
{
	abortSearch()
	return
}
Wrapper code

Code: Select all

/*
	Name:		RAP_ImageSearch for AHKv1
	Author:		andymbody
	Updated:	2023-11-26
	Purpose:
				ImageSearch Wrapper providing the following enhancements

				* Supports user-defined wait-period to find image on screen
				* Provides optional timeout function, with visual countdown display
				* Supports ability to search for multiple images at the same time (in a group)
				* Each image within group can have unique search criteria
				* Can search in AND/OR modes. More modes are currently being planned.
				* Can also return centered x,y (cx, cy)
				* Supports verification of ImageFile path on disk (debugging assist)
				* Supports all native ImageSearch Options
				* Supports Abort search at any time

	Syntax:
				RAPImageSearch(srcObj, timeout:=0, options:="", x1:="", y1:="", x2:="", y2:="")
					SrcObj:
						* Single file path string
						* ImageProfile object
						* ImageGroup object
					Timeout: in seconds
						0 := don't wait for image - search once and return result immediately (default)
					Options:
						Native ImageSearch options (Separate from fileName string)
					x1, y1, x2, y2:
						Same as native ImageSearch
*/
#Requires AutoHotkey v1.1.33
CoordMode,Mouse,Screen
CoordMode,Pixel,Screen
CoordMode,ToolTip,Screen
global ga:=false
RAPImageSearch(srcObj,timeout:=0,options:="",x1:="",y1:="",x2:="",y2:="")
{
global ga
if(!IsObject(srcObj)&&StrLen(srcObj)>0)
{
if(pe(srcObj))
{
srcObj:=new ImageProfile(srcObj,options,x1,y1,x2,y2)
}
}
if(IsObject(srcObj)&&srcObj.isip)
{
srcObj:=new ImageGroup([srcObj],0)
}
if(IsObject(srcObj)&&srcObj.isgp)
{
ga:=false
return new pigs(srcObj,timeout)
}
if(!ga)
{
msg:="The source object DOES NOT appear to be`nany of the following "
.   "and is therefore invalid:`n`n* File-Path,`n* ImageProfile,"
.	"`n* ImageGroupProfile`n`nPlease correct this before continuing..."
MsgBox,16,% "Invalid Source Object",% msg
}
return new ImageProfile()
}
class ImageProfile
{
__New(ip:="",op:="",x1:="",y1:="",x2:="",y2:="")
{
this._ip:=ip
this._is:=gis(this._ip)
this._io:=op
this._x1:=(!this.isip)?"":(x1=="")?0:x1
this._y1:=(!this.isip)?"":(y1=="")?0:y1
this._x2:=(!this.isip)?"":(x2=="")?A_ScreenWidth:x2
this._y2:=(!this.isip)?"":(y2=="")?A_ScreenHeight:y2
this._rX:=""
this._rY:=""
this._r:=""
}
_s(lso)
{
global ga
if(!this.isip||lso!="lso")
return ""
this._r:="",this._rX:="",this._rY:="",rtx:="",rty:=""
if(!ga)
this._r:=pcnis(this._ip,this._io,rtx,rty,this._x1,this._y1,this._x2,this._y2)
if(ga)
return -1
this._rX:=rtx
this._rY:=rty
return this.Result
}
Found{
get{
return ((this._rX=="")||(this._rY==""))?"":(this.Result==1)
}
}
X{
get{
return this._rX
}
}
CX{
get{
return (!this.isip)?"":(this.X + (this.ImageWidth//2))
}
}
Y{
get{
return this._rY
}
}
CY{
get{
return (!this.isip)?"":(this.Y + (this.ImageHeight//2))
}
}
ImageSize{
get{
return this._is
}
}
ImageWidth{
get{
return (!this.isip)?"":this._is.W
}
}
ImageHeight{
get{
return (!this.isip)?"":this._is.H
}
}
ImagePath{
get{
return this._ip
}
}
Result{
get{
return this._r
}
}
isip{
get{
return this.ImagePath!=""
}
}
}
class ImageGroup
{
__New(ima,md:=0)
{
md:=SubStr(md,1,1)
this._md:=(md=="a"||md=="1")?1:0
ia:=pvg(ima)
this._v:=(IsObject(ia)&&ia.MaxIndex()>0)
this._ia:=(this._v)?ia:""
}
ia{
get{
return this._ia
}
}
Mode{
get{
return this._md
}
}
isgp{
get{
return this._v
}
}
}
class pigs
{
__New(igp,to:=0)
{
this._v:=igp.isgp
this._to:=(to=="")?0:to+0
this._smd:=igp.Mode
this._rp:=""
if(this._v)
this._ig:=igp,this._s("lso")
else
{
msg:="Invalid Group Profile detected! Search halted!`n`n"
.	"Please correct this before continuing."
MsgBox,% msg
}
}
_s(lso)
{
global ga
if(lso!="lso")
return -1
if(!ga)
this._rp:=pts(this._ig,this._to)
if(ga)
return -1
}
Found{
get{
return this._rp.Found
}
}
X{
get{
return this._rp.X
}
}
CX{
get{
return this._rp.CX
}
}
Y{
get{
return this._rp.Y
}
}
CY{
get{
return this._rp.CY
}
}
ImageSize{
get{
return this._rp.ImageSize
}
}
ImageWidth{
get{
return this._rp.ImageWidth
}
}
ImageHeight{
get{
return this._rp.ImageHeight
}
}
ImagePath{
get{
return this._rp.ImagePath
}
}
Result{
get{
return this._rp.Result
}
}
}
class pat
{
static ttid:=[]
__New(to:=0,ai:=1000,sc:=true)
{
to:=(to<0)?1:to
this._c:=to
this._ai:=ai
this._sc:=sc
this._ttX:=""
this._ttY:=""
this._ttid:=this._nttid()
this._tm:=ObjBindMethod(this,"_a")
}
_nttid()
{
nid:=1
Loop % pat.ttid.MaxIndex()
{
if(pat.ttid[A_Index]=="")
{
nid:=A_Index
break
}
else
{
nid:=A_Index + 1
}
}
if(pat.ttid.MaxIndex()<nid)
pat.ttid.push(nid)
else
pat.ttid[nid]:=nid
return pat.ttid[nid]
}
_ctt(idx)
{
toolTip,,,,% idx
this._ttid:=""
pat.ttid[idx]:=""
}
_str()
{
tm:=this._tm
SetTimer % tm,% this._ai
}
_stp()
{
if(this._ttid=="")
return 
tm:=this._tm
SetTimer % tm,off
this._ctt(this._ttid)
}
_a()
{
this._c--,this._dc()
if(this._c<=0)
this._c:=0,this._stp()
}
_dc()
{
if(!this._sc)
return 
x:=this._ttX,y:=this._ttY
m:=this._c,ttid:=this._ttid
tooltip,% m,x,y,% ttid
}
_stt(x:="",y:="")
{
this._ttX:=(x!="")?x:this._ttX
this._ttY:=(y!="")?y:this._ttY
}
_rt{
get{
return this._c
}
}
}
pvg(ima)
{
if((!IsObject(ima))||(ima.MaxIndex()<1))
return ""
vps:=pvip(ima)
return (IsObject(vps)&&vps.MaxIndex()>0)?vps:""
}
pvip(ima)
{
global ga
ptp:=ima
pti:=[],pte:=[]
Loop % ptp.MaxIndex()
{
cp:=ptp[A_Index]
vp:=cp.isip
curPath:=cp.ImagePath
vpth:=(pe(curPath))
if(vp&&vpth)
pti.push(cp)
else if(!vpth)
pte.push(cp)
}
if(pte.MaxIndex()>0)
{
bp:=""
Loop % pte.MaxIndex()
bp.=pte[A_Index].ImagePath . "`n"
msg:="The following paths were not found on disk...`n`n" . bp . "`n"
if(pti.MaxIndex()<=0)
{
pti:="",ga:=true,msg.="Aborting search`n"
MsgBox,16,% "Invalid Search",% msg
}
else
{
msg.="Would you like to perform graphic search anyway?`n"
MsgBox,4,% "Continue Search?",% msg
IfMsgBox,No
ga:=true,pti:=""
}
}
return pti
}
pcnis(img,iOpt,ByRef rtx,ByRef rty,x1,y1,x2,y2)
{
oi:=Trim(Trim(iOpt) . " " . Trim(img))
ImageSearch,rtx,rty,x1,y1,x2,y2,%oi%
return (ErrorLevel==0)
}
pts(igp,to:=0)
{
global ga:=false
fd:=false
scmp:=false
rip:=""
md:=igp.Mode
ima:=igp.ia
wt:=new pat(to)
wr:=(to>0)
if(wr)
wt._str()
While (!ga&&!fd&&!scmp)
{
fd:=(rip:=psai(ima,md))
scmp:=(wr)?(wt._rt<=0):true
}
wt._stp()
return rip
}
psai(ima,md:=0)
{
global ga
fd:=false
bl:=false
rip:=""
while (!ga&&!bl&&(A_Index<=ima.MaxIndex()))
{
cp:=ima[A_Index]
fd:=(cp._s("lso")==1)
rip:=(fd)?cp:""
bl:=(md==1)?!fd:fd
}
return rip
}
gis(ip)
{
SplitPath ip,fn,dir
if(fn=="")
return ""
dir:=(dir=="")?A_WorkingDir:dir
os:=ComObjCreate("Shell.Application")
of:=os.NameSpace(dir)
ofi:=of.ParseName(fn)
isz:=of.GetDetailsOf(ofi,31)
isz:=RegExReplace(isz,".(.+).","$1")
dim:=StrSplit(isz," x ")
return {w:dim[1],h:dim[2]}
}
abortSearch()
{
global ga:=true
return 
}
pe(spth)
{
fo:=""
try
{
fo:=FileOpen(spth,"r")
}
catch
{
}
if(IsObject(fo))
{
Sleep, 50
fo.Close()
return true
}
msg:="The Source String DOES NOT appear to point to a valid file!"
.	"`nPlease correct this before continuing...`n`nSource String:`n" . spth
MsgBox,64,% "Invalid File Path",% msg
return false
}
Last edited by andymbody on 18 Jan 2024, 07:38, edited 2 times in total.
nacken012
Posts: 92
Joined: 22 Jul 2016, 14:39

Re: RAP_ImageSearch - ImageSearch Wrapper V1

27 Nov 2023, 08:00

Thank you so much, that's brilliant.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: Chunjee and 113 guests