OpenCV Essentials
上QQ阅读APP看书,第一时间看更新

Using Qt-based functions

While highgui will be sufficient for most purposes, the Qt UI framework (available at http://qt-project.org/) can be leveraged in OpenCV to develop richer user interfaces. A number of OpenCV's user interface functions use the Qt library behind the scenes. In order to use these functions, OpenCV must have been compiled with the WITH_QT option.

Note that Qt is a class and widget library that allows the creation of full-fledged applications with rich, event-driven user interfaces. In this section, however, we will mainly focus on specific Qt-based functions within OpenCV. Programming with Qt is out of the scope of this book.

With Qt support on, windows created with the namedWindow function will automatically look like what is shown in the following screenshot. There is a toolbar with useful functions such as pan, zoom, and save image. Windows also display a status bar at the bottom with the current mouse location and RGB value under that pixel. Right-clicking on the image will display a pop-up menu with the same toolbar options.

Using Qt-based functions

Window displayed with Qt support enabled

Text overlays and status bar

Text can be displayed on a line across the top of the image. This is very useful to show frames per second, number of detections, filenames, and so on. The main function is displayOverlay(const string& winname, const string& text, int delayms=0). The function expects a window identifier and the text to display. Multiple lines are allowed by using the \n character in the text string. The text will be displayed in the center and has a fixed size. The delayms parameter allows to display the text only for a specified amount of milliseconds (0=forever).

We can also display user text in the status bar. This text will replace the default x and y coordinates and RGB value under the current pixel. The displayStatusBar(const string& winname, const string& text, int delayms=0) function has the same parameters as the previous displayOverlay function. When the delay has passed, the default status bar text will be displayed.

The properties dialog

One of the most useful features of OpenCV's Qt-based functions is the properties dialog window. This window can be used to place trackbars and buttons. Again, this comes in handy while tuning parameters for our application. The properties dialog window can be accessed by pressing the last button in the toolbar (as shown in the preceding screenshot) or by pressing Ctrl + P. The window will only be accessible if trackbars or button have been assigned to it. To create a trackbar for the properties dialog, simply use the createTrackbar function passing an empty string (not NULL) as the window name.

Buttons can also be added to the properties dialog. Since both the original window and the dialog windows can be visible at the same time, this can be useful to activate/deactivate features in our application and see the results immediately. To add buttons to the dialog, use the createButton(const string& button_name, ButtonCallback on_change, void* userdata=NULL,inttype=CV_PUSH_BUTTON, bool initial_button_state=0) function. The first parameter is the button label (that is, the text to be displayed in the button). Every time the button changes its state, the on_change callback function will be called. This should be in the form void on_change(intstate, void *userdata). The userdata pointer passed to createButton will be passed to this callback function every time it is called. The state parameter signals the button change and it will have a different value for each type of button, given by parameter types:

  • CV_PUSH_BUTTON: Push button
  • CV_CHECKBOX: Checkbox button; the state will be either 1 or 0
  • CV_RADIOBOX: Radiobox button; the state will be either 1 or 0

For the first two types, the callback is called once on each press. For the radiobox button, it is called both for the button just clicked and for the button that goes unclicked.

Buttons are organized into button bars. Button bars occupy one row in the dialog window. Each new button is added to the right of the last one. Trackbars take up an entire row, so button bars are terminated when a trackbar is added. The following propertyDlgButtons example shows how buttons and trackbars are laid out in the properties dialog:

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace std;
using namespace cv;

Mat image;
const char win[]="Flip image";

void on_flipV(int state, void *p)
{
    flip(image, image, 0);  // flip vertical
    imshow(win, image);
}

void on_flipH(int state, void *p)
{
    flip(image, image, 1);  // flip horizontal
    imshow(win, image);
}

void on_negative(int state, void *p)
{
    bitwise_not(image, image);  // invert all channels
    imshow(win, image);
}

int main(int argc, char *argv[])
{
    if (argc != 2) {//Check args.
        cout << "Usage: <cmd><file_in>\n";
        return -1;
    }
    image = imread(argv[1]);
    if (image.empty()) {
        cout << "Error! Input image cannot be read...\n";
        return -1;
    }

    namedWindow(win);
    imshow(win, image);
    displayOverlay(win, argv[1], 0);
    createButton("Flip Vertical", on_flipV, NULL, CV_PUSH_BUTTON);
    createButton("Flip Horizontal", on_flipH, NULL, CV_PUSH_BUTTON);
    int v=0;
    createTrackbar("trackbar1", "", &v, 255);
    createButton("Negative", on_negative, NULL, CV_CHECKBOX);

    cout << "Press any key to exit...\n";
    waitKey();
    return 0;
}

This code is similar to the flipImage example in the previous chapter. In this example, an image filename is passed as an argument. A properties window is created with two buttons for vertical and horizontal flipping, a dummy trackbar, and a checkbox button to invert color intensities. The callback functions on_flipV and on_flipH simply flip the current image and show the result (we use a global image variable for this), while the callback function on_negative logically inverts color intensities and shows the result. Note that the trackbar is not really being used; it is used to show the line feed effect. The following screenshot shows the result:

The properties dialog

The propertyDlgButtons example

Windows properties

As mentioned previously, by default, all new windows will look like what's shown in the screenshot in the Using Qt-based functions section. Still, we can display windows in the non-Qt format by passing the CV_GUI_NORMAL option to namedWindow. On the other hand, window size parameters can be retrieved and set using the double getWindowProperty(const string& winname, int prop_id) and setWindowProperty (const string& winname, int prop_id,double prop_value) functions. The following table shows the properties that can be changed:

More importantly, window properties can be saved. This includes not only size and location, but also flags, trackbar values, zoom, and panning location. To save and load window properties, use the saveWindowParameters(const string& windowName) and loadWindowParameters(const string& windowName) functions.

Qt images

If we want to use the Qt libraries extensively in our project (that is, beyond OpenCV's Qt-based functions), we have to find a way to convert OpenCV's images to the format used by Qt (QImage). This can be done by using the following function:

QImage* Mat2Qt(const Mat &image)
{
Mat temp=image.clone();
cvtColor(image, temp, CV_BGR2RGB);
QImage *imgQt= new QImage((const unsigned char*)(temp.data),temp.cols,temp.rows,QImage::Format_RGB888);
return imgQt;
}

This function creates a Qt image using OpenCV's image data. Note that a conversion is first necessary, since Qt uses RGB images while OpenCV uses BGR order.

Finally, to display the image with Qt, we have at least two options:

  • Create a class that extends the QWidget class and implements paint events.
  • Create a label and set it to draw an image (using the setPixMap method).