How to use regions properly

Asked by Smizzy

I am quite new to programming, and while i am enjoying sikuli and the intuitive syntax I am wondering which is the proper method for using Regions.
Ive defined a region "icon = Region( 40, 230, 75, 350)"
then when im searching the region do i use
icon.exists(.png) ?
I cant use find() because the image I'm searching for wont always be there and i don't want the program to stop if it doesn't find it immediately.
How can i use wait() to wait for multiple possible images to appear within the region?

Not all of these questions have to be answered, any help given is very much appreciated :D

Question information

Language:
English Edit question
Status:
Solved
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Solved by:
Eugene S
Solved:
Last query:
Last reply:
Revision history for this message
Best Eugene S (shragovich) said :
#1

Hi,

You search should be for a region but for a pattern.
First you must create screenshots of patterns you wish to detect on the screen. Then, once you have the patterns and you have defined the region, you can search for these patterns within the region. For example:

region = Region( 40, 230, 75, 350)
region.find("pattern1.png")

A possible way to look for multiple patterns(images) in the same area:

imagesList = ["image1.png", "image2.png", "image3.png"]

for image in imageList:
     try:
          region.find(image)
          print "image %s found!" %(image)
     except:
          print "image %s NOT found!" %(image)

Cheers,
Eugene

Revision history for this message
Smizzy (mad-dugas) said :
#2

Thanks Eugene S, that solved my question.

Revision history for this message
RaiMan (raimund-hocke) said :
#3

@Eugene
your solution is principally ok, but very time consuming caused by the unnecessary waiting for not existing images in this case.

so at least this way:
imagesList = ["image1.png", "image2.png", "image3.png"]

for image in imageList:
     try:
          region.wait(image, 0)
          print "image %s found!" %(image)
     except:
          print "image %s NOT found!" %(image)

or even
imagesList = ["image1.png", "image2.png", "image3.png"]

for image in imageList:
     if region.exists(image, 0):
          print "image %s found!" %(image)
     else:
          print "image %s NOT found!" %(image)

the parameter 0 for wait and exists tells the search process to only do it once and come back immediately. So in case of not existing image, it does not carry on searching until the timeout of standard 3 seconds is reached.

Revision history for this message
Eugene S (shragovich) said :
#4

@ RaiMan

I completely agree with your comment.
I just wanted to show the concept here but clearly, the approach you mentioned should be used for better efficiency.

Eugene

Revision history for this message
Smizzy (mad-dugas) said :
#5

For those, say i have 4 sets of images and I search for the first image in each set within a region, is there a way to tell which set the image came from when it is found?

Revision history for this message
Eugene S (shragovich) said :
#6

Can you post your code?

Revision history for this message
Smizzy (mad-dugas) said :
#7

The script im working on is kinda long, like 200 lines, Ill just post the relevant parts.

        customerlist = ("buyitem-2.png","dungeonquester.png","questgiver.png")
        if customer.exists(customerlist):
            try:
                customer.click(customerlist)
                if selling.exists("buy.png"):
                    selling.click("buy.png")
                    continue
                if selling.exists("thanks.png"):
                    selling.click("thanks.png")
                    continue
                if selling.exists("ok.png"):
                    selling.click("ok-1.png")
                    continue
                else:
                    selling.click("refuse.png")
                    continue

My issue is that buy.png only exists if the image found was buyitem-2.png,
 thanks.png only exists if the image found was dungeonquester.png,
and ok.png only exists if the image found was questgiver.png

my script wastes a lot of time searching for buttons that arent there because i cant differentiate between which image from the list was found.

Revision history for this message
Smizzy (mad-dugas) said :
#8

I also have this kind of a situation and was wondering how to optimize it

c1="shopkeeper-1.png" # worker icon
c1i1=0 # most desired item to craft
c1i2=0 # second highest priority
c1i3=0 #third
c1i4=0 #fourth
c2="Tinkerer-1.png"
c2i1="pistol-1.png"
c2i2=0
c2i3=0
c2i4=0
c3="jeweler-2.png"
c3i1="scholarsmark-1.png"
c3i2="ringofwizardry-1.png"
c3i3=0
c3i4=0
c4="Enchanter-2.png"
c4i1="antivenom-2.png"
c4i2=0
c4i3=0
c4i4=0

#Those images are run through this function one by one in a loop, its not very fast because the loop checks for each icon individually

def crafter(worker, item1, item2, item3, item4):
    if item1==0:
        return(0)
    if item1 != 0:
        if icon.exists(worker):
            x=1
            try:
                icon.click(worker)
                if queue.exists(Pattern("emptyqueue.png").similar(0.90)):
                    if clicker(item1)==0:
                        if item2 != 0:
                            if clicker(item2)==0:
                                if item3 != 0:
                                    if clicker(item3)==0:
                                        if item4 != 0:
                                            if clicker(item4)==0:
                                                quit.click("closeitemselect.png")
                                                return(1)
                                        else:
                                            quit.click("closeitemselect.png")
                                            return(1)
                                else:
                                    quit.click("closeitemselect.png")
                                    return(1)
                        else:
                            quit.click("closeitemselect.png")
                            return(1)
                else:
                    if game.exists("another close button.png"):
                        game.click("another close button.png")
                    quit.click("closeitemselect.png")
                    return(1)
            except:
                x=3
                return(0)
        else:
            return(0)

How could I use image lists to scan for any of the 4 worker icons and then send the correct sets of images to the function?

Revision history for this message
RaiMan (raimund-hocke) said :
#9

--- A general comment:
if you have found something in a region (e.g. with game.exists(someImage)) then you can use game.click(getLastMatch()) to click, what just was found in region game.

            if game.exists("another close button.png"):
                        game.click("another close button.png")

the click in your case triggers another search, that costs valuable time.

--- speeding things up:
If you think something should be there or if you are searching a sequence of images to find out, which one is there:
match = region.exists(someImage, 0)

The 0 tells the search to only look once and come back immediately, found or not.

Revision history for this message
RaiMan (raimund-hocke) said :
#10

      customerlist = ("buyitem-2.png","dungeonquester.png","questgiver.png")
        if customer.exists(customerlist):

should not work, because exists() does not accept a list of images (supposing customer is a region).

… or do you have a class, that has a function exists, that in turn accepts a list of images to search?

Revision history for this message
RaiMan (raimund-hocke) said :
#11

at comment #8:

looks ugly because of the many necessary indents
    if clicker(item1)==0:
                        if item2 != 0:
                            if clicker(item2)==0:
                                if item3 != 0:
                                    if clicker(item3)==0:
                                        if item4 != 0:
                                            if clicker(item4)==0:

this is better:
doit = clicker(item1)==0 and item2 != 0 and clicker(item2)==0
doit = doit and item3 != 0 and clicker(item3)==0 and item4 != 0 and clicker(item4)==0
if doit:

Revision history for this message
RaiMan (raimund-hocke) said :
#12

your question in comment #8:

images = (img1, img2, img3, img4)
found = []

for i in range(len(images)):
    if exists(images[i], 0):
        found.append(True)
    else:
        found.append(False)

if found[3]:
    print "img4 was found"

Revision history for this message
Smizzy (mad-dugas) said :
#13

Ok, wow, thats a lot of very intense things. I learned programming from a C programming course so my natural reaction was to just do massive if chains, this doit function seems very handy.

The exists(image.png, 0) seems very useful, how many times does the exists function normally search without specifying 0?

Yeah, 'customer','game', 'quit', 'selling' are all regions, I made about 10 different regions for different buttons/icons to speed up searches. Also it was the only way i found to stop it from searching my second screen.

Your post #12, how does "found = []" work? what does the found. prefix do to change the append function? And does this search for all 4 images at once? or is it just a faster/neater way to search 1 at a time?

Thank you again for all of the input!

Revision history for this message
RaiMan (raimund-hocke) said :
#14

A search no matter triggered by what method (find, click, exists, …) waits 3 seconds in the standard for something to appear before giving up. if possible, 3 searches per second are done in the standard. Both waiting time and scan rate can be adjusted.
To get a feeling about the options, you should read at least once across the docs:
http://sikulix-2014.readthedocs.org/en/latest/index.html

--- to stop it from searching my second screen.
This only applies to the capture feature (getting an image into your script) and for the preview feature.
When a script is running, it only searches in the given region or the primary screen (the one you get with Screen(0)) if no region is given.

--- post #12
found = []
defines an empty array (called list in Python)
and found.append() simply adds the given value to the end of the array.

the snippet simply looks for all given images one after the other (the exists might be restricted by a region) and records success/fail in array found.

Revision history for this message
Smizzy (mad-dugas) said :
#15

Im having an issue with your suggestion in post#9 about using click(getLastMatch) when an exists has just been run.

    if day.exists("endday.png",0):
        day.click(getLastMatch())
        wait(0.5)

In this section of code the endday.png is found but it is not clicked, the mouse doesnt move and the loop moves on. When i change getLastMatch() back to endday.png it fixes this issue. Am I missing something in my usage of it?
Similar sections of code are behaving the same.
Swapping it to
        try:
            day.find("endday.png")
            day.click(getLastMatch())
        except:
            pass
also doesnt click on the found image and continues the rest of the script.
i used highlight() on the regions to visually verify the button was actually inside the searched regions.

And thank you for the sikuli document! I'd seen it once but couldn't find the link again, I'll be sure to bookmark it this time.

Revision history for this message
RaiMan (raimund-hocke) said :
#16

Sorry for the mistake:
getLastMatch() is region specific.

So correctly:
   if day.exists("endday.png",0):
        click(day.getLastMatch())
        wait(0.5)

with version 1.0.1+ this will do the same (a convenience)
   if day.exists("endday.png",0):
        day.click()
        wait(0.5)