Flow of Control Python OpenCv : Why cv2.setMouseCallback isn't inside loop?

Viewed 1090

I am confused with the flow of control in the following program. The purpose of the code is to draw a rectangle in the live video stream from the webcam.

Working Principal: First click will be initializing coordinates of the starting corner of the rectangle and mark it with a bold circle. Second click will be completing the rectangle.

Now my Question is: Why is cv2.setMouseCallback('Test',draw_rectangle) statement isn't inside the loop?

The code is working perfectly fine but I am unable to understand the flow of control. Please help me out.

    import cv2
    import os
    os.environ["OPENCV_VIDEOIO_PRIORITY_MSMF"] = "0" 


#CALLBACK FUNCTION RECTANGLE
def draw_rectangle(event,x,y,flags,param):  #Param is the just the additional paramter which u can receive
    global pt1, pt2, topLeft_Clicked, botRight_Clicked
    if event ==cv2.EVENT_LBUTTONDOWN:

        #Reset if rectangle is drawing i.e both var are true
        if topLeft_Clicked and botRight_Clicked:
            pt1=(0,0)
            pt2=(0,0)
            topLeft_Clicked=False
            botRight_Clicked=False
        if topLeft_Clicked == False:   
            pt1=(x,y)
            topLeft_Clicked=True
        elif  botRight_Clicked == False:
            pt2=(x,y)
            botRight_Clicked=True



#GLOBAL VARIABLES
pt1=(0,0)
pt2=(0,0)

topLeft_Clicked= False
botRight_Clicked= False

#COnnect to the Callback
cap=cv2.VideoCapture(0)
cv2.namedWindow('Test')
cv2.setMouseCallback('Test',draw_rectangle)
while True:

    ret,frame=cap.read()

    #Drawing Based on Global Variables

    if topLeft_Clicked: # If topleft is true
        cv2.circle(frame,center=pt1,radius=5,color=(0,0,255),thickness=-1)

    if topLeft_Clicked and botRight_Clicked:
        cv2.rectangle(frame,pt1,pt2,(0,0,255),3)

    cv2.imshow('Test',frame)

    if(cv2.waitKey(1) & 0xFF==ord('q')):
        break

cap.release()
cv2.destroyAllWindows()
3 Answers

Callback is the function that is called every time you move the mouse over the display window. It is independent from the flow in main, i.e., it is in a new thread waiting for changes in mouse input.

The reason why you use loop in main is because you want to update the image you display. After calling imshow, you need to call waitKey for impact on rendering.

Callback functions are called on events. Unlike a regular function, you don't need to make a function call every time you want it to run.

The line cv2.setMouseCallback('Test',draw_rectangle) will set the function draw_rectangle as a response to any event received from mouse on the OpenCV window "Test". Once the callback is set, inside your while loop you will catch all your mouse events on your "Test" window.

cv2.setMouseCallback('Test',draw_rectangle) this function is actually an event handler, which is setting the call for draw_rectangle function on every left mouse click. The rest of the code inside the while loop are for all the dynamic operations and at last cv2.imshow is to render that in the image.

One token of gift for better handling of opencv closeWindows, closing only currently used window only:

def showImage(imageName, image):
    img = image.copy()
    cv2.imshow(imageName, img)
    while(1):
        pressedKey = cv2.waitKey(0) & 0xFF

        if(pressedKey == ord('q')):
            cv2.destroyWindow(imageName)
            break
        else:
            cv2.putText(img, "\press q to exit", (10,10), cv2.FONT_HERSHEY_SIMPLEX, 0.45, color=(255,0,0))
            cv2.imshow(imageName, img)
Related