Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

The way this series of columns are written

This series of columns will use the first question-and-answer writing format to quickly introduce you to the beginner, intermediate, and advanced levels of OpenCV.

4. Mouse event handling in Python OpenCV and FAQ solutions

This blog focuses on the cv2.setmousecallback function and how to solve problems with it in everyday coding.

This function is mainly used to deal with mouse related events in OpenCV function, through which it can capture the event triggered by data, and its processing.

Before using this function, you can check the basic usage through the help function.

The function prototype is as follows:

setMouseCallback(windowName, onMouse [, param]) -> None
Copy the code

As you can see, this function takes two arguments: the window name and the callback function. The window name should be the same as the one in cv2.imshow.

From the function prototype, you can see that the cv2.setMouseCallback function is setting a callback function to the window.

What are the mouse events in OpenCV?

The code for viewing events is shown below, which can be viewed using the built-in dir function.

import cv2

def show_event() :
    events = [i for i in dir(cv2) if 'EVENT' in i]
    print(events)

if __name__ == "__main__":
    show_event()
Copy the code

The result is as follows, with all event-related functions listed.

['EVENT_FLAG_ALTKEY', 'EVENT_FLAG_CTRLKEY', 'EVENT_FLAG_LBUTTON', 'EVENT_FLAG_MBUTTON', 'EVENT_FLAG_RBUTTON', 'EVENT_FLAG_SHIFTKEY', 'EVENT_LBUTTONDBLCLK', 'EVENT_LBUTTONDOWN',
'EVENT_LBUTTONUP', 'EVENT_MBUTTONDBLCLK', 'EVENT_MBUTTONDOWN', 'EVENT_MBUTTONUP', 'EVENT_MOUSEHWHEEL', 'EVENT_MOUSEMOVE', 'EVENT_MOUSEWHEEL', 'EVENT_RBUTTONDBLCLK', 'EVENT_RBUTTONDOWN', 'EVENT_RBUTTONUP']
Copy the code

The most commonly used events are EVENT_LBUTTONDOWN and EVENT_LBUTTONUP, which we will focus on next.

EVENT_LBUTTONDOWN Event that the left mouse button is pressed.

First render a form with the following code to test the left mouse button down.

import cv2


def show_event() :
    events = [i for i in dir(cv2) if 'EVENT' in i]
    print(events)


def mouse_handler(event, x, y, flags, userdata) :
    if event == 1:   # cv2.EVENT_LBUTTONDOWN
        print("Left mouse button down")


if __name__ == "__main__":

    image = cv2.imread("./tt.jpg")

    cv2.namedWindow("mouse_event")
    cv2.imshow("mouse_event", image)
    cv2.setMouseCallback("mouse_event", mouse_handler)
    cv2.waitKey()

Copy the code

The running effect of the code is as follows. Click the left mouse button on the picture to input data on the console. The output content is shown in the red box in the screenshot.

Note that the setMouseCallback function will bind successfully even if you do not load any images and just name the window as nameWindow.

# image = cv2.imread("./tt.jpg")

cv2.namedWindow("mouse_event")
# cv2.imshow("mouse_event", image)
cv2.setMouseCallback("mouse_event", mouse_handler)
Copy the code

From the above example, we can also infer that the cv2.setMouseCallback callback, onMouse, has a certain format because it appears in the above code:

def mouse_handler(event, x, y, flags, userdata) :
Copy the code

The format of the callback function is the same for all mouse events, but the implementation inside the function is different.

The parameters are described as follows:

  • event: The name of the mouse event, through which you can obtain the event operation of the mouse.
  • x, y: The coordinate position of the mouse for event operation moment;
  • flags: refers to andeventRelated practices are includedFLAGThe events;
  • userdata: The argument passed in when the mouse callback function is triggered.

The above parameters are easy to understand, but there is a lot of content on the network that does not specify flags parameters.

This parameter is actually a subset of all the events we got above, looking at all the events we got before.

['EVENT_FLAG_ALTKEY'.'EVENT_FLAG_CTRLKEY'.'EVENT_FLAG_LBUTTON'.'EVENT_FLAG_MBUTTON'.'EVENT_FLAG_RBUTTON'.'EVENT_FLAG_SHIFTKEY'.'EVENT_LBUTTONDBLCLK'.'EVENT_LBUTTONDOWN'.'EVENT_LBUTTONUP'.'EVENT_MBUTTONDBLCLK'.'EVENT_MBUTTONDOWN'.'EVENT_MBUTTONUP'.'EVENT_MOUSEHWHEEL'.'EVENT_MOUSEMOVE'.'EVENT_MOUSEWHEEL'.'EVENT_RBUTTONDBLCLK'.'EVENT_RBUTTONDOWN'.'EVENT_RBUTTONUP']
Copy the code

In which you focus on looking for values with flags, search as follows:

'EVENT_FLAG_ALTKEY'.'EVENT_FLAG_CTRLKEY'.'EVENT_FLAG_LBUTTON'.'EVENT_FLAG_MBUTTON'.'EVENT_FLAG_RBUTTON'.'EVENT_FLAG_SHIFTKEY'
Copy the code

For example, if we want to drag while holding down the left mouse button, the core code is:

event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON
Copy the code

While holding down CTRL, press the left mouse button as follows

event == cv2.EVENT_LBUTTONUP and flags == cv2.EVENT_FLAG_CTRLKEY
Copy the code

Now let’s implement how to hold down the left mouse button and drag to draw a rectangle.

import cv2

image = cv2.imread("./tt.jpg")
cv2.namedWindow("mouse_event")
x1, y1 = 0.0


def show_event() :
    events = [i for i in dir(cv2) if 'EVENT' in i]
    print(events)


def mouse_handler(event, x, y, flags, userdata) :
    global x1, y1
    if event == cv2.EVENT_LBUTTONDOWN:
        print("Left click")
        x1, y1 = x, y

    if event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
        # print(" Left mouse button drag ")
        cv2.rectangle(image, (x1, y1), (x, y), (0.255.0), -1)


if __name__ == "__main__":
    cv2.setMouseCallback("mouse_event", mouse_handler)
    while True:
        cv2.imshow("mouse_event", image)
        k = cv2.waitKey(1) & 0xFF
        if k == 27:
            break

    cv2.destroyAllWindows()
Copy the code

This code does not use the last parameter, userdata. Let’s apply this parameter by passing it as an argument.

Cv2. setMouseCallback passes the image read to the callback function, as shown below

cv2.setMouseCallback("mouse_event", mouse_handler, image)
Copy the code

OpenCV captures mouse event solutions in video

Now that we’ve captured mouse events in images, let’s see how we can do the same in videos.

As we already know, video processing is an operation for each frame of a video, which can be carried out in the following code.

import cv2


def mouse_handler(event, x, y, flags, frame) :

    if frame is not None:
        Get coordinates for testing
        # print(x, y)
        if event == cv2.EVENT_MOUSEMOVE:
            cv2.putText(frame, "Hello OpenCV", (x, y),
                        cv2.FONT_HERSHEY_COMPLEX, 1, (255.0.0))
            cv2.imshow("video", frame)


if __name__ == "__main__":

    cap = cv2.VideoCapture("./test.mp4")
    while cap.isOpened():
        ret, frame = cap.read()
        if ret:
            cv2.imshow("video", frame)
            cv2.setMouseCallback("video", mouse_handler, frame)
            if cv2.waitKey(25) & 0xFF= =27:
                break

    cap.release()
    cv2.destroyAllWindows()
Copy the code

The above code is bound to the EVENT_MOUSEMOVE event, so when the mouse moves, a “Hello OpenCV” will appear, but this method will cause the video to repeatedly render, which is inefficient, and the page will crash after several frequent refresh times.

If you’re just testing, set the number in cv2.waitkey (25) to 1000, and the video will play slower to capture the final image.

For the mouse callback function learning, the key to master is still a variety of events, there is also a need to pay attention to the combination of key and mouse position calculation, you can implement a simple OpenCV drawing board based on this, of course, the premise is that you are familiar with the graph drawing function before learning.

Additional knowledge, OpenCV to draw polygons

In the last blog post, we were missing a function to draw polygons, which we added here. This function is called cv2.polylines.

polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]]) -> img
Copy the code

The most important of these is PTS, which represents the polygon array to be drawn and can also be understood as the vertex sequence coordinates of the polygon.

For example:

image = np.zeros((400.400.3), np.uint8)
points = np.array(
    [[50.50], [170.100], [200.150], [300.320]], np.int32)
cv2.polylines(image, [points], True, (255.0.0))
cv2.imshow('image',image)
cv2.waitKey()
Copy the code

The polygons drawn are as follows:

Finally, you can combine the cv2.setMouseCallback function you learned in this article with the draw line function to implement a manual polygon drawing tool.