Creating an eitherOr method

Asked by G-Mint

Hey

Been working with Sikuli for a while now and one method I started to need rather quickly was some kind of "either or". By this I mean a method that takes one or more images and returns a match if it can see any.

Was surprised to see Sikuli didn't appear to have this built in as it seems like a natural extension (unless I missed one :P), so I went ahead and made my own:

def eitherOr(imageList):
    for x in range(0, len(imageList)):
            if(exists(imageList[x], 0)):
                return imageList[x]

Now this is rather rough but it does work. I use it mainly with 2 images, usually the two same links or buttons on different looking browsers.

It's not perfect by any means. It's main problem at the moment is if the first image is not found the exists call waits for some time (even with the 0 secs defined?) dragging the whole method down and increasing time exponentially.

So I was wondering what you guys thought about this and if there are any more efficient ways to do this?

Any help would be brilliant! Thanks!

Question information

Language:
English Edit question
Status:
Answered
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
j (j-the-k) said :
#1

So I made this "waitForAny"-method some time ago.
It uses an observer and waits for a number of images to appear. If one of the images is found, the observer is stopped and the method returns. If more than one image is found at the same time, the image with the highest score wins.

Here is a simplified version to show the principle:

# region: region where the images are searched
# observetime: time, how long the images will be searched
# *args: list of images that will be searched
def waitForAny(region, observetime, *args):

    # list to save the results
    results = []
    # create a method-local new region to keep the parent region clean of observers because observers cannot be removed
    region = Region(region)

    # handler that is called when an image is found
    def getHandleFind():
        def handleFind(event):
            event.region.stopObserver()
            results.append(event.match)
        return handleFind

    # iterate over all images
    for img in args:
        # add onAppear for every image
        region.onAppear(img,getHandleFind())

    # start observation
    region.observe(observetime)

    if (len(results) == 0):
        return None

    results = sorted(results,key=lambda result: result.getScore(), reverse=True) # sort all results by score
    bestMatch = results[0]
    # return image and index of best match and match object
    return bestMatch

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

--- exists(image, 0) waits too long if not found
This is a known "bug".
The standard scan rate for normal searches (observe has its own), is 3, which means a search will take place only 3 times a second.
If you squeeze everything out of Sikuli to get performance (search times even below 0.1 seconds), this will always wait 0.3 seconds (frustrating ;-)

try
Settings.waitScanRate = 100

But be aware, that this might exhaust your cpu ;-)

Another option is to delegate your searches in the def() to parallel threads (which in fact will be the case, if you use observe in the background version, but might be slightly slower than exists())

Can you help with this problem?

Provide an answer of your own, or ask G-Mint for more information if necessary.

To post a message you must log in.