Common Vision Blox 15.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Friends Modules Pages
Image Manager/Cvb++/QtDisplayAdvanced

This example program is located in your CVB installation under %CVB%Tutorial/Image Manager/Cvb++/QtDisplayAdvanced.

main.cpp:

// Example for advanced QT display.
#include <iostream>
#include <QApplication>
#include <cvb/image.hpp>
#include "main_widget.hpp"
int main(int argc, char* argv[])
{
QApplication application(argc, argv);
PTResultWidget ptResultWidget;
MainWidget mainWidget(&ptResultWidget);
mainWidget.setWindowIcon(QIcon(":/qttutorial.png"));
mainWidget.show();
application.exec();
}

main_widget.cpp:

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
#include "main_widget.hpp"
#include <cvb/image.hpp>
#include <cvb/utilities/system_info.hpp>
#include <cvb/ui/ui.hpp>
#include <cvb/ui/opengl_image_renderer_factory.hpp>
// performance test result window
PTResultWidget::PTResultWidget()
: QTableWidget()
{
setWindowIcon(QIcon(":/qttutorial.png"));
for (int i = 0; i < 7; i++)
insertColumn(0);
QStringList lables;
lables << "Image Size" << "View Size" << "Zoom" << "Format" << "Upload" << "Rendering" << "FPs";
setHorizontalHeaderLabels(lables);
auto* header = horizontalHeader();
header->setSectionResizeMode(QHeaderView::Stretch);
auto font = header->font();
font.setBold(true);
header->setFont(font);
resize(640, 480);
setWindowTitle("Performance Test Results");
}
// display result in the result window
void PTResultWidget::AddResult(const PTResult& result)
{
auto row = rowCount();
insertRow(row);
SetResultItem(row, 0, ImageSizeToString(result.ImageSize));
SetResultItem(row, 1, ViewSizeToString(result.ViewSize));
SetResultItem(row, 2, ZoomToString(result.Zoom));
SetResultItem(row, 3, PlanesToString(result.Planes));
SetResultItem(row, 4, UploadModeToString(result.UploadMode));
QString renderEngineToolTip;
if (result.RenderEngine == Cvb::UI::RenderEngine::Raster)
{
renderEngineToolTip = QString("Rendered with \"QPainter\"");
}
else
{
int glVersion = (result.RenderEngine == Cvb::UI::RenderEngine::OpenGL2) ? 2 : 3;
QString vendor = QString("Vendor: %1").arg(Cvb::UI::CvbToQt(Cvb::UI::OpenGLImageRendererFactory::VendorName(glVersion)));
QString renderer = QString("Renderer: %1").arg(Cvb::UI::CvbToQt(Cvb::UI::OpenGLImageRendererFactory::RendererName(glVersion)));
renderEngineToolTip = vendor + QString("\n") + renderer;
}
SetResultItem(row, 5, RenderEngineToString(result.RenderEngine), renderEngineToolTip);
SetResultItem(row, 6, FPsToString(result.FPS));
}
void PTResultWidget::SetResultItem(int row, int column, const QString & text, const QString & toolTip)
{
auto cell = new QTableWidgetItem(text);
cell->setTextAlignment(Qt::AlignCenter);
cell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
if (!toolTip.isEmpty())
cell->setToolTip(toolTip);
setItem(row, column, cell);
}
QString PTResultWidget::ImageSizeToString(Cvb::Size2D<int> size) const
{
return QString("%1 x ").arg(size.Width()) + QString("%1").arg(size.Height());
}
QString PTResultWidget::ViewSizeToString(QSize size) const
{
return QString("%1 x ").arg(size.width()) + QString("%1").arg(size.height());
}
QString PTResultWidget::ZoomToString(Cvb::UI::ZoomDescriptor zoomDescriptor) const
{
switch (zoomDescriptor.ID)
{
default:
case Cvb::UI::ZoomID::Invalid:
return "Invalid";
case Cvb::UI::ZoomID::Panorama:
return "Panorama";
case Cvb::UI::ZoomID::Factor1:
return "1 : 1";
case Cvb::UI::ZoomID::Factor2:
return "1 : 2";
case Cvb::UI::ZoomID::Factor4:
return "1 : 4";
case Cvb::UI::ZoomID::Factor8:
return "1 : 8";
case Cvb::UI::ZoomID::Factor16:
return "1 : 16";
case Cvb::UI::ZoomID::Factor32:
return "1 : 32";
case Cvb::UI::ZoomID::Factor64:
return "1 : 64";
case Cvb::UI::ZoomID::Factor128:
return "1 : 128";
}
}
QString PTResultWidget::PlanesToString(int planes) const
{
return (planes == 1) ? "Mono" : "Colour";
}
QString PTResultWidget::UploadModeToString(Cvb::UI::UploadMode uploadMode) const
{
return (uploadMode == Cvb::UI::UploadMode::Image) ? "Image" : "View";
}
QString PTResultWidget::RenderEngineToString(Cvb::UI::RenderEngine renderEngine) const
{
switch (renderEngine)
{
default:
return "Invalid";
case Cvb::UI::RenderEngine::Raster:
return "Raster";
case Cvb::UI::RenderEngine::OpenGL2:
return "OpenGL 2";
case Cvb::UI::RenderEngine::OpenGL3:
return "OpenGL 3";
}
}
QString PTResultWidget::FPsToString(double fps) const
{
return QString("%1").arg(fps, 3);
}
PTSetupWidget::PTSetupWidget(QWidget * parent, PTResultWidget * ptResultWidget)
: QWidget(parent)
, ptResultWidget_(ptResultWidget)
{
spMeasurementCount_ = new QSpinBox(this);
spRefreshCount_ = new QSpinBox(this);
auto pbHide = new QPushButton("Hide");
auto pbHideAndRunPT = new QPushButton("Hide & Run");
auto groupBox = new QGroupBox("Performance Test for Render Engine");
auto mainLayout = new QVBoxLayout;
auto spLayout = new QVBoxLayout;
auto pbLayout = new QHBoxLayout;
spLayout->addWidget(spMeasurementCount_);
spLayout->addWidget(spRefreshCount_);
pbLayout->addStretch();
pbLayout->addWidget(pbHide);
pbLayout->addWidget(pbHideAndRunPT);
pbLayout->addStretch();
mainLayout->addLayout(spLayout);
mainLayout->addLayout(pbLayout);
groupBox->setLayout(mainLayout);
auto gblayout = new QVBoxLayout;
gblayout->addWidget(groupBox);
setLayout(gblayout);
spMeasurementCount_->setPrefix("Measurement Count: ");
spMeasurementCount_->setRange(2, 10000);
spMeasurementCount_->setValue(measurementCount_);
spMeasurementCount_->setToolTip("Number of measurements used to get a result as mean.");
spRefreshCount_->setPrefix("Refresh Count: ");
spRefreshCount_->setRange(500, 1000000);
spRefreshCount_->setValue(refreshCount_);
spRefreshCount_->setToolTip("Number of display refreshes executed for a single measurement.");
connect(spMeasurementCount_, SIGNAL(valueChanged(int)), this, SLOT(HandleMeasurementCountChanged(int)));
connect(spRefreshCount_, SIGNAL(valueChanged(int)), this, SLOT(HandleRefreshCountChanged(int)));
connect(pbHide, SIGNAL(clicked()), this, SLOT(HandleHide()));
connect(pbHideAndRunPT, SIGNAL(clicked()), this, SLOT(HandleHideAndRunPT()));
}
void PTSetupWidget::HandleHide() noexcept
{
setVisible(false);
}
void PTSetupWidget::HandleHideAndRunPT() noexcept
{
HandleHide();
if (!ptResultWidget_->isVisible())
{
ptResultWidget_->move(QApplication::desktop()->screen()->rect().center());
ptResultWidget_->show();
}
RunPT();
}
void PTSetupWidget::HandleRefreshCountChanged(int value) noexcept
{
refreshCount_ = value;
}
void PTSetupWidget::HandleMeasurementCountChanged(int value) noexcept
{
measurementCount_ = value;
}
MainWidget::MainWidget(PTResultWidget * ptResultWidget)
: QWidget()
, ptResultWidget_(ptResultWidget)
{
imageView_ = new Cvb::UI::ImageView(this);
ptSetupWidget_ = new PTSetupWidget(this, ptResultWidget_);
auto mainLayout = new QVBoxLayout;
mainLayout->addWidget(imageView_);
mainLayout->addWidget(new QLabel(tr("Right click to get the context menu."), this));
mainLayout->addWidget(ptSetupWidget_);
setLayout(mainLayout);
Cvb::ImagePtr image = Cvb::Image::Load(Cvb::ExpandPath(Cvb::InstallPath() + CVB_LIT("tutorial/ClassicSwitch001.bmp")));
imageView_->Refresh(image);
performaceTimer_.setTimerType(Qt::TimerType::PreciseTimer);
connect(ptSetupWidget_, SIGNAL(RunPT()), this, SLOT(HandlePT()));
connect(&performaceTimer_, SIGNAL(timeout()), this, SLOT(HandleTimeout()));
ptSetupWidget_->hide();
resize(640, 480);
}
void MainWidget::HandleLoadImage()
{
auto fileName = QFileDialog::getOpenFileName(this, "Load Image", Cvb::UI::CvbToQt(Cvb::InstallPath()), "Images(*.bmp *.png *.tif *.tiff *.jpg);;Common Vision Blox Image Object(*.mio)");
if (fileName.isEmpty())
return;
try
{
imageView_->Refresh(image);
}
catch (const std::exception& error)
{
QMessageBox::critical(this, "Error", QString(error.what()));
}
}
void MainWidget::HandlePixelValue()
{
if (!mouseMoveCookie_)
{
mouseMoveCookie_ = imageView_->RegisterEventMouseMoved([&](Cvb::Point2D<int> mousePos, const std::vector<double>& pixelVal)
{
Cvb::StringStream titleStream;
titleStream << "(X:" << mousePos.X() << ", Y:" << mousePos.Y() << ") ";
if (pixelVal.size() == 3)
titleStream << "(R:" << qFloor(pixelVal[0]) << ", G:" << qFloor(pixelVal[1]) << ", B:" << qFloor(pixelVal[2]) << ")";
else if (pixelVal.size() == 1)
titleStream << "(V:" << qFloor(pixelVal[0]) << ")";
setWindowTitle(Cvb::UI::CvbToQt(titleStream.str()));
});
}
else
{
imageView_->UnregisterEventMouseMoved(mouseMoveCookie_);
setWindowTitle("");
}
}
void MainWidget::HandleRenderEngineChanged(QAction* action)
{
auto renderEngine = static_cast<Cvb::UI::RenderEngine>(action->data().toInt());
try
{
imageView_->SetRenderEngine(renderEngine);
imageView_->Refresh();
}
catch (const std::exception& error)
{
QMessageBox::critical(this, "Error", QString(error.what()) + QString("\nCheck your graphics driver!"));
}
}
void MainWidget::HandleUploadModeChange(QAction* action)
{
auto uploadMode = static_cast<Cvb::UI::UploadMode>(action->data().toInt());
try
{
imageView_->SetUploadMode(uploadMode);
}
catch (const std::exception& error)
{
QMessageBox::critical(this, "Error", QString(error.what()));
}
}
void MainWidget::HandlePT()
{
ptState_ = PTState::Running;
rateCounter_.SetWindowSize(ptSetupWidget_->MeasurementCout());
testCycles_ = 0;
ShowProgress();
performaceTimer_.start();
}
void MainWidget::HandleTimeout()
{
if (testCycles_ % ptSetupWidget_->RefreshCount() == 0)
{
rateCounter_.Step();
ShowProgress();
if (rateCounter_.NumSteps() == rateCounter_.WindowSize())
{
performaceTimer_.stop();
if (ptState_ == PTState::Running)
{
auto rate = rateCounter_.Rate();
AppendResult(rate * static_cast<double>(ptSetupWidget_->RefreshCount()));
rateCounter_.Reset();
ptState_ = PTState::Idle;
setWindowTitle("");
}
}
}
imageView_->Refresh();
testCycles_++;
}
void MainWidget::HandleClearResults()
{
while (ptResultWidget_->rowCount())
ptResultWidget_->removeRow(0);
}
void MainWidget::ShowProgress() noexcept
{
ptResultWidget_->setWindowTitle(QString("Performance Test ")
+ ((ptState_ == PTState::Running) ? QString("Running") : QString("Setup"))
+ QString(": %1").arg(rateCounter_.NumSteps())
+ QString(" / %1").arg(rateCounter_.WindowSize()));
}
void MainWidget::AppendResult(double fps)
{
PTResult result;
result.Planes = imageView_->Image()->PlanesCount();
result.FPS = fps;
result.RenderEngine = imageView_->RenderEngine();
result.ViewSize = imageView_->size();
result.ImageSize = imageView_->Image()->Size();
result.UploadMode = imageView_->UploadMode();
result.Zoom = imageView_->Zoom();
ptResultWidget_->setWindowTitle("Performance Test Results");
ptResultWidget_->AddResult(result);
}
void MainWidget::contextMenuEvent(QContextMenuEvent *event)
{
// Context menus do not work in full screen mode!
if (windowState() & Qt::WindowFullScreen
|| ptState_ != PTState::Idle)
return;
QMenu contextMenu;
auto acLoadImage = contextMenu.addAction("Load Image");
contextMenu.addSeparator();
auto acShowFullScreen = contextMenu.addAction("Show Full Screen");
auto acPixelValues = contextMenu.addAction("Pixel Values");
acPixelValues->setCheckable(true);
acPixelValues->setChecked(static_cast<bool>(mouseMoveCookie_));
contextMenu.addSeparator();
auto mnRenderEngine = contextMenu.addMenu("Render Engine");
QActionGroup* agRenderEngine = new QActionGroup(&contextMenu);
agRenderEngine->setExclusive(true);
auto acRenderEngineRaster = agRenderEngine->addAction("Raster");
acRenderEngineRaster->setCheckable(true);
acRenderEngineRaster->setData(static_cast<int>(Cvb::UI::RenderEngine::Raster));
auto acRenderEngineGL2 = agRenderEngine->addAction("OpenGL 2");
acRenderEngineGL2->setCheckable(true);
acRenderEngineGL2->setData(static_cast<int>(Cvb::UI::RenderEngine::OpenGL2));
auto acRenderEngineGL3 = agRenderEngine->addAction("OpenGL 3");
acRenderEngineGL3->setCheckable(true);
acRenderEngineGL3->setData(static_cast<int>(Cvb::UI::RenderEngine::OpenGL3));
switch (imageView_->RenderEngine())
{
default:
case Cvb::UI::RenderEngine::Raster:
acRenderEngineRaster->setChecked(true);
break;
case Cvb::UI::RenderEngine::OpenGL2:
acRenderEngineGL2->setChecked(true);
break;
case Cvb::UI::RenderEngine::OpenGL3:
acRenderEngineGL3->setChecked(true);
break;
}
mnRenderEngine->addActions(agRenderEngine->actions());
auto mnUploadMode = contextMenu.addMenu("Upload Mode");
QActionGroup* agUploadMode = new QActionGroup(&contextMenu);
agUploadMode->setExclusive(true);
auto acUploadModeViewPort = agUploadMode->addAction("Viewport");
acUploadModeViewPort->setCheckable(true);
acUploadModeViewPort->setData(static_cast<int>(Cvb::UI::UploadMode::Viewport));
auto acUploadModeImage = agUploadMode->addAction("Image");
acUploadModeImage->setCheckable(true);
acUploadModeImage->setData(static_cast<int>(Cvb::UI::UploadMode::Image));
switch (imageView_->UploadMode())
{
default:
case Cvb::UI::UploadMode::Viewport:
acUploadModeViewPort->setChecked(true);
break;
case Cvb::UI::UploadMode::Image:
acUploadModeImage->setChecked(true);
break;
}
mnUploadMode->addActions(agUploadMode->actions());
auto mnPT = contextMenu.addMenu("Performance Test");
auto acSetupTest = mnPT->addAction("Setup Test");
auto acShowResults = mnPT->addAction("Show Results");
auto acClearResults = mnPT->addAction("Clear Results");
connect(acLoadImage, SIGNAL(triggered()), this, SLOT(HandleLoadImage()));
connect(acPixelValues, SIGNAL(triggered()), this, SLOT(HandlePixelValue()));
connect(agRenderEngine, SIGNAL(triggered(QAction*)), this, SLOT(HandleRenderEngineChanged(QAction*)));
connect(agUploadMode, SIGNAL(triggered(QAction*)), this, SLOT(HandleUploadModeChange(QAction*)));
connect(acShowFullScreen, SIGNAL(triggered()), this, SLOT(showFullScreen()));
connect(acSetupTest, SIGNAL(triggered()), ptSetupWidget_, SLOT(show()));
connect(acShowResults, SIGNAL(triggered()), ptResultWidget_, SLOT(show()));
connect(acClearResults, SIGNAL(triggered()), this, SLOT(HandleClearResults()));
contextMenu.exec(mapToGlobal(event->pos()));
}
void MainWidget::keyPressEvent(QKeyEvent *event)
{
if (ptState_ == PTState::Running)
{
QWidget::keyPressEvent(event);
return;
}
if ((event->key() == Qt::Key_T) && QApplication::keyboardModifiers() && Qt::ControlModifier)
{
if (ptSetupWidget_->isVisible())
ptSetupWidget_->hide();
else
ptSetupWidget_->show();
}
else if ((event->key() == Qt::Key_F) && QApplication::keyboardModifiers() && Qt::ControlModifier)
{
if (isFullScreen())
showNormal();
else
showFullScreen();
}
else if ((event->key() == Qt::Key_R) && QApplication::keyboardModifiers() && Qt::ControlModifier)
{
if (ptResultWidget_->isVisible())
ptResultWidget_->close();
else
ptResultWidget_->show();
}
else if (event->key() == Qt::Key_Escape)
{
if (isFullScreen())
showNormal();
}
}
static std::unique_ptr< Image > Load(const String &fileName)
T X() const noexcept
T Y() const noexcept
T Height() const noexcept
T Width() const noexcept
static String VendorName(int version)
static String RendererName(int version)
Cvb::String QtToCvb(const QString text) noexcept
QString CvbToQt(const Cvb::String &text) noexcept
String ExpandPath(const String &path)
std::shared_ptr< Image > ImagePtr
std::stringstream StringStream
String InstallPath()
cvb.Image resize(cvb.Image image, cvb.Size2D target_size, int interpolation=cvb.foundation.Interpolation.Linear)

main_widget.hpp:

#pragma once
#include <QWidget>
#include <QTimer>
#include <QDialog>
#include <QSpinBox>
#include <QList>
#include <QTableWidget>
#include <QHBoxLayout>
#include <QMenu>
#include <QAction>
#include <QActionGroup>
#include <QMessageBox>
#include <QFileDialog>
#include <QPushButton>
#include <QStringList>
#include <QHeaderView>
#include <QLabel>
#include <QGroupBox>
#include <QApplication>
#include <QDesktopWidget>
#include <cvb/ui/image_view.hpp>
#include <cvb/utilities/rate_counter.hpp>
struct PTResult
{
Cvb::Size2D<int> ImageSize;
QSize ViewSize;
int Planes = 1;
Cvb::UI::UploadMode UploadMode = Cvb::UI::UploadMode::Image;
Cvb::UI::RenderEngine RenderEngine = Cvb::UI::RenderEngine::Raster;
double FPS = 0.0;
};
class PTResultWidget
: public QTableWidget
{
public:
PTResultWidget();
~PTResultWidget() = default;
void AddResult(const PTResult& result);
private:
void SetResultItem(int row, int column, const QString & text, const QString & toolTip = QString());
QString ImageSizeToString(Cvb::Size2D<int> size) const;
QString ViewSizeToString(QSize size) const;
QString ZoomToString(Cvb::UI::ZoomDescriptor zoomDescriptor) const;
QString PlanesToString(int planes) const;
QString UploadModeToString(Cvb::UI::UploadMode uploadMode) const;
QString RenderEngineToString(Cvb::UI::RenderEngine renderEngine) const;
QString FPsToString(double fps) const;
};
class PTSetupWidget
: public QWidget
{
Q_OBJECT
public:
PTSetupWidget(QWidget * parent, PTResultWidget * ptResultWidget);
~PTSetupWidget() = default;
int RefreshCount() const noexcept
{
return refreshCount_;
}
int MeasurementCout() const noexcept
{
return measurementCount_;
}
private:
QSpinBox * spRefreshCount_ = nullptr;
QSpinBox * spMeasurementCount_ = nullptr;
PTResultWidget * ptResultWidget_ = nullptr;
private Q_SLOTS:
void HandleHide() noexcept;
void HandleHideAndRunPT() noexcept;
void HandleRefreshCountChanged(int value) noexcept;
void HandleMeasurementCountChanged(int value) noexcept;
private:
int refreshCount_ = 1000;
int measurementCount_ = 10;
Q_SIGNALS:
void RunPT();
};
enum class PTState
{
Idle,
Running
};
class MainWidget
: public QWidget
{
Q_OBJECT
public:
explicit MainWidget(PTResultWidget * ptResultWidget);
~MainWidget() = default;
private Q_SLOTS:
void HandleLoadImage();
void HandlePixelValue();
void HandleRenderEngineChanged(QAction* action);
void HandleUploadModeChange(QAction* action);
void HandlePT();
void HandleTimeout();
void HandleClearResults();
private:
void contextMenuEvent(QContextMenuEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void ShowProgress() noexcept;
void AppendResult(double fps);
Cvb::RateCounter rateCounter_;
QTimer performaceTimer_;
Cvb::UI::ImageView* imageView_ = nullptr;
Cvb::EventCookie mouseMoveCookie_;
int testCycles_ = 0;
PTState ptState_ = PTState::Idle;
PTSetupWidget * ptSetupWidget_ = nullptr;
PTResultWidget * ptResultWidget_ = nullptr;
};