Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Qt 5 and OpenCV 4 Computer Vision Projects
Qt 5 and OpenCV 4 Computer Vision Projects

Qt 5 and OpenCV 4 Computer Vision Projects: Get up to speed with cross-platform computer vision app development by building seven practical projects

eBook
€8.99 €26.99
Paperback
€32.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Qt 5 and OpenCV 4 Computer Vision Projects

Building an Image Viewer

Computer vision is the technology that enables computers to achieve a high-level understanding of digital images and videos, rather than only treating them as bytes or pixels. It is widely used for scene reconstruction, event detection, video tracking, object recognition, 3D pose estimation, motion estimation, and image restoration.

OpenCV (open source computer vision) is a library that implements almost all computer vision methods and algorithms. Qt is a cross-platform application framework and widget toolkit for creating applications with graphical user interfaces that can run on all major desktop platforms, most embedded platforms, and even mobile platforms.

These two powerful libraries are used together by many developers to create professional software with a solid GUI in industries that benefit from computer vision technology. In this book, we will demonstrate how to build these types of functional application with Qt 5 and OpenCV 4, which has friendly graphical user interfaces and several functions associated with computer vision technology.

In this first chapter, we will start by building a simple GUI application for image viewing with Qt 5.

The following topics will be covered in this chapter as follows:

  • Designing the user interface
  • Reading and displaying images with Qt
  • Zooming in and out of images
  • Saving a copy of images in any supported format
  • Responding to hotkeys in a Qt application

Technical requirements

Ensure that you at least have Qt version 5 installed and have some basic knowledge of C++ and Qt programming. A compatible C++ compiler is also required, that is, GCC 5 or later on Linux, Clang 7.0 or later on macOS, and MSVC 2015 or later on Microsoft Windows.

Since some pertinent basic knowledge is required as a prerequisite, the Qt installation and compiler environment setup are not included in this book. There are many books, online documents, or tutorials available (for example, GUI Programming with C++ and Qt5, by Lee Zhi Eng, as well as the official Qt library documentation) to help teach these basic configuration processes step by step; users can refer to these by themselves if necessary.

With all of these prerequisites in place, let's start the development of our first application—the simple image viewer.

All the code for this chapter can be found in our code repository at https://github.com/PacktPublishing/Qt-5-and-OpenCV-4-Computer-Vision-Projects/tree/master/Chapter-01.

Check out the following video to see the code in action: http://bit.ly/2KoYWFx

Designing the user interface

The first part of building an application is to define what the application will do. In this chapter, we will develop an image viewer app. The features it should have are as follows:

  • Open an image from our hard disk
  • Zoom in/out
  • View the previous or next image within the same folder
  • Save a copy of the current image as another file (with a different path or filename) in another format

There are many image viewer applications that we can follow, such as gThumb on Linux and Preview app on macOS. However, our application will be simpler than those in that we have undertaken some preplanning. This involved the use of Pencil to draw the wireframe of the application prototype.

Pencil is a functional prototyping tool. With it, you can create mockups easily. It is open-source and platform-independent software. The latest version of Pencil is now an Electron-based application. It runs well on Windows, Linux, and macOS. You can download it freely from https://pencil.evolus.vn/.

The following is a wireframe showing our application prototype:

As you can see in the preceding diagram, we have four areas in the main window: the MenuBar, the ToolBar, the Main Area, and the Status Bar.

The menu bar has two menu options on it—the File and View menus. Each menu will have its own set of actions. The File menu consists of the following three actions as follows:

  • Open: This option opens an image from the hard disk.
  • Save as: This option saves a copy of the current image as another file (with a different path or filename) in any supported format.
  • Exit: This option exits the application.

The View menu consists of four actions as follows:

  • Zoom in: This option zooms in to the image.
  • Zoom out: This option zooms out of the image.
  • Prev: This option opens the previous image in the current folder.
  • Next: This option opens the next image in the current folder.

The toolbar consists of several buttons that can also be found in the menu options. We place them on the toolbar to give the users shortcuts to trigger these actions. So, it is necessary to include all frequently used actions, including the following:

  • Open
  • Zoom in
  • Zoom out
  • Previous image
  • Next image

The main area is used to show the image that is opened by the application.

The status bar is used to show some information pertaining to the image that we are viewing, such as its path, dimensions, and its size in bytes.

You can find the source file for this design in our code repository on GitHub: https://github.com/PacktPublishing/Qt-5-and-OpenCV-4-Computer-Vision-Projects. The file merely resides in the root directory of the repository, named WireFrames.epgz. Don't forget that it should be opened using the Pencil application.

Starting the project from scratch

In this section, we will build the image viewer application from scratch. No assumptions are made as to what integrated development environment (IDE) or editor you are using. We will just focus on the code itself and how to build the application using qmake in a Terminal.

First, let's create a new directory for our project, named ImageViewer. I use Linux and execute this in a Terminal, as follows:

$ pwd
/home/kdr2/Work/Books/Qt5-And-OpenCV4-Computer-Vision-Projects/Chapter-01
$ mkdir ImageViewer
$

Then, we create a C++ source file named main.cpp in that directory with the following content:

    #include <QApplication>
#include <QMainWindow>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
window.setWindowTitle("ImageViewer");
window.show();
return app.exec();
}

This file will be the gateway to our application. In this file, we first include dedicated header files for a GUI-based Qt application provided by the Qt library. Then, we define the main function, as most C++ applications do. In the main function, we define an instance of the QApplication class, which represents our image viewer application while it is running, and an instance of QMainWindow, which will be the main UI window, and which we designed in the preceding section. After creating the QMainWindow instance, we call some methods of it: setWindowTitle to set the title of the window and show to let the window emerge. Finally, we call the exec method of the application instance to enter the main event loop of the Qt application. This will make the application wait until exit() is called, and then return the value that was set to exit().

Once the main.cpp file is saved in our project directory, we enter the directory in the Terminal and run qmake -project to generate the Qt project file, as follows:

    $ cd ImageViewer/
$ ls
main.cpp
$ qmake -project
$ ls
ImageViewer.pro main.cpp
$

As you can see, a file named ImageViewer.pro is generated. This file contains
many directives and configurations of the Qt project and qmake will use this
ImageViewer.pro file to generate a makefile later. Let's examine that project file. Its content is listed in the following snippet after we omit all the comment lines that start with #, as follows:

    TEMPLATE = app
TARGET = ImageViewer
INCLUDEPATH += .

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp

Let's go through this line by line.

The first line, TEMPLATE = app, specifies app as the template to use when generating the project. Many other values are allowed here, for example, lib and subdirs. We are building an application that can be run directly, so the value app is the proper one for us. Using other values are beyond the scope of this chapter; you can refer to the qmake manual at http://doc.qt.io/qt-5/qmake-manual.html yourself to explore them.

The second line, TARGET = ImageViewer, specifies the name of the executable for the application. So, we will get an executable file named ImageViewer once the project is built.

The remaining lines define several options for the compiler, such as the include path, macro definitions, and input source files. You can easily ascertain which line does what based on the variable names in these lines.

Now, let's build the project, run qmake -makefile to generate the makefile, and then run make to build the project, that is, compile the source to our target executable:

    $ qmake -makefile
$ ls
ImageViewer.pro main.cpp Makefile
$ make
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I. -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -isystem /usr/include/libdrm -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++
-o main.o main.cpp
main.cpp:1:10: fatal error: QApplication: No such file or directory
#include <QApplication>
^~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:395: main.o] Error 1
$

Oops! We get a big error. This is because, with effect from Qt version 5, all the native GUI features have been moved from the core module to a separate module, the widgets module. We should tell qmake that our application depends on that module by adding the line greaterThan(QT_MAJOR_VERSION, 4): QT += widgets to the project file. Following this modification, the content of ImageViewer.pro appears as follows:

    TEMPLATE = app
TARGET = ImageViewer
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

INCLUDEPATH += .

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp

Now, let's build the application again by issuing the qmake -makefile and make commands in the Terminal as follows:

    $ qmake -makefile
$ make
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -isystem /usr/include/libdrm -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o main.o main.cpp
g++ -Wl,-O1 -o ImageViewer main.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
$ ls
ImageViewer ImageViewer.pro main.cpp main.o Makefile
$

Hooray! We finally get the executable file, ImageViewer, in the project directory. Now, let's execute it and see what the window looks like:

As we can see, it's just a blank window. We will implement the full user interface as per our designed wireframe in the next section, Setting up the full user interface.

Although we didn't mention any IDE or editor and built the application in a Terminal with qmake, you can use any IDE with which you are familiar, for instance, Qt Creator. Especially on Windows, the terminal (cmd or MinGW) does not perform as well as Terminals on Linux and macOS, so please feel free to use an IDE.

Setting up the full user interface

Let's proceed with the development. In the preceding section, we built a blank window and now we are going to add the menu bar, toolbar, image display component, and the status bar to the window.

First, instead of using the QMainWindow class, we will define a class ourselves, named MainWindow, which extends the QMainWindow class. Let's see its declaration in mainwindow.h:

    class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();

private:
void initUI();

private:
QMenu *fileMenu;
QMenu *viewMenu;

QToolBar *fileToolBar;
QToolBar *viewToolBar;

QGraphicsScene *imageScene;
QGraphicsView *imageView;

QStatusBar *mainStatusBar;
QLabel *mainStatusLabel;
};

Everything is straightforward. Q_OBJECT is a crucial macro provided by the Qt library. If we want to declare a class that has customized signals and slots of its own, or that uses any other facility from the Qt meta-object system, we must incorporate this crucial macro in our class declaration, or, more precisely, in the private section of our class, like we just did. The initUI method initializes all widgets that are declared in the private section. The imageScene and imageView widgets will be placed in the main area of the window to display images. Other widgets are self-explanatory from their type and name, so I will not say too much about them in order to keep the chapter concise.

To keep the chapter concise, I have not included each source file in the text in its entirety when I introduce it. For example, most of the time, the #include ... directions at the beginning of the files are omitted. You can refer to the source file in the code repository on GitHub to check the details if needed.

Another key aspect is the implementation of the initUI method in mainwindow.cpp as follows:

    void MainWindow::initUI()
{
this->resize(800, 600);
// setup menubar
fileMenu = menuBar()->addMenu("&File");
viewMenu = menuBar()->addMenu("&View");

// setup toolbar
fileToolBar = addToolBar("File");
viewToolBar = addToolBar("View");

// main area for image display
imageScene = new QGraphicsScene(this);
imageView = new QGraphicsView(imageScene);
setCentralWidget(imageView);

// setup status bar
mainStatusBar = statusBar();
mainStatusLabel = new QLabel(mainStatusBar);
mainStatusBar->addPermanentWidget(mainStatusLabel);
mainStatusLabel->setText("Image Information will be here!");
}

As you can see, at this stage, we don't create every item and button for the menu and toolbar; we just set up the main skeleton. In the preceding code, the imageScene variable is a QGraphicsSence instance. Such an instance is a container for 2D graphical items. According to its design, it only manages graphics items but doesn't have a visual appearance. In order to visualize it, we should create an instance of the QGraphicsView class with it, which is why the imageView variable is there. In our application, we use these two classes to display images.

After implementing all the methods of the MainWindow class, it's time to compile the sources. Before doing this, a number of changes need to be made to the ImageViewer.pro project file, as follows:

  1. We just write a new source file, and it should be known by qmake:
     # in ImageViewer.pro
SOURCES += main.cpp mainwindow.cpp
  1. The header file, mainwindow.h, has a special macro, Q_OBJECT, which indicates that it has something that cannot be dealt with by a standard C++ preprocessor. That header file should be correctly handled by a Qt-provided preprocessor named moc, the Meta-Object Compiler, to generate a C++ source file that contains some code relating to the Qt meta-object system. So, we should tell qmake to check this header file by adding the following line to ImageViewer.pro:
     HEADERS += mainwindow.h

OK. Now that all of that is complete, let's run qmake -makefile and make again, and then run the new executable. You should see the following window:

Well, so far so good. Now, let's go on to add the items that should appear in the menus as we intended. In Qt, each item in a menu is represented by an instance of QAction. Here, we take the action, which is to open a new image as an example. First, we declare a pointer to a QAction instance as a private member of our MainWindow class:

    QAction *openAction;

Then, in the body of the initUI method, we create the action as a child widget of the main window by calling the new operator, and add it to the File menu as follows:

    openAction = new QAction("&Open", this);
fileMenu->addAction(openAction);
You may notice that we create many Qt objects by calling the new operator, but never delete them. That is fine because all these objects are instances of QObject, or a subclass of it. Instances of QObject are organized in one or many object trees in the Qt library. When a QObject is created as the child of another object, the object will be added to its parent's children() list automatically. The parent object will take ownership of the child object. And, when the parent object is disposed of, its children will be deleted in its destructor automatically. In our application, we create most instances of QObject as children of the main window object, so we don't need to delete them.

Fortunately, buttons on the toolbar can also be represented by QAction, so we can add openAction directly to the file toolbar:

    fileToolBar->addAction(openAction);

As mentioned previously, we have seven actions to create: open, save as, exit, zoom in, zoom out, previous image, and next image. All of them can be added in the same way as we added the open action. Also, given that many lines of code are required to add these actions, we can do a little refactoring of the code—create a new private method named createActions, insert all the code of the action into that method, and then call it in initUI.

All actions are now created in a separate method, createActions, after the refactoring. Let's compile the sources and see what the window looks like now:

Great! The window looks just like the wireframe we designed, and we can now expand the menu by clicking on the items on the menu bar!

Implementing the functions for the actions

In the previous section, we added several actions to the menu and toolbar. However, if we click on these actions, nothing happens. That's because we have not written any handler for them yet. Qt uses a signal and slot connection mechanism to establish the relationship between events and their handlers. When users perform an operation on a widget, a signal of that widget will be emitted. Then, Qt will ascertain whether there is any slot connected with that signal. The slot will be called if it is found. In this section, we will create slots for the actions we have created in the preceding sections and make connections between the signals of the actions to these slots respectively. Also, we will set up some hotkeys for frequently used actions.

The Exit action

Take Exit action as an example. If users click it from the File menu, a signal named triggered will be emitted. So, let's connect this signal to a slot of our application instance in the MainWindow class's member function, createActions:

     connect(exitAction, SIGNAL(triggered(bool)), QApplication::instance(), SLOT(quit()));

The connect method takes four parameters: the signal sender, the signal, the receiver, and the slot. Once the connection is made, the slot on the receiver will be called as soon as the signal of the sender is emitted. Here, we connect the triggered signal of the Exit action with the quit slot of the application instance to enable the application to exit when we click on the Exit action.

Now, to compile and run, click the Exit item from the File menu. The application will exit as we expect if everything goes well.

Opening an image

The quit slot of QApplication is provided by Qt, but if we want to open an image when clicking on the open action, which slot should we use? In this scenario, there's no slot built-in for this kind of customized task. We should write a slot on our own.

To write a slot, first we should declare a function in the body of the class, MainWindow, and place it in a slots section. As this function is not used by other classes, we put it in a private slots section, as follows:

     private slots:
void openImage();

Then, we give this slot (also a member function) a simple definition for testing:

     void MainWindow::openImage()
{
qDebug() << "slot openImage is called.";
}

Now, we connect the triggered signal of the open action to the openImage slot of the main window in the body of the createActions method:

     connect(openAction, SIGNAL(triggered(bool)), this, SLOT(openImage()));

Now, let's compile and run it again. Click the Open item from the File menu, or the Open button on the toolbar, and the slot openImage is called. message will be printed in the Terminal.

We now have a testing slot that works well with the open action. Let's change its body, as shown in the following code, to implement the function of opening an image from disk:

         QFileDialog dialog(this);
dialog.setWindowTitle("Open Image");
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter(tr("Images (*.png *.bmp *.jpg)"));
QStringList filePaths;
if (dialog.exec()) {
filePaths = dialog.selectedFiles();
showImage(filePaths.at(0));
}

Let's go through this code block line by line. In the first line, we create an instance of QFileDialog, whose name is dialog. Then, we set many properties of the dialog. This dialog is used to select an image file locally from the disk, so we set its title as Open Image, and set its file mode to QFileDialog::ExistingFile to make sure that it can only select one existing file, rather than many files or a file that doesn't exist. The name filter Images (*.png *.bmp *.jpg) ensures that only files with the extension mentioned (that is, .png, .bmp, and .jpg) can be selected. After these settings, we call the exec method of dialog to open it. This appears as follows:

If the user selects a file and clicks the Open button, a non-zero value will be returned by dialog.exec. Then, we call dialog.selectedFiles to get the path of the files that are selected as an instance of QStringList. Here, only one selection is allowed; hence, there's only one element in the resulting list: the path of the image that we want to open. So, we call the showImage method of our MainWindow class with the only element to display the image. If the user clicks the Cancel button, a zero value will be returned by the exec method, and we can just ignore that branch because that means the user has given up on opening an image.

The showImage method is another private member function we just added to the MainWindow class. It is implemented as follows:

     void MainWindow::showImage(QString path)
{
imageScene->clear();
imageView->resetMatrix();
QPixmap image(path);
imageScene->addPixmap(image);
imageScene->update();
imageView->setSceneRect(image.rect());
QString status = QString("%1, %2x%3, %4 Bytes").arg(path).arg(image.width())
.arg(image.height()).arg(QFile(path).size());
mainStatusLabel->setText(status);
}

In the process of displaying the image, we add the image to imageScene and then update the scene. Afterward, the scene is visualized by imageView. Given the possibility that there is already an image opened by our application when we open and display another one, we should remove the old image, and reset any transformation (for example, scaling or rotating) of the view before showing the new one. This work is done in the first two lines. After this, we construct a new instance of QPixmap with the file path we selected, and then we add it to the scene and update the scene. Next, we call setSceneRect on imageView to tell it the new extent of the scene—it is the same size as the image.

At this point, we have shown the target image in its original size in the center of the main area. The last thing to do is display the information pertaining to the image on the status bar. We construct a string containing its path, dimensions, and size in bytes, and then set it as the text of mainStatusLabel, which had been added to the status bar.

Let's see how this image appears when it's opened:

Not bad! The application now looks like a genuine image viewer, so let's go on to implement all of its intended features.

Zooming in and out

OK. We have successfully displayed the image. Now, let's scale it. Here, we take zooming in as an example. With the experience from the preceding actions, we should have a clear idea as to how to do that. First, we declare a private slot, which is named zoomIn, and give its implementation as shown in the following code:

     void MainWindow::zoomIn()
{
imageView->scale(1.2, 1.2);
}

Easy, right? Just call the scale method of imageView with a scale rate for the width and a scale rate for the height. Then, we connect the triggered signal of zoomInAction to this slot in the createActions method of the MainWindow class:

     connect(zoomInAction, SIGNAL(triggered(bool)), this, SLOT(zoomIn()));

Compile and run the application, open an image with it, and click on the Zoom in button on the toolbar. You will find that the image enlarges to 120% of its current size on each click.

Zooming out just entails scaling the imageView with a rate of less than 1.0. Please try to implement it by yourself. If you find it difficult, you can refer to our code repository on GitHub (https://github.com/PacktPublishing/Qt-5-and-OpenCV-4-Computer-Vision-Projects/tree/master/Chapter-01).

With our application, we can now open an image and scale it for viewing. Next, we will implement the function of the saveAsAction action.

Saving a copy

Let's look back at the showImage method of MainWindow. In that method, we created an instance of QPixmap from the image and then added it to imageScene by calling imageScene->addPixmap. We didn't hold any handler of the image out of that function; hence, now we don't have a convenient way to get the QPixmap instance in the new slot, which we will implement for saveAsAction.

To solve this, we add a new private member field, QGraphicsPixmapItem *currentImage, to MainWindow to hold the return value of imageScene->addPixmap and initialize it with nullptr in the constructor of MainWindow. Then, we find the line of code in the body of MainWindow::showImage:

   imageScene->addPixmap(image);

To save the returned value, we replace this line with the following one:

   currentImage = imageScene->addPixmap(image);

Now, we are ready to create a new slot for saveAsAction. The declaration in the private slot section is straightforward, as follows:

       void saveAs();

The definition is also straightforward:

     void MainWindow::saveAs()
{
if (currentImage == nullptr) {
QMessageBox::information(this, "Information", "Nothing to save.");
return;
}
QFileDialog dialog(this);
dialog.setWindowTitle("Save Image As ...");
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setNameFilter(tr("Images (*.png *.bmp *.jpg)"));
QStringList fileNames;
if (dialog.exec()) {
fileNames = dialog.selectedFiles();
if(QRegExp(".+\\.(png|bmp|jpg)").exactMatch(fileNames.at(0))) {
currentImage->pixmap().save(fileNames.at(0));
} else {
QMessageBox::information(this, "Information", "Save error: bad format or filename.");
}
}
}

First, we check whether currentImage is nullptr. If true, it means we haven't opened any image yet. So, we open a QMessageBox to tell the user there's nothing to save. Otherwise, we create a QFileDialog, set the relevant properties for it, and open it by calling its exec method. If the user gives the dialog a filename and clicks the open button on it, we will get a list of file paths that have only one element in it as our last usage of QFileDialog. Then, we check whether the file path ends with the extensions we support using a regexp matching. If everything goes well, we get the QPixmap instance of the current image from currentImage->pixmap() and save it to the specified path. Once the slot is ready, we connect it to the signal in createActions:

   connect(saveAsAction, SIGNAL(triggered(bool)), this, SLOT(saveAs()));

To test this feature, we can open a PNG image and save it as a JPG image by giving a filename that ends with .jpg in the Save Image As... file dialog. Then, we open the new JPG image we just saved, using another image view application to check whether the image has been correctly saved.

Navigating in the folder

Now that we have completed all of the actions in relation to a single image, let's go further and navigate all the images that reside in the directory in which the current image resides, that is, prevAction and nextAction.

To know what constitutes the previous or next image, we should be aware of two things as follows:

  • Which is the current one
  • The order in which we count them

So, first we add a new member field, QString currentImagePath, to the MainWindow class to save the path of the current image. Then, we save the image's path while showing it in showImage by adding the following line to the method:

     currentImagePath = path;

Then, we decide to count the images in alphabetical order according to their names. With these two pieces of information, we can now determine which is the previous or next image. Let's see how we define the slot for prevAction:

     void MainWindow::prevImage()
{
QFileInfo current(currentImagePath);
QDir dir = current.absoluteDir();
QStringList nameFilters;
nameFilters << "*.png" << "*.bmp" << "*.jpg";
QStringList fileNames = dir.entryList(nameFilters, QDir::Files, QDir::Name);
int idx = fileNames.indexOf(QRegExp(QRegExp::escape(current.fileName())));
if(idx > 0) {
showImage(dir.absoluteFilePath(fileNames.at(idx - 1)));
} else {
QMessageBox::information(this, "Information", "Current image is the first one.");
}
}

First, we get the directory in which the current image resides as an instance of QDir, and then we list the directory with name filters to ensure that only PNG, BMP, and JPG files are returned. While listing the directory, we use QDir::Name as the third argument to make sure the returned list is sorted by filename in alphabetical order. Since the current image we are viewing is also in this directory, its filename must be in the filename list. We find its index by calling indexOf on the list with a regexp, which is generated by QRegExp::escape, so that it can exactly match its filename. If the index is zero, this means the current image is the first one in this directory. A message box pops up to give the user this information. Otherwise, we show the image whose filename is at the position of index - 1 to complete the operation.

Before you test whether prevAction works, don't forget to connect the signal and the slot by adding the following line to the body of the createActions method:

   connect(prevAction, SIGNAL(triggered(bool)), this, SLOT(prevImage()));

Well, it's not too hard, so attempt the work of nextAction yourself or just read the code for it in our code repository on GitHub.

Responding to hotkeys

At this point, almost all of the features are implemented as we intended. Now, let's add some hotkeys for frequently used actions to make our application much easier to use.

You may have noticed that, when we create the actions, we occasionally add a strange & to their text, such as &File and E&xit. Actually, this is a way of setting shortcuts in Qt. In certain Qt widgets, using & in front of a character will automatically create a mnemonic (a shortcut) for that character. Hence, in our application, if you press Alt + F, the File menu will be triggered, and while the File menu is expanded, we can see the Exit action on it. At this time, you press Alt + X, and the Exit action will be triggered to let the application exit.

Now, let's give the most frequently used actions some single key shortcuts to make using them more convenient and faster as follows:

  • Plus (+) or equal (=) for zooming in
  • Minus (-) or underscore (_) for zooming out
  • Up or left for the previous image
  • Down or right for the next image

To achieve this, we add a new private method named setupShortcuts in the MainWindow class and implement it as follows:

     void MainWindow::setupShortcuts()
{
QList<QKeySequence> shortcuts;
shortcuts << Qt::Key_Plus << Qt::Key_Equal;
zoomInAction->setShortcuts(shortcuts);

shortcuts.clear();
shortcuts << Qt::Key_Minus << Qt::Key_Underscore;
zoomOutAction->setShortcuts(shortcuts);

shortcuts.clear();
shortcuts << Qt::Key_Up << Qt::Key_Left;
prevAction->setShortcuts(shortcuts);

shortcuts.clear();
shortcuts << Qt::Key_Down << Qt::Key_Right;
nextAction->setShortcuts(shortcuts);
}

To support multiple shortcuts for one action, for example, + and = for zooming in, for each action we make an empty QList of QKeySequence, and then add each shortcut key sequence to the list. In Qt, QKeySequence encapsulates a key sequence as used by shortcuts. Because QKeySequence has a non-explicit constructor with int arguments, we can add Qt::Key values directly to the list and they will be converted to instances of QKeySequence implicitly. After the list is filled, we call the setShortcuts method on each action with the filled list, and this way setting shortcuts will be easier.

Add the setupShortcuts() method call at the end of the body of the createActions method, then compile and run; now you can test the shortcuts in your application and they should work well.

Summary

In this chapter, we used Qt to build a desktop application for image viewing, from scratch. We learned how to design the user interface, create a Qt project from scratch, build the user interface, open and display images, respond to hotkeys, and save a copy of images.

In the next chapter, we will add more actions to the application to allow the user to edit the image with the functions provided by OpenCV. Also, we will add these editing actions in a more flexible way by using the Qt plugin mechanism.

Questions

Try these questions to test your knowledge of this chapter:

  1. We use a message box to tell users that they are already viewing the first or last image while they are trying to see the previous one before the first image, or the next one after the last image. But there is another way to deal with this situation—disable prevAction when users are viewing the first image, and disable nextAction when users are viewing the last image. How is this implemented?
  2. Our menu items or tool buttons only contain text. How could we add an icon image to them?
  3. We use QGraphicsView.scale to zoom in or out of an image view, but how do you rotate an image view?
  4. What does moc do? What actions do the SIGNAL and SLOT macros perform?
Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Gain practical insights into code for all projects covered in this book
  • Understand modern computer vision concepts such as character recognition, image processing and modification
  • Learn to use a graphics processing unit (GPU) and its parallel processing power for filtering images quickly

Description

OpenCV and Qt have proven to be a winning combination for developing cross-platform computer vision applications. By leveraging their power, you can create robust applications with both an intuitive graphical user interface (GUI) and high-performance capabilities. This book will help you learn through a variety of real-world projects on image processing, face and text recognition, object detection, and high-performance computing. You’ll be able to progressively build on your skills by working on projects of increasing complexity. You’ll begin by creating an image viewer application, building a user interface from scratch by adding menus, performing actions based on key-presses, and applying other functions. As you progress, the book will guide you through using OpenCV image processing and modification functions to edit an image with filters and transformation features. In addition to this, you’ll explore the complex motion analysis and facial landmark detection algorithms, which you can use to build security and face detection applications. Finally, you’ll learn to use pretrained deep learning models in OpenCV and GPUs to filter images quickly. By the end of this book, you will have learned how to effectively develop full-fledged computer vision applications with OpenCV and Qt.

Who is this book for?

This book is for engineers and developers who are familiar with both Qt and OpenCV frameworks and are capable of creating simple projects using them, but want to build their skills to create professional-level projects using them. Familiarity with the C++ language is a must to follow the example source codes in this book.

What you will learn

  • Create an image viewer with all the basic requirements
  • Construct an image editor to filter or transform images
  • Develop a security app to detect movement and secure homes
  • Build an app to detect facial landmarks and apply masks to faces
  • Create an app to extract text from scanned documents and photos
  • Train and use cascade classifiers and DL models for object detection
  • Build an app to measure the distance between detected objects
  • Implement high-speed image filters on GPU with Open Graphics Library (OpenGL)
Estimated delivery fee Deliver to Bulgaria

Premium delivery 7 - 10 business days

€25.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jun 21, 2019
Length: 348 pages
Edition : 1st
Language : English
ISBN-13 : 9781789532586
Category :
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Bulgaria

Premium delivery 7 - 10 business days

€25.95
(Includes tracking information)

Product Details

Publication date : Jun 21, 2019
Length: 348 pages
Edition : 1st
Language : English
ISBN-13 : 9781789532586
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 102.97
Machine Learning for OpenCV 4
€36.99
OpenCV 4 Computer Vision Application Programming Cookbook
€32.99
Qt 5 and OpenCV 4 Computer Vision Projects
€32.99
Total 102.97 Stars icon
Banner background image

Table of Contents

10 Chapters
Building an Image Viewer Chevron down icon Chevron up icon
Editing Images Like a Pro Chevron down icon Chevron up icon
Home Security Applications Chevron down icon Chevron up icon
Fun with Faces Chevron down icon Chevron up icon
Optical Character Recognition Chevron down icon Chevron up icon
Object Detection in Real Time Chevron down icon Chevron up icon
Real-Time Car Detection and Distance Measurement Chevron down icon Chevron up icon
Using OpenGL for the High-Speed Filtering of Images Chevron down icon Chevron up icon
Assessments Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.5
(2 Ratings)
5 star 50%
4 star 50%
3 star 0%
2 star 0%
1 star 0%
Robert Feb 26, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
The chapters build on each other, the books author does anexcellent job of laying out the material. Each chapter tells youwhere you can get the needed code in order to follow the examples in the book.I am learning a lot from this book.Good Job !!!
Amazon Verified review Amazon
Anthony Love Oct 20, 2023
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Feefo Verified review Feefo
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela