Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Gdip_ImageSearch


  • Please log in to reply
63 replies to this topic
tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
I'm putting this here as it continually gets lost in the GDI+ thread. This is still a work in progress so can't be included in the library. Further testing is needed as there are still problems with it. There are 2 parts that everything needs to be tested with; with variation and without.

Bugs:

[*:3qersqza]With variation, a no match takes a long time to complete
[*:3qersqza]It has been reported that w and h paramteres work on neither
Gdip_ImageSearch(pBitmapHayStack, pBitmapNeedle, ByRef x, ByRef y, Variation=0, sx="", sy="", w="", h="")
{
   static _ImageSearch1, _ImageSearch2
   if !_ImageSearch1
   {
      MCode_ImageSearch1 := "83EC108B44242C9983E20303C28BC88B4424309983E20303C253C1F80255894424148B44244056C1F9023B44244C578944244"
      . "80F8DCA0000008B7C24348D148D000000000FAFC88B442444895424148B54242403C88D1C8A8B4C244C895C24183BC1894424407D7A895C24108D6424"
      . "008B6C2428C744243C000000008D6424008B44243C3B4424380F8D9400000033C985FF7E178BD58BF38B063B02752283C10183C20483C6043BCF7CED8"
      . "B44241C035C24148344243C0103C003C003E8EBC08B4424408B5C24108B4C244C83C00183C3043BC189442440895C24107C928B4424448B5424488B5C"
      . "2418035C241483C2013B54245089542448895C24180F8C5DFFFFFF8B5424548B4424585F5EC702FFFFFFFF5DC700FFFFFFFF83C8FF5B83C410C38B4C2"
      . "4548B5424408B4424585F89118B4C24445E5D890833C05B83C410C3"

      VarSetCapacity(_ImageSearch1, StrLen(MCode_ImageSearch1)//2)
      Loop % StrLen(MCode_ImageSearch1)//2      ;%
         NumPut("0x" SubStr(MCode_ImageSearch1, (2*A_Index)-1, 2), _ImageSearch1, A_Index-1, "char")
   }

   if !_ImageSearch2
   {
      MCode_ImageSearch2 :="83EC1C8B4424443B44244C535556578944241C0F8D760100008B4C24488B5424580FAFC88B4424608B742440894C24188B4C24"
      . "503BCA894C24140F8D320100008B54241833FF897C24108B5C24103B5C2444897C2428895424240F8D4E01000085F6C7442420000000000F8ECD00000"
      . "08B7424348D148A8B4C243003F7897424548D1C0AEB0A8DA424000000008D49008B6C2454B9030000000FB60C19BE030000000FB6342E8D2C013BF50F"
      . "8FA20000002BC83BF10F8C980000008B4C24300FB64C0A028B7424340FB67437028D2C013BF57F7F2BC83BF17C798B4C24300FB64C0A018B7424340FB"
      . "67437018D2C013BF57F602BC83BF17C5A0FB60B8B7424540FB6368D2C013BF57F492BC83BF17C438B4C24208B742440834424540483C10183C20483C3"
      . "0483C7043BCE894C24200F8C5BFFFFFF8B4C24148B7C24288B542424035424488344241001037C244CE9F7FEFFFF8B4C24148B5424588B74244083C10"
      . "13BCA894C24140F8CD2FEFFFF8B4C24508B7C241C8B5C2448015C241883C7013B7C245C897C241C0F8CA5FEFFFF8B5424648B4424685F5EC702FFFFFF"
      . "FF5DC700FFFFFFFF83C8FF5B83C41CC38B5424648B4424685F890A8B4C24185E5D890833C05B83C41CC3"

      VarSetCapacity(_ImageSearch2, StrLen(MCode_ImageSearch2)//2)
      Loop % StrLen(MCode_ImageSearch2)//2      ;%
         NumPut("0x" SubStr(MCode_ImageSearch2, (2*A_Index)-1, 2), _ImageSearch2, A_Index-1, "char")
   }
   
   if (Variation > 255 || Variation < 0)
      return -2

   Gdip_GetImageDimensions(pBitmapHayStack, hWidth, hHeight), Gdip_GetImageDimensions(pBitmapNeedle, nWidth, nHeight)
   
   if !(hWidth && hHeight && nWidth && nHeight)
      return -3
   if (nWidth > hWidth || nHeight > hHeight)
      return -4
   
   sx := (sx = "") ? 0 : sx
   sy := (sy = "") ? 0 : sy
   w := (w = "") ? hWidth-sx : w
   h := (h = "") ? hHeight-sy : h
   
   if (sx+w > hWidth-nWidth)
      w := hWidth-sx-nWidth+1
   
   if (sy+h > hHeight-nHeight)
      h := hHeight-sy-nHeight+1
      
   E1 := Gdip_LockBits(pBitmapHayStack, 0, 0, hWidth, hHeight, Stride1, Scan01, BitmapData1)
   E2 := Gdip_LockBits(pBitmapNeedle, 0, 0, nWidth, nHeight, Stride2, Scan02, BitmapData2)
   if (E1 || E2)
      return -5

   x := y := 0
   if (Variation = 0)
   {
      E := DllCall(&_ImageSearch1, "uint", Scan01, "uint", Scan02, "int", hWidth, "int", hHeight, "int", nWidth, "int", nHeight, "int", Stride1
      , "int", Stride2, "int", sx, "int", sy, "int", w, "int", h, "int*", x, "int*", y)
   }
   else
   {
      E := DllCall(&_ImageSearch2, "uint", Scan01, "uint", Scan02, "int", hWidth, "int", hHeight, "int", nWidth, "int", nHeight, "int", Stride1
      , "int", Stride2, "int", sx, "int", sy, "int", w, "int", h, "int", Variation, "int*", x, "int*", y)
   }
   Gdip_UnlockBits(pBitmapHayStack, BitmapData1), Gdip_UnlockBits(pBitmapNeedle, BitmapData2)
   return (E = "") ? -6 : E
}

int Gdip_ImageSearch1(unsigned int * HayStack, unsigned int * Needle, int w1, int h1, int w2, int h2, int Stride1, int Stride2, int sx, int sy, int w, int h, int * x, int * y)
{
   int tx, ty;
   int offset1 = Stride1/4, offset2 = Stride2/4;
   for (int y1 = sy; y1 < h; ++y1)
   {
      for (int x1 = sx; x1 < w; ++x1)
      {
         ty = y1;
         for (int y2 = 0; y2 < h2; ++y2)
         {
            tx = x1;
            for (int x2 = 0; x2 < w2; ++x2)
            {
               if (HayStack[tx+(ty*offset1)] != Needle[x2+(y2*offset2)])
                  goto NoMatch;
               tx++;
            }
            ty++;
         }
         x[0] = x1; y[0] = y1;
         return 0;
         NoMatch:
         continue;
      }
   }
   x[0] = -1; y[0] = -1;
   return -1;
}

int Gdip_ImageSearch2(unsigned char * HayStack, unsigned char * Needle, int w1, int h1, int w2, int h2, int Stride1, int Stride2, int sx, int sy, int w, int h, int v, int * x, int * y)
{
   int tx, ty, ph, pn, Ah, Rh, Gh, Bh, An, Rn, Gn, Bn;
   for (int y1 = sy; y1 < h; ++y1)
   {
      for (int x1 = sx; x1 < w; ++x1)
      {
         ty = y1;
         for (int y2 = 0; y2 < h2; ++y2)
         {
            tx = x1;
            for (int x2 = 0; x2 < w2; ++x2)
            {
               ph = (4*tx)+(ty*Stride1);
               pn = (4*x2)+(y2*Stride2);

               Ah = HayStack[3+ph]; An = Needle[3+pn];
               if (An > Ah+v || An < Ah-v) goto NoMatch;

               Rh = HayStack[2+ph]; Rn = Needle[2+pn];
               if (Rn > Rh+v || Rn < Rh-v) goto NoMatch;

               Gh = HayStack[1+ph]; Gn = Needle[1+pn];
               if (Gn > Gh+v || Gn < Gh-v) goto NoMatch;

               Bh = HayStack[ph]; Bn = Needle[pn];
               if (Bn > Bh+v || Bn < Bh-v) goto NoMatch;
               
               tx++;
            }
            ty++;
         }
         x[0] = x1; y[0] = y1;
         return 0;
         NoMatch:
         continue;
      }
   }
   x[0] = -1; y[0] = -1;
   return -1;
}


Iggy_
  • Members
  • 90 posts
  • Last active: Nov 16 2012 05:55 PM
  • Joined: 29 May 2011
Hi tic, thanks for posting this, I was never sure when I was using the gdi+ image search what version was working or latest or what.

Would it be possible to also include a parameter to allow a transparent color to be specified, like the *TransN AHK imagesearch option?

The reason I ask is because I have some scripts which use pngs where RGB:FF00FF is the transparent color, and I'd like to at some point add some features which would require doing these searches on GDI bitmaps instead. I know you can make pngs which have real transparency encoded, but neither MSPaint nor the PaintShopPro version I have can save them like this, so it's convenient to just use pink. Or maybe it would be more appropriate to run some sort of image processing function to set a color in the gdi bitmap transparent prior to searching - I don't know. Sorry if this has already been requested/discussed, but I thought I'd mention it, since it would make it more easily interchangeable with the AHK imagesearch, if you could specify a transparent color. Thanks.

imagy
  • Guests
  • Last active:
  • Joined: --
this looks so complicate,
im quite new to autohotkey,
can someone explain allittle about how to use this script , such as an example

closed
  • Members
  • 509 posts
  • Last active: Jan 14 2012 06:14 PM
  • Joined: 07 Feb 2008

is it possible to take a screenshot of the background window, and then use 'imagesearch' to find the coodinate

in another word, can i imagesearch on a picture-file instead of the screen



#SingleInstance, Force
#NoEnv
SetBatchLines, -1

#include gdip.ahk   ; download from here http://www.autohotkey.com/forum/topic32238.html 


If !pToken := Gdip_Startup()
{
   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
   ExitApp
}

file1=e:\imagetosearch_for.png      ;filepath to image to search in image 
file2=e:\imagetosearch_in.png       ;filepath to imagefile 


pBitmapneedle:=Gdip_CreateBitmapFromFile(file1)
pBitmapHaystack:=Gdip_CreateBitmapFromFile(file2)

Gdip_ImageSearch( pBitmapHayStack,pBitmapNeedle,  x,  y)


msgbox x coord =%x% y coord= %y%




Gdip_DisposeImage(pBitmaphaystack)
Gdip_DisposeImage(pBitmapneedle)
Gdip_Shutdown(pToken)
ExitApp




Gdip_ImageSearch(pBitmapHayStack, pBitmapNeedle, ByRef x, ByRef y, Variation=0, sx="", sy="", w="", h="")
{
   static _ImageSearch1, _ImageSearch2
   if !_ImageSearch1
   {
      MCode_ImageSearch1 := "83EC108B44242C9983E20303C28BC88B4424309983E20303C253C1F80255894424148B44244056C1F9023B44244C578944244"
      . "80F8DCA0000008B7C24348D148D000000000FAFC88B442444895424148B54242403C88D1C8A8B4C244C895C24183BC1894424407D7A895C24108D6424"
      . "008B6C2428C744243C000000008D6424008B44243C3B4424380F8D9400000033C985FF7E178BD58BF38B063B02752283C10183C20483C6043BCF7CED8"
      . "B44241C035C24148344243C0103C003C003E8EBC08B4424408B5C24108B4C244C83C00183C3043BC189442440895C24107C928B4424448B5424488B5C"
      . "2418035C241483C2013B54245089542448895C24180F8C5DFFFFFF8B5424548B4424585F5EC702FFFFFFFF5DC700FFFFFFFF83C8FF5B83C410C38B4C2"
      . "4548B5424408B4424585F89118B4C24445E5D890833C05B83C410C3"

      VarSetCapacity(_ImageSearch1, StrLen(MCode_ImageSearch1)//2)
      Loop % StrLen(MCode_ImageSearch1)//2      ;%
         NumPut("0x" SubStr(MCode_ImageSearch1, (2*A_Index)-1, 2), _ImageSearch1, A_Index-1, "char")
   }

   if !_ImageSearch2
   {
      MCode_ImageSearch2 :="83EC1C8B4424443B44244C535556578944241C0F8D760100008B4C24488B5424580FAFC88B4424608B742440894C24188B4C24"
      . "503BCA894C24140F8D320100008B54241833FF897C24108B5C24103B5C2444897C2428895424240F8D4E01000085F6C7442420000000000F8ECD00000"
      . "08B7424348D148A8B4C243003F7897424548D1C0AEB0A8DA424000000008D49008B6C2454B9030000000FB60C19BE030000000FB6342E8D2C013BF50F"
      . "8FA20000002BC83BF10F8C980000008B4C24300FB64C0A028B7424340FB67437028D2C013BF57F7F2BC83BF17C798B4C24300FB64C0A018B7424340FB"
      . "67437018D2C013BF57F602BC83BF17C5A0FB60B8B7424540FB6368D2C013BF57F492BC83BF17C438B4C24208B742440834424540483C10183C20483C3"
      . "0483C7043BCE894C24200F8C5BFFFFFF8B4C24148B7C24288B542424035424488344241001037C244CE9F7FEFFFF8B4C24148B5424588B74244083C10"
      . "13BCA894C24140F8CD2FEFFFF8B4C24508B7C241C8B5C2448015C241883C7013B7C245C897C241C0F8CA5FEFFFF8B5424648B4424685F5EC702FFFFFF"
      . "FF5DC700FFFFFFFF83C8FF5B83C41CC38B5424648B4424685F890A8B4C24185E5D890833C05B83C41CC3"

      VarSetCapacity(_ImageSearch2, StrLen(MCode_ImageSearch2)//2)
      Loop % StrLen(MCode_ImageSearch2)//2      ;%
         NumPut("0x" SubStr(MCode_ImageSearch2, (2*A_Index)-1, 2), _ImageSearch2, A_Index-1, "char")
   }
   
   if (Variation > 255 || Variation < 0)
      return -2

   Gdip_GetImageDimensions(pBitmapHayStack, hWidth, hHeight), Gdip_GetImageDimensions(pBitmapNeedle, nWidth, nHeight)
   
   if !(hWidth && hHeight && nWidth && nHeight)
      return -3
   if (nWidth > hWidth || nHeight > hHeight)
      return -4
   
   sx := (sx = "") ? 0 : sx
   sy := (sy = "") ? 0 : sy
   w := (w = "") ? hWidth-sx : w
   h := (h = "") ? hHeight-sy : h
   
   if (sx+w > hWidth-nWidth)
      w := hWidth-sx-nWidth+1
   
   if (sy+h > hHeight-nHeight)
      h := hHeight-sy-nHeight+1
      
   E1 := Gdip_LockBits(pBitmapHayStack, 0, 0, hWidth, hHeight, Stride1, Scan01, BitmapData1)
   E2 := Gdip_LockBits(pBitmapNeedle, 0, 0, nWidth, nHeight, Stride2, Scan02, BitmapData2)
   if (E1 || E2)
      return -5

   x := y := 0
   if (Variation = 0)
   {
      E := DllCall(&_ImageSearch1, "uint", Scan01, "uint", Scan02, "int", hWidth, "int", hHeight, "int", nWidth, "int", nHeight, "int", Stride1
      , "int", Stride2, "int", sx, "int", sy, "int", w, "int", h, "int*", x, "int*", y)
   }
   else
   {
      E := DllCall(&_ImageSearch2, "uint", Scan01, "uint", Scan02, "int", hWidth, "int", hHeight, "int", nWidth, "int", nHeight, "int", Stride1
      , "int", Stride2, "int", sx, "int", sy, "int", w, "int", h, "int", Variation, "int*", x, "int*", y)
   }
   Gdip_UnlockBits(pBitmapHayStack, BitmapData1), Gdip_UnlockBits(pBitmapNeedle, BitmapData2)
   return (E = "") ? -6 : E
}


Sven
  • Members
  • 22 posts
  • Last active: Apr 05 2012 08:03 AM
  • Joined: 03 Aug 2011

Would it be possible to also include a parameter to allow a transparent color to be specified, like the *TransN AHK imagesearch option?

Seconded. For me, having transparency is a must have.

Safmy
  • Guests
  • Last active:
  • Joined: --
I added the first code you posted into the GDIP.ahk but only received an error level of -6 with the code below:-

pToken := Gdip_Startup() 

file1:="Location of Haystack" ;specific to your file location
file2:="Location of needle" ;specific to your file location

my_haystack := Gdip_CreateBitmapFromFile(File1) 
my_needle := Gdip_CreateBitmapFromFile(File2) 

F4::
;if !Gdip_ImageSearch(pBitmapHayStack, pBitmapNeedle, x, y) 
;   MsgBox, %x%`n%y%
MsgBox % Gdip_ImageSearch(my_haystack, my_needle, FoundX, FoundY) 
Return

Gdip_ShutDown(pToken)


swades
  • Guests
  • Last active:
  • Joined: --
The above code with Gdip_CreateBitmapFromFile, doesnot work for me.

Same image search is successful for Gdip_BitmapFromScreen.

Can anyone please advise, if it imagesearch can work on file?

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
Are either of you running this on x64 ahk as that could provide an error level -6

The above code with Gdip_CreateBitmapFromFile, doesnot work for me.

Same image search is successful for Gdip_BitmapFromScreen.

Can anyone please advise, if it imagesearch can work on file?


Are the files jpgs that you are using? Are you sure that 1 file is definitely within the other file? Please provide both images

kenn
  • Members
  • 407 posts
  • Last active: Jan 14 2015 08:16 PM
  • Joined: 11 Oct 2010
Hi tic Another thread you mention that fastPixelGetColor would be thousands times faster with machine code. Would you please post such an example script? I saw your image search script with machine code so you must know how to do that.
My Scripts
Ain’t No Shame in Asking for Help!

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
Hi kenn

I don't want to turn this thread into a general question thread, but should only relate to Image Searching to help bug test the function in the first post.

Simple pixel searching for 1 pixel will look like

int Gdip_PixelSearch(unsigned int * HayStack, int w, int h, int Stride, int ARGB, int * x, int * y)
{
	int offset = Stride/4;
	for (int y1 = 0; y1 < h; ++y1)
	{
		for (int x1 = 0; x1 < w; ++x1)
		{
			if (HayStack[x1+y1*offset] == ARGB)
			{
				x[0] = x1; y[0] = y1;
				return 0;
			}
		}
	}
	x[0] = -1; y[0] = -1;
	return -1;
}

Although this is not the speed I was talking of. The speed I was talking of would come into effect if you tried for example to find all the x,y coordinates of every pixel on the screen that matches a certain colour, as then it could return all of them in an array and only run through the code once. The only difference would be that ByRefs x and y would need to have the appropriate size for VarSetCapacity and the c++ function would dump the results into this "array"

Hope this helps a bit. Don't reply in this thread please. Thanks!

  • Guests
  • Last active:
  • Joined: --

Are either of you running this on x64 ahk as that could provide an error level -6

The above code with Gdip_CreateBitmapFromFile, doesnot work for me.

Same image search is successful for Gdip_BitmapFromScreen.

Can anyone please advise, if it imagesearch can work on file?


Are the files jpgs that you are using? Are you sure that 1 file is definitely within the other file? Please provide both images


If both haystack and needle are from Gdip_CreateBitmapFromFile the search returns a -6.
I am running a 64 bit os but 32 bit AHK_L (unicode)
Sample code would be:
pbHaystack := Gdip_CreateBitmapFromFile("haystack.png")
pbNeedle := Gdip_CreateBitmapFromFile("haystack.png") ;yes loading again, same image
Gdip_ImageSearch(pbHaystack, pbNeedle, X, Y)

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
-6 means the machine code could not complete, which likely means it doesn't work in AHK_L
I need to make the library completely AHK_L compatible but I have a million projects I'm working on!

Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
Take your time, tic. All your work is highly valued and very much appreciated! :).

Works for me in AHK_L 32b Uni.

3nL8f.png


Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
After messing with it further, I noticed the sx, sy, w, h. I suppose that's of the needle? Is it possible to search a specific area of the haystack? I know the exact coordinates where the image should be, I just want to make sure it's there before proceeding. Rather then scan the whole haystack, or without creating a whole new bitmap, how would I scan a specified area?

More specifically, I know my needle should appear at x277 y4 in my haystack and is 8x8. How might I narrow it down so that it only checks x277 y4 w8 h8. I tried simply using those values as sx, sy, etc, with no luck.

3nL8f.png


meochain
  • Members
  • 12 posts
  • Last active: Jun 10 2012 04:25 PM
  • Joined: 10 Jun 2012
I have learn many unique things from this sharing..Thanks