Common Vision Blox 15.0
Loading...
Searching...
No Matches
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 "main_widget.hpp"
#include <cvb/image.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/ui/opengl_image_renderer_factory.hpp>
#include <cvb/ui/ui.hpp>
#include <cvb/utilities/system_info.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")
QString renderer =
QString("Renderer: %1")
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::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 <QAction>
#include <QActionGroup>
#include <QApplication>
#include <QDesktopWidget>
#include <QDialog>
#include <QFileDialog>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QList>
#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
#include <QSpinBox>
#include <QStringList>
#include <QTableWidget>
#include <QTimer>
#include <QWidget>
#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;
};