Determining Required Image Search Threshold

Last edited on

When using the Squish IDE for executing a test script, and the findImage() function does not find the desired image, the Squish IDE will show the "Image Not Found" dialog, which offers the option "Adjust Search Parameters", which will calculate the required threshold value for fuzzy/"tolerant" image search.

It is possible to mimic the same behavior in script code, for example to report the required threshold in case test.imagePresent() or when not using the Squish IDE:

# -*- coding: utf-8 -*-

import names

import os


def main():
    startApplication("%s/examples/qt5/calqlatr/calqlatr" % os.getenv("SQUISH_PREFIX"))


    # Example of "tolerant" image search and a threshold value
    # that the Squish IDE had adjusted for a specific case:
    #findImage("my_search_image",{ "tolerant": True, "threshold": 99.853 })


    # One can use the same "tolerant" image search with
    # test.imagePresent("my_search_image"):
    #test.imagePresent("my_search_image",{ "tolerant": True, "threshold": 99.853 })


    # But we want our script code to compute the threshold now:
    if not test.imagePresent("my_search_image"):
        log_required_threshold("my_search_image")


def log_required_threshold(img_name):
    def img_present(img_name, threshold):
        backup = testSettings.imageNotFoundDebugging
        testSettings.imageNotFoundDebugging = False
        try:
            findImage(img_name, { "timeout": 1, "tolerant": True, "threshold": threshold / 1000.0})
            return True
        except:
            return False
        finally:
            testSettings.imageNotFoundDebugging = backup


    # A very lenient threshold, may result in matching
    # too many other things on the screen:
    initial_floor = 97000
    floor = initial_floor

    # This basically means exact matching:
    ceiling = 100000

    # Wait a little to ensure previous messages are
    # shown on the control bar first:
    snooze(0.2)


    test.warning(f"Determining required threshold for image '{img_name}'...")


    while True:
        diff = ceiling - floor
        mid = diff // 2 + floor
        if diff == 0 and not img_present(img_name, mid):
            raise LookupError(f"Image '{img_name}' not found with threshold {initial_floor / 1000.0:.03f} to 100")

        if img_present(img_name, mid):
            # If the next larger threshold does not find the image,
            # we found the highest threshold:
            if mid == ceiling or not img_present(img_name, mid + 1):
                test.warning(f"Required threshold: {mid / 1000.0}")
                return mid
            floor = mid + 1
        else:
            ceiling = mid - 1
test.py