Using OpenCV's highgui module
The highgui
module has been designed to provide an easy way to visualize the results and try the functionality of developed applications with OpenCV. As we saw in the previous chapter, this module supplies functions to perform the following operations:
- Reading images and videos from files and live cameras (
imread
) through aVideoCapture
object. - Writing images and videos from memory to disk (
imwrite
) through aVideoWriter
object. - Creating a window that can display images and video frames (
namedWindow
andimshow
). - Fetching and handling events when a key is pressed (
waitKey
).
Of course, the module contains more functions to enhance the user interaction with the software applications. Some of them will be explained in this chapter. In the following tbContrast
code example, we can read an image file and two windows are created: the first one shows the original image and the other is the resulting image after increasing or decreasing the contrast to the original image applying a quite simple scaling operation. The following example shows how to create a trackbar in the window to easily change the contrast factor (scale) in the image. Let's see the code:
#include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> using namespace std; using namespace cv; int main(int argc, char* argv[]) { const char in_win[]="Orig. image"; const char out_win[]="Image converted...(no saved)"; int TBvalContrast=50; // Initial value of the TrackBar Mat out_img; if (argc != 2) { cout << "Usage: <cmd><input image_file>" << endl; return -1; } Mat in_img = imread(argv[1]); // Open and read the image if (in_img.empty()) { cout << "Error!!! Image cannot be loaded..." << endl; return -1; } namedWindow(in_win); // Creates window for orig. image moveWindow(in_win, 0, 0); // Move window to pos. (0, 0) imshow(in_win, in_img); // Shows original image namedWindow(out_win); createTrackbar("Contrast", out_win, &TBvalContrast, 100); cout << "Press Esc key to exit..." << endl; while (true) { in_img.convertTo(out_img, -1, TBvalContrast/50.0); imshow(out_win, out_img); if (waitKey(50) == 27) // If Esc key pressed breaks break; } return 0; }
The following screenshot shows the original image (fruits.jpg
) and the same image with increased contrast obtained with the tbContrast
application.
The code explanation is given as follows:
void moveWindow(const string& winname, int x, int y)
: This function moves the window to the specified screen (x, y) position being the origin point (0, 0) at the upper-left corner. When a window is created and displayed, its default position is at the center of the screen. That behavior is quite convenient if only one window is displayed. However, if several windows have to be shown, they are overlapped and should be moved in order to see their content. In the example, this function is used as follows:moveWindow(in_win,0,0);
Now, the window that shows the original image is moved, after its creation, to the upper-left corner (origin) of the screen while the converted imaged is located at its default position (center of the screen).
intcreateTrackbar(const string&trackbarname, const string&winname, int*value, intrange, TrackbarCallbackonChange=0, void*userdata=0)
: This function creates a trackbar (a slider) attached to the window with the specified name and range. The position of the slider is synchronized with thevalue
variable. Moreover, it is possible to implement a callback function for being called after the slider moves. In this call, a pointer to the user data is passed as argument. In our code, this function is used as follows:createTrackbar("Contrast", out_win, &TBvalContrast, 100);
In this code, the trackbar is called
"Contrast"
without a callback function linked to it. Initially, the slider is located at the middle (50) of the full range (100). This range allows a maximum scale factor of 2.0 (100/50).void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0 ) const
: This function converts an array to another data type with an optional scaling. Ifrtype
is negative, the output matrix will have the same type as the input. The applied scaling applied formula is as follows:m(x, y) = alfa(*this)(x, y) + beta,
In this code, a final implicit cast (
saturate_cast<>
) is applied to avoid possible overflows. In thetbContrast
example, this function is used inside an infinite loop:while (true) { in_img.convertTo(out_img, -1, TBvalContrast/50.0); imshow(out_win, out_img); if (waitKey(50) == 27) // If Esc key pressed breaks break; }
In the previous chapter, we saw code examples that can create an implicit infinite loop waiting for a pressed key with the function call waitKey
(without arguments). The events on the application main window (for example, trackbars, mouse, and so on) are caught and handled inside of that loop. On the contrary, in this example, we create an infinite loop with a while
statement applying the contrast change with the convertTo
function with a scale factor from 0.0
(slider at 0
) to 2.0
(slider at 100
). The infinite loop breaks when the Esc key (ASCII code 27) is pressed. The implemented contrast method is quite simple because the new values for the pixels are calculated by multiplying the original value by a factor greater than 1.0
to increase contrast and a factor smaller than 1.0
to decrease contrast. In this method, when a pixel value exceeds 255
(in any channel), a rounding (saturate cast) has to be done.
Then, in the tbContrastCallB
example, we show the same functionality, but using a trackbarcallback
function that is called every time the slider is moved. Note that the events are handled when the waitKey
function is called. The application ends if you press any key. The code is as follows:
//… (omitted for brevity) #define IN_WIN "Orig. image" #define OUT_WIN "Image converted...(no saved)" Mat in_img, out_img; // CallBack function for contrast TrackBar void updateContrast(int TBvalContrast, void *userData=0) { in_img.convertTo(out_img, -1, TBvalContrast/50.0); imshow(OUT_WIN, out_img); return; } int main(int argc, char* argv[]) { int TBvalContrast=50; // Value of the TrackBar // (omitted for simplicity) in_img = imread(argv[1]); // Open and read the image // (omitted for simplicity) in_img.copyTo(out_img); // Copy orig. image to final img namedWindow(IN_WIN); // Creates window for orig. image moveWindow(IN_WIN, 0, 0); // Move window to pos. (0, 0) imshow(IN_WIN, in_img); // Shows original image namedWindow(OUT_WIN); // Creates window for converted image createTrackbar("Contrast", OUT_WIN, &TBvalContrast, 100, updateContrast); imshow(OUT_WIN, out_img); // Shows converted image cout << "Press any key to exit..." << endl; waitKey(); return 0; }
In this example, a void
pointer to the updatedContrast
function is passed as argument to the createTrackbar
function:
createTrackbar("Contrast", OUT_WIN, &TBvalContrast, 100, updateContrast);
The callback function gets as its first argument the value of the slider in the trackbar and a void
pointer to other user data. The new pixels values for the image will be calculated in this function.
Using a callback function cause a few changes in this new code because the accessible data inside this function has to be defined with global scope. Then, more complexity is avoided on the datatypes passed to the callback function as follows:
- Windows names are defined symbols (for example,
#define IN_WIN
). In the previous example (tbContrast
), the window names are stored in local variables (strings). - In this case, the
Mat
variables for the original (in_img
) and converted (out_img
) images are declared as global variables.
The two different implementations shown in the previous example produce the same results. However, it should be noted that after using a callback function, the resulting application (tbContrastCallB
) is more efficient because the math operations for the image conversion only take place at the change of the trackbar slide (when the callback is executed). In the first version (tbContrast
), the convertTo
function is called inside the while
loop even if the TBvalContrast
variable doesn't change.