customizing how an observer finds an event

Asked by Joshua Spinak on 2019-11-17

Hi, I would like to use observer to find images based on color. I am using the java code from user aguelle for finding a match by color and the example java code from RaiMan for observers. Code for both methods is below.

The custom class MinSimColoredScreen from aguelle that extends Screen overrides the following methods:
<PatternOrString> Match wait(PatternOrString target, double timeout)
Observer getObserver()

I assumed when I called onAppear and observeInBackground from a MinSimColoredScreen instance, that observe would use the wait method from MinSimColoredScreen. This doesn't happen though. How does observe work exactly and is it possible to customize the way it finds and records events?

btw, Sikuli is great, thanks RaiMan!

Josh
---

/**
 * This class implements support for colored pattern matching if similarity has
 * to be quite low.
 *
 * @author aguelle
 *
 */
public class MinSimColoredScreen extends Screen {

    public MinSimColoredScreen() {
        super();
    }

    /**
     * Constructor
     *
     * @param searchRegion
     * The search region
     */
    public MinSimColoredScreen(Region searchRegion) {
        setSearchRegion(searchRegion);
    }

    static Logger log = Logger.getLogger(MinSimColoredScreen.class.getName());

    private final double MAX_COLOR_DIFFERENCE = 0.07;
    private Region searchRegion;

    @Override
    public <PatternOrString> Match wait(PatternOrString target, double timeout)
            throws FindFailed {
        System.out.println("in MinSim");
        long startingTime = System.currentTimeMillis();
        long timeoutMS = (long) (timeout * 1000);

        boolean found = false;
        Match match = null;
        long usedTime = 0;
        Color colorFoundImage = null;
        Color colorTargetImage = null;
        double colorDifference = -1;

        while (usedTime < timeoutMS && found == false) {

            match = super.wait(target, timeout);
            Rectangle targetRect = match.getRect();
            BufferedImage targetImage = match.getImage().get();

            try {
                Thread.sleep(10);
            } catch (InterruptedException e1) {
                log.error("Thread Sleep failed.", e1);
            }

            // take screenshot of found region
            BufferedImage foundImage = null;
            try {
                foundImage = new Robot().createScreenCapture(new Rectangle(
                        targetRect));
            } catch (AWTException e) {
                log.error("Creating screen capture failed.", e);
            }

            // compare average colors of target image and screenshot of the
            // found region
            colorFoundImage = new Color(ImageUtils.getAverageColor(foundImage));
            colorTargetImage = new Color(
                    ImageUtils.getAverageColor(targetImage));

            colorDifference = ImageUtils.getColorDifference(colorFoundImage,
                    colorTargetImage);

            if (colorDifference <= MAX_COLOR_DIFFERENCE) {
                found = true;
            }

            usedTime = System.currentTimeMillis() - startingTime;
        }

        if (!found) {
            throw new FindFailed("Color does not match");
        }

        log.debug(target + " found!");
        return match;
    }

    /**
     * Sets the search region for the screen
     *
     * @param searchRegion
     * The search region
     */
    public void setSearchRegion(Region searchRegion) {
        this.searchRegion = searchRegion;
        setH(searchRegion.h);
        setW(searchRegion.w);
        this.setLocation(new Location(searchRegion.x, searchRegion.y));
    }

    public Region getSearchRegion() {
        return searchRegion;
    }

    @Override
    public Observer getObserver() {
        return super.getObserver();
    }
}

---

public class Example {

    public Example() {}

    //a helper for the formatted printout:
    private static void p(String msg, Object... args) {
        System.out.println(String.format(msg, args));
    }

    //the example:
    private void findColor() {
        String orange = "orange.png";
        Region reg = new Region(0, 0, 880, 580); // define the observed region
        MinSimColoredScreen minSimColoredScreen = new MinSimColoredScreen(reg);
        minSimColoredScreen.getSearchRegion().highlight(2);
        minSimColoredScreen.onAppear(orange, new ObserverCallBack() { // define the handler
            @Override
            public void appeared(ObserveEvent evt) {
                if (evt.isAppear()) {
                    evt.getMatch().highlight(1);
                    evt.stopObserver();
                } else {
                    p("im handler: match nicht gefunden");
                }
            }
        });
        minSimColoredScreen.observeInBackground(); // start observation in background forever
        int n = 0;
        while (minSimColoredScreen.isObserving()) { // do something while observe is running
            p("%d - observing", n);
            reg.wait(1.0);
            n++;
        }
    }

    public static void main(String args[]) {
        Example example = new Example();
        example.findColor();
    }
}

Question information

Language:
English Edit question
Status:
Solved
For:
Sikuli Edit question
Assignee:
No assignee Edit question
Solved by:
RaiMan
Solved:
2019-11-18
Last query:
2019-11-18
Last reply:
2019-11-18
Best RaiMan (raimund-hocke) said : #2

Sorry, but not possible this way.

Reason: the find implementation is hardwired deep down in the Observer implementation and cannot be overwritten.

2 possible solutions:

1. put your post-evaluation into the handler

2. make your own background-observer (running some synchronised thread) using the features of class Finder with a current screenshot and the image waiting for.

Joshua Spinak (jspinak) said : #3

Thanks RaiMan, that solved my question.