1

I'm writing a code using Python 3.8 where the user is asked to press a button as soon as an image appears. The image is then replaced with a white screen for a random interval of 1 to 4 seconds, until a new image appears. I used cv2.waitKey() until the spacebar gets pressed: no problem, works just fine. See below:

    import sys, cv2, random

    im = cv2.imread('image.tiff')                    
    imBlank = cv2.imread('imageBlank.tiff')            
    cv2.namedWindow('win', cv2.WINDOW_NORMAL) 

    for i in range(5):           # create a loop that runs 5 times
        cv2.imshow('win', im)    # show the image
        k = cv2.waitKey(0)       # wait until key press           
        if k == 32:              # when space bar is pressed
            cv2.imshow('win', imBlank)  # show a blank screen
            SI = random.randint(1,4)    # random interval between 1 and 4 seconds
            cv2.waitKey(SI*1000)        # wait for random interval until loop starts again

Now the problem is that I want to do exactly this, but instead of the space bar, I want the user to press a mouse button. For as far as I can find, the cv2.waitKey() function does not work with the mouse, so I wrote the code below:

    def showBlank(event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDOWN:
            cv2.imshow('win', imBlank)
        elif event == cv2.EVENT_RBUTTONDOWN:
            cv2.imshow('win', imBlank)              
            
    # repeat the loop 5 times
    for i in range(5):
        cv2.imshow('win', im)                       # show the image
        cv2.setMouseCallback('win', showBlank)      # go to function showBlank()
        """ wait here until mouse button is clicked"""
        SI = random.randint(1,4)                    # random interval between 1 and 4 seconds
        cv2.waitKey(SI*1000)                        # wait for random interval until loop starts again

Again, this code basically works, but if the user does not press the mouse button, the loop keeps running anyways. I want the loop to wait for the random interval to start until the mouse is clicked.

Thanks! I hope someone can help me out here

1 Answer 1

2

I developed this solution which worked on my computer using Python 3.8.0.

import sys, cv2, random

def swapImages():
    cv2.imshow('win', imBlank)
    SI = random.randint(1,4)
    cv2.waitKey(SI*1000)
    cv2.imshow('win', im)    

def showBlank(event, x, y, flags, param):
    #param is the array i from below
    if event == cv2.EVENT_LBUTTONDOWN:
        print("showBlank: i[0]: ", param)
        swapImages()
        param[0] = param[0] + 1
    elif event == cv2.EVENT_RBUTTONDOWN:
        print("showBlank: i[0]: ", param)
        swapImages()
        param[0] = param[0] + 1
                    
im = cv2.imread('image.tiff')                    
imBlank = cv2.imread('imageBlank.tiff')            
cv2.namedWindow('win', cv2.WINDOW_NORMAL) 

i = [0]
# the mousecallback only needs to be set once
cv2.setMouseCallback('win', showBlank, i )
        
# show the initial image for the first time.
cv2.imshow('win', im)

while i[0] < 5:    
  cv2.waitKey(10)

According to this it is not posssible to wait for a mouse click the same way, one can wait for a keyboard input. Because of that, I needed to alter the original code a bit. What the above code does, is to run a while loop until the variable i[0] reaches the value 5. i[0] is increased each time, the image was clicked.

A few explanations to the code:

The array

i = [0]

is passed to the mousecallback via the "param" parameter.

cv2.setMouseCallback('win', showBlank, i )

As described in this, "i" needs to be a container, because

Python passes references to objects. Inside your function you have an object -- You're free to mutate that object (if possible). However, integers are immutable. One workaround is to pass the integer in a container which can be mutated

i[0] changes at each mouse event

param[0] = param[0] + 1

and when i[0] reaches 5, the while loop ends.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.