Python OpenCV mouse events

Introduction

In this tutorial we will learn how to get started handling OpenCV mouse events, in Python.

We will create a very simple application where we will track the position of the mouse in a window by drawing a circle on it. So, we will only make use of one of the event types available, but the full list can be seen on this page.

This tutorial was tested on Windows 8.1, with version 4.1.2 of OpenCV. The Python version used was 3.7.2.

The code

We will start our code by importing the cv2 module, so we have access to all the functions we need for our tutorial.

import cv2

After that, we will read an image from the file system, to show it in a window. It will be on that window that we will be listening to the mouse moved events. For a detailed tutorial on how to read an image and display it on a window, please check here.

Note that we will call “image” to the window. We will need this name to register the function that will handle the mouse events.

img = cv2.imread('C:/Users/N/Desktop/test.png')
cv2.imshow('image', img)

Then we will call the setMouseCallback function from the cv2 module to start listening to mouse events. As first input, this function receives the name of the window and as second a callback function that will be invoked every time a mouse event happens. We will check its definition later, but we will call this function drawCircle.

Just as an additional note, this function can receive an additional “user data” parameter that will later be passed to the callback function when it is invoked. Nonetheless, we are not going to make use of it.

cv2.setMouseCallback('image', drawCircle)

Then we will wait for a user input in the keyboard to end the program and destroy the window.

cv2.waitKey(0)
cv2.destroyAllWindows()

To finalize, we will check the implementation of the drawCircle function. As input, this function should receive 5 parameters (the last 2 we won’t be using), accordingly to what is defined here. The parameters are summarized below:

  • event: the OpenCV mouse event that was detected and triggered the execution of the callback. The list of existing events can be seen here;
  • x: the x coordinate, in the window, of the mouse event;
  • y: the y coordinate, in the window, of the mouse event;
  • flags: one of the flags defined here;
  • params: optional user defined data that can be passed to the callback. Needs to be defined when registering the callback if we want to use it, like mentioned before.

We start by checking if the event we received is a mouse movement event. To do so, we will compare the received parameter with the constant EVENT_MOUSEMOVE from the cv2 module. This is the only event type we want to handle on this tutorial.

if event == cv2.EVENT_MOUSEMOVE:

If a mouse movement event happened, then we will print the x and y coordinates we also received as parameters.

print('({}, {})'.format(x, y))

After that, we will draw a blue circle with center on these coordinates. You can check how to draw circles on images with OpenCV on this previous tutorial.

Note that drawing a circle alters the image we provide. So, if we start drawing the circles on the original image, we will have the circles all over it as we are moving the mouse. To avoid this, we will always create a copy of the original image and draw the circle on the copy. To learn how to copy an image in OpenCV, please consult this tutorial.

Once we have the copy of the image, we then draw the circle and show the image on the same window we created in the previous code (recall the window is called “image“).

imgCopy = img.copy()
cv2.circle(imgCopy, (x, y), 10, (255, 0, 0), -1)

cv2.imshow('image', imgCopy)

The full callback function is shown on the code snippet below.

def drawCircle(event, x, y, flags, param):

    if event == cv2.EVENT_MOUSEMOVE:
        print('({}, {})'.format(x, y))

        imgCopy = img.copy()
        cv2.circle(imgCopy, (x, y), 10, (255, 0, 0), -1)

        cv2.imshow('image', imgCopy)

The complete code can be seen below.

import cv2

def drawCircle(event, x, y, flags, param):

    if event == cv2.EVENT_MOUSEMOVE:
        print('({}, {})'.format(x, y))

        imgCopy = img.copy()
        cv2.circle(imgCopy, (x, y), 10, (255, 0, 0), -1)

        cv2.imshow('image', imgCopy)


img = cv2.imread('C:/Users/N/Desktop/test.png')
cv2.imshow('image', img)

cv2.setMouseCallback('image', drawCircle)

cv2.waitKey(0)
cv2.destroyAllWindows()

Testing the code

To test the code, simply run it in a tool of your choice. In my case, I’m using PyCharm, a Python IDE from JetBrains.

Upon running the code and moving the mouse over the window, you should see a result similar to figure 1. Also, on the console, you should see the coordinates of the mouse getting printed.

Image with blue circle drawn from the position of the mouse obtained from the OpenCV mouse events.
Figure 1 – Image with the blue circle drawn on the mouse position.

Figure 2 is a GIF showing this behavior.

Drawing a blue circle on the mouse position, accordingly to the coordinates retrieved from the OpenCV event.
Figure 2 – Drawing a blue circle on the mouse position.

Leave a Reply