Adding slider and mouse events to our interfaces
Mouse events and slider control are very useful in computer vision and OpenCV. Using these control users, we can interact directly with the interface and change the properties of the input images or variables. In this section, we are going to introduce the mouse events and slider controls for basic interactions. To facilitate proper understanding, we have created the following code, by means of which we are going to paint green circles in an image, using mouse events, and blur the image with the slider:
// Create a variable to save the position value in track int blurAmount=15; // Trackbar call back function static void onChange(int pos, void* userInput); //Mouse callback static void onMouse(int event, int x, int y, int, void* userInput); int main(int argc, const char** argv) { // Read images Mat lena= imread("../lena.jpg"); // Create windows namedWindow("Lena"); // create a trackbar createTrackbar("Lena", "Lena", &blurAmount, 30, onChange, &lena); setMouseCallback("Lena", onMouse, &lena); // Call to onChange to init onChange(blurAmount, &lena); // wait app for a key to exit waitKey(0); // Destroy the windows destroyWindow("Lena"); return 0; }
Let's understand the code!
First, we create a variable to save the slider position. We need to save the slider position for access from other functions:
// Create a variable to save the position value in track int blurAmount=15;
Now, we define our callbacks for our slider and mouse event, required for the OpenCV functions setMouseCallback and createTrackbar:
// Trackbar call back function static void onChange(int pos, void* userInput); //Mouse callback static void onMouse(int event, int x, int y, int, void* userInput);
In the main function, we load an image and create a new window called Lena:
int main(int argc, const char** argv) { // Read images Mat lena= imread("../lena.jpg"); // Create windows namedWindow("Lena");
Now is the time to create the slider. OpenCV has the createTrackbar function to generate a slider with the following parameters in order:
- Trackbar name.
- Window name.
- Integer pointer to use as a value; this parameter is optional. If it is set, the slider attains this position when created.
- Maximum position on slider.
- Callback function when the position of the slider changes.
- User data to send to callback. It can be used to send data to callbacks without using global variables.
To this code, we add trackbar for the Lena window and call the Lena trackbar too in order to blur the image. The value of the trackbar is stored in the blurAmount integer that we pass as a pointer and set the maximum value of the bar to 30. We set up onChange as a callback function and send the lena mat image as user data:
// create a trackbar createTrackbar("Lena", "Lena", &blurAmount, 30, onChange, &lena);
After creating the slider, we add the mouse events to paint circles when a user clicks the left button on the mouse. OpenCV has the setMouseCallback function. This function has three parameters:
A window name where we get mouse events.
A callback function to call when there is any mouse interaction.
User data: this is any data that will be sent to the callback function when it's fired. In our example, we'll send the entire Lena image.
Using the following code, we can add a mouse callback to the Lena window and set up onMouse as a callback function, passing the lena mat image as user data:
setMouseCallback("Lena", onMouse, &lena);
To finalize the main function only, we need to initialize the image with the same parameter as the slider. To carry out the initialization, we only need to call the onChange callback function and wait for events before closing the windows with destroyWindow, as can be seen in the following code:
// Call to onChange to init
onChange(blurAmount, &lena); // wait app for a key to exit waitKey(0); // Destroy the windows destroyWindow("Lena");
The slider callback applies a basic blur filter to the image using the slider value as a blur quantity:
// Trackbar call back function
static void onChange(int pos, void* userData) {
if(pos <= 0) return;
// Aux variable for result
Mat imgBlur;
// Get the pointer input image
Mat* img= (Mat*)userInput;
// Apply a blur filter
blur(*img, imgBlur, Size(pos, pos));
// Show the result
imshow("Lena", imgBlur);
}
This function checks whether the slider value is 0 using the variable pos. In this case, we do not apply the filter because it generates a bad execution. We cannot apply a 0 pixel blur either. After checking the slider value, we create an empty matrix called imgBlur to store the blur result. To retrieve the image sent through user data in the callback function, we have to cast void* userData to the correct image type pointer Mat*.
Now we have the correct variables to apply the blur filter. The blur function applies a basic median filter to an input image, *img in our case; to an output image, the last required parameter is the size of the blur kernel (a kernel is a small matrix used to calculate the means of convolution between the kernel and the image) that we want to apply. In our case, we are using a squared kernel of pos size. Finally, we only need to update the image interface using the imshow function.
The mouse events callback has five input parameters: the first parameter defines the event type; the second and third define the mouse position; the fourth parameter defines the wheel movement; and the fifth parameter defines the user input data.
The mouse event types are as follows:
In our sample, we only manage events that result from a left-click of the mouse, and any event other than EVENT_LBUTTONDOWN is discarded. After discarding other events, we obtain the input image like that with the slider callback, and with a circle in the image using the circle OpenCV function:
//Mouse callback static void onMouse(int event, int x, int y, int, void* userInput) { if(event != EVENT_LBUTTONDOWN) return; // Get the pointer input image Mat* img= (Mat*)userInput; // Draw circle circle(*img, Point(x, y), 10, Scalar(0,255,0), 3); // Call on change to get blurred image onChange(blurAmount, img); }