In this article we outline how to use the DUOLib with Qt 5. We initialize the DUO device and display the resulting captured frames in a standard Qt QMainWindow and QWidget classes. We use the OpenCV Mat class as a helper to convert the color space and display the images frames using QImage by implementing the paintEvent event.
With the DUO SDK we provide an example project to compile an application for the usage of DUO with OpenCV and Qt. This project can be found in your user directory /user/DUO3D/Developers/Samples/Qt or DUO_SDK/Developers/Samples/Qt.
DUOLib.h - DUOLib API include file.globals.h - Helper functions for console output and debugging.main.cpp - Boilerplate code for initializing the MainWindow class.mainwindow.cpp - Application main window class implementation.mainwindow.h - Application main window class declaration. Sample.pro - Sample QMake project file.Lets begin by reviewing the header class which contains the logic to display the images; ImageObject class which extends QWidget. Also note the MainWindow class which extends QMainWindow and is used for the base of the application.
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include#include "DUOLib.h" #include using namespace cv; class ImageOutput : public QWidget { Q_OBJECT public: ImageOutput() { setMinimumSize(1, 1); _image = QImage(QSize(1,1), QImage::Format_RGB888); _image.fill(Qt::black); } public Q_SLOTS: // Mat imag must be BGR image void setImage(const Mat3b &image) { QMutexLocker lock(&_mutex); // Lock to assure access _image = QImage(image.data, image.cols, image.rows, QImage::Format_RGB888); update(); } private: void paintEvent(QPaintEvent *event) { QMutexLocker lock(&_mutex); QPainter painter(this); painter.setRenderHint(QPainter::SmoothPixmapTransform, true); painter.drawPixmap(event->rect(), QPixmap::fromImage(_image)); } private: QImage _image; QMutex _mutex; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); void closeEvent(QCloseEvent *); private: static void CALLBACK newFrameCb(const PDUOFrame pFrameData, void *pUserData) { ((MainWindow *)pUserData)->onNewFrame(pFrameData); } void onNewFrame(const PDUOFrame pFrameData); private: DUOInstance _duo; ImageOutput *_img[2]; Mat _leftRGB, _rightRGB; }; #endif // MAINWINDOW_H
Moving into the implementation where we initialize the DUO device and in the onNewFrame callback we convert the grayscale image into color image suitable for the display and then emit an event which calls the setImage method declared in our header.
mainwindow.cpp
#include "globals.h"
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent),
_duo(NULL)
{
resize(320*2, 240);
setWindowTitle("DUO Test");
setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, size(),
qApp->desktop()->availableGeometry()));
QSplitter *hs = new QSplitter();
hs->addWidget(_img[0] = new ImageOutput());
hs->addWidget(_img[1] = new ImageOutput());
setCentralWidget(hs);
DUOResolutionInfo ri;
if(EnumerateDUOResolutions(&ri, 1, 320, 240, DUO_BIN_HORIZONTAL2 + DUO_BIN_VERTICAL2, 60))
{
Print("[%dx%d], [%f-%f], %f, [%d]", ri.width, ri.height, ri.minFps, ri.maxFps, ri.fps, ri.binning);
if(OpenDUO(&_duo))
{
char buf[256];
GetDUOSerialNumber(_duo, buf); Print("Serial Number: %s", buf);
GetDUOFirmwareVersion(_duo, buf); Print("Firmware Version: v%s", buf);
GetDUOFirmwareBuild(_duo, buf); Print("Firmware Build Time: %s", buf);
Print("Library Version: v%s", GetLibVersion());
Print("-------------------------------------------------");
SetDUOResolutionInfo(_duo, ri);
uint32_t w, h;
GetDUOFrameDimension(_duo, &w, &h); Print("Frame Dimension: [%d, %d]", w, h);
StartDUO(_duo, newFrameCb, this);
SetDUOLedPWM(_duo, 30);
SetDUOGain(_duo, 0);
SetDUOExposure(_duo, 50);
SetDUOVFlip(_duo, true);
}
}
}
MainWindow::~MainWindow()
{
if(_duo) CloseDUO(_duo);
}
void MainWindow::closeEvent(QCloseEvent *)
{
if(_duo) StopDUO(_duo);
}
void MainWindow::onNewFrame(const PDUOFrame pDFrame)
{
Mat left(Size(pDFrame->width, pDFrame->height), CV_8UC1, pDFrame->leftData);
Mat right(Size(pDFrame->width, pDFrame->height), CV_8UC1, pDFrame->rightData);
cvtColor(left, _leftRGB, COLOR_GRAY2BGR);
cvtColor(right, _rightRGB, COLOR_GRAY2BGR);
Q_EMIT _img[0]->setImage(_leftRGB);
Q_EMIT _img[1]->setImage(_rightRGB);
}
Brining it all together, we use the following QMake project to properly link against the DUOLib and OpenCV. This project file is provided for Windows but with a few small changes it could be adjusted to target OSX or Linux.
Sample.pro
TARGET = Sample-01-Display
TEMPLATE = app
QT += core gui widgets
CONFIG += console c++11 warn_off
HEADERS += mainwindow.h
SOURCES += main.cpp mainwindow.cpp
INCLUDEPATH += $$PWD/../../../SDK/include C:/Dev/OpenCV/3.1.0/include
DEPENDPATH += $$PWD/../../../SDK/include C:/Dev/OpenCV/3.1.0/include
equals(QMAKE_HOST.os, Windows) {
!contains(QT_ARCH, x86_64) {
DESTDIR = $$PWD/../../bin/x86
LIBS += -L$$PWD/../../../SDK/windows/x86 -LC:/Dev/OpenCV/3.1.0/x86/vc12/staticlib
} else {
DESTDIR = $$PWD/../../bin/x64
LIBS += -L$$PWD/../../../SDK/windows/x64 -LC:/Dev/OpenCV/3.1.0/x64/vc12/staticlib
}
LIBS += -lDUOLib -lopencv_core310 -lopencv_imgproc310 -lippicvmt -lzlib
}
equals(QMAKE_HOST.os, Linux) {
contains(QT_ARCH, x86_64) {
DESTDIR = $$PWD/../../bin/x64
LIBS += -L$$PWD/../../../SDK/linux/x64
} else:contains(QT_ARCH, x86) {
DESTDIR = $$PWD/../../bin/x86
LIBS += -L$$PWD/../../../SDK/linux/x86
} else:contains(QT_ARCH, arm) {
DESTDIR = $$PWD/../../bin/arm
LIBS += -L$$PWD/../../../SDK/linux/arm
}
LIBS += -lDUO -lopencv_core -lopencv_imgproc
}
With this example we aim to showcase a reliable method for capturing and displaying DUO image frame data using OpenCV as a helper. We provide a standard Qt ".pro" project which allows for easy compilation with the latest Qt development tools.