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

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

main.cpp:

// The QtStatisticsDisplay example shows a statistics display with a stream from a GenICam device with
// Qt.
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
#include "main_widget.hpp"
#include <QIcon>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setWindowIcon(QIcon(":/CVB_Qt_App.png"));
MainWidget mainWidget;
mainWidget.show();
mainWidget.resize(1024, 640);
return app.exec();
}

main_widget.cpp:

#include "main_widget.hpp"
#include <qmath.h>
#include <QCheckBox>
#include <QComboBox>
#include <QDebug>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QGroupBox>
#include <QMessageBox>
#include <QMutexLocker>
#include <QPushButton>
#include <QRadioButton>
#include <QWeakPointer>
#include <cvb/device_factory.hpp>
MainWidget::MainWidget()
: QWidget(),
gbStatEntriesLayout_(new QVBoxLayout), pbSnap_(new QPushButton("Sna&p", this)),
chkGrab_(new QCheckBox("&Grab", this)), gbSelectedPort_(new QGroupBox("Selected Port", this)),
gbStatistics_(new QGroupBox("Statistic", this)), cbSelectedPort_(new QComboBox(gbSelectedPort_)),
view_(new Cvb::UI::ImageView(this)), device_(Cvb::DeviceFactory::Open(Cvb::InstallPath() + CVB_LIT("drivers/CVMock.vin"),
Cvb::AcquisitionStack::Vin)),
streamH_(Cvb::Async::SingleStreamHandler::Create(device_->Stream())), updateStatTimer_(new QTimer(this))
{
qDebug() << "Please wait for the setup to load...";
// Widgets we do not need to modify (only local)
QPushButton* pbOpen = new QPushButton("&Open Image", this);
QPushButton* pbOpenDev = new QPushButton("&Discover Devices", this);
QPushButton* pbSave = new QPushButton("&Save Image", this);
// Create layouts
QHBoxLayout* mainLayout = new QHBoxLayout;
QVBoxLayout* sideLayout = new QVBoxLayout;
QVBoxLayout* gbSelectedPortLayout = new QVBoxLayout;
// add the widgets to the side layout
sideLayout->addWidget(pbOpen);
sideLayout->addWidget(pbOpenDev);
sideLayout->addWidget(pbSave);
sideLayout->addWidget(chkGrab_);
sideLayout->addWidget(pbSnap_);
// Discover devices and fill list
onDiscover();
// Add horizontal statistics entries to stat. layout and attach to side layout
gbStatistics_->setLayout(gbStatEntriesLayout_);
sideLayout->addWidget(gbStatistics_);
// add a stretch
sideLayout->addStretch();
// add the combobox to the layout
gbSelectedPortLayout->addWidget(cbSelectedPort_);
// add the combobox to the group box layout
gbSelectedPort_->setLayout(gbSelectedPortLayout);
// add the group box to the side layout
sideLayout->addWidget(gbSelectedPort_);
// add the side layout to the main layout
mainLayout->addLayout(sideLayout);
// add a stretch
mainLayout->addStretch();
// add the display
mainLayout->addWidget(view_);
// now use this layout
setLayout(mainLayout);
// Connections
connect(pbOpen, SIGNAL(clicked()), this, SLOT(onOpen()));
connect(pbOpenDev, SIGNAL(clicked()), this, SLOT(onDiscover()));
connect(pbSave, SIGNAL(clicked()), this, SLOT(onSave()));
connect(pbSnap_, SIGNAL(clicked()), this, SLOT(onSnaped()));
connect(chkGrab_, SIGNAL(stateChanged(int)), this, SLOT(onGrabChanged(int)));
connect(cbSelectedPort_, SIGNAL(currentIndexChanged(int)), this, SLOT(onPortIndexChanged(const int)));
// Statistics timed update
connect(updateStatTimer_, SIGNAL(timeout()), SLOT(updateStatistics()));
updateStatTimer_->start(100);
// Second image view for stream handler to test
view_->SetUploadMode(Cvb::UI::UploadMode::Viewport);
view_->SetRenderEngine(Cvb::UI::RenderEngine::Raster);
view_->Refresh(device_->DeviceImage(), Cvb::UI::AutoRefresh::On);
view_->SetWaitForRepaintEnabled(false);
// Add statistics text
initalizeTooltip();
}
MainWidget::~MainWidget()
{
// Stop the stream before destructing handlers
streamH_->Finish();
}
void MainWidget::onGrabChanged(int state)
{
// Toggle grab
state == Qt::Unchecked ? streamH_->Finish() : streamH_->Run();
}
void MainWidget::onOpen()
{
// Block all possibly recursive signals and update the UI according to the current image
SignalGuard guard(this);
try
{
// Stop grab if running
if (streamH_->IsActive())
{
streamH_->Finish();
chkGrab_->setChecked(false);
}
// Open file dialog
QString filename = QFileDialog::getOpenFileName(
this, tr("Open Image"), QString("/"), tr("CImages (*.bmp *.jpg *.png *.tif *.tiff)"));
if (!filename.isEmpty())
{
// Reset old image if it exists
if (img)
img.reset();
// Load new image
img = Cvb::Image::Load(filename.toStdString());
view_->Refresh(img, Cvb::UI::RefreshMode::UploadAndScheduleRepaint, Cvb::UI::AutoRefresh::Off);
}
}
catch (const Cvb::CvbException& e)
{
std::cout << e.what() << "\nError opening image!" << std::endl;
}
}
void MainWidget::onDiscover()
{
SignalGuard guard(this);
std::cout << "Discovering devices..." << std::endl;
discover_ = Cvb::DeviceFactory::Discover(Cvb::Driver::DiscoverFlags::UpToLevelVin);
cbSelectedPort_->clear();
gbSelectedPort_->setEnabled(true);
for (const auto& device : discover_)
{
Cvb::String devModel{ "Unset" };
// Write device model name to list if available, else number each entry
if (device.TryGetProperty(Cvb::Driver::DiscoveryProperties::DeviceModel, devModel))
cbSelectedPort_->addItem(QString::fromStdString(devModel), static_cast<int32_t>(device.Index()));
else
cbSelectedPort_->addItem(QString("Device %1").arg(device.Index()), static_cast<int32_t>(device.Index()));
}
cbSelectedPort_->setCurrentIndex(0);
loadDiscoveredDevice(0ul); // Load first device
}
void MainWidget::onSave()
{
// Block all possibly recursive signals and update the UI according to the current image
SignalGuard guard(this);
// Stop grab if running
if (streamH_->IsActive())
{
streamH_->Finish();
chkGrab_->setChecked(false);
}
// Open file dialog
QString filename = QFileDialog::getSaveFileName(
this, tr("Save Image"), QString("~/"), tr("CImages (*.bmp *.jpg *.png *.tif *.tiff)"));
if (!filename.isEmpty())
view_->Image()->Save(filename.toLatin1().toStdString());
}
void MainWidget::onSnaped()
{
// Stop grab if running
if (streamH_->IsActive())
{
streamH_->Finish();
chkGrab_->setChecked(false);
}
auto waitResult = device_->Stream()->GetSnapshot();
if (waitResult.Image == nullptr)
throw std::runtime_error("Could not snap image.");
}
void MainWidget::onPortIndexChanged(const int index)
{
// Load new device to tmp and check if exists
loadDiscoveredDevice(index);
}
void MainWidget::loadDiscoveredDevice(const unsigned long devNum)
{
SignalGuard guard(this);
std::cout << "Loading device..." << std::endl;
// Stop grab if running
if (streamH_->IsActive())
{
streamH_->Finish();
chkGrab_->setChecked(false);
}
// Load first discovered device to tmp and check if exists
try
{
Cvb::DevicePtr tmpDevPtr{ Cvb::DeviceFactory::Open(discover_.at(devNum).AccessToken(), Cvb::AcquisitionStack::Vin) };
if (tmpDevPtr)
{
std::cout << "Loading device " << discover_.at(devNum).AccessToken() << std::endl;
// Reset stream and device pointer
streamH_.reset();
device_.reset();
device_ = tmpDevPtr;
streamH_ = Cvb::SingleStreamHandler::Create(device_->Stream());
view_->Refresh(device_->DeviceImage(), Cvb::UI::AutoRefresh::On);
initializeStatistics();
}
}
catch (const Cvb::CvbException& e)
{
std::cout << e.what() << "\nError changing discovered device!" << std::endl;
}
}
void MainWidget::updateStatistics()
{
SignalGuard guard(this);
unsigned long currentStat = 0;
for (auto const& stat : statisticsList_)
{
// Update available statistic values
auto const statEnumName = std::get<0>(stat);
auto value = device_->Stream()->Statistics(statEnumName);
auto statValue = QString::number(value);
statValues_.at(currentStat)->setText(statValue);
++currentStat;
}
}
void MainWidget::initializeStatistics()
{
std::cout << "Creating device statistic..." << std::endl;
using namespace Cvb::Driver;
// Clean statistics in case of repaint after device change
for (auto& valWdg : statValues_)
{
gbStatEntriesLayout_->removeWidget(valWdg);
delete valWdg;
}
for (auto& nameWdg : statNames_)
{
gbStatEntriesLayout_->removeWidget(nameWdg);
delete nameWdg;
}
for (auto& lay : gbHStatNameValLayout_)
{
// delete lay;
gbStatEntriesLayout_->removeItem(lay);
delete lay;
}
// Set displayable statistics here
statisticsList_.clear();
statisticsList_.push_back(tuple_element(StreamInfo::IsCameraDetected, "IsCameraDetected"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersAcquired, "NumBuffersAcquired"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersAnnounced, "NumBuffersAnnounced"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersPending, "NumBuffersPending"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersBeingFilled, "NumBuffersBeingFilled"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersDelivered, "NumBuffersDelivered"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersLocked, "NumBuffersLocked"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersLost, "NumBuffersLost"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersLostLocked, "NumBuffersLostLocked"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersLostTransfer, "NumBuffersLostTransfer"));
statisticsList_.push_back(tuple_element(StreamInfo::NumBuffersQueued, "NumBuffersQueued"));
statisticsList_.push_back(tuple_element(StreamInfo::NumPacketsReceived, "NumPacketsReceived"));
statisticsList_.push_back(tuple_element(StreamInfo::NumResends, "NumResends"));
statisticsList_.push_back(tuple_element(StreamInfo::NumTriggersLost, "NumTriggersLost"));
// Fill out statistic display
statNames_.clear();
statValues_.clear();
gbHStatNameValLayout_.clear();
unsigned long currentStat = 0;
int unavailableStatisticPos = -1;
std::vector<int> delEntries{};
for (auto const& stat : statisticsList_)
{
try
{
++unavailableStatisticPos;
// Set available statistic values
auto const statEnumName = std::get<0>(stat);
auto value = device_->Stream()->Statistics(statEnumName); // May throw exception when statistic is not available
std::string statValue = std::to_string(value);
statValues_.push_back(new QLabel(tr(statValue.c_str())));
statValues_.back()->setAlignment(Qt::AlignLeft);
statValues_.back()->updatesEnabled();
// Set available statistic names
statNames_.push_back(new QLabel(tr(std::get<1>(stat).c_str())));
// Add statistic name and value to horizontal layout
gbHStatNameValLayout_.push_back(new QHBoxLayout);
gbHStatNameValLayout_.at(currentStat)->addWidget(statNames_.back());
statValues_.back()->setAlignment(Qt::AlignRight);
gbHStatNameValLayout_.at(currentStat)->addWidget(statValues_.back());
// Add horizontal layout to vertical statistics layout
gbStatEntriesLayout_->addLayout(gbHStatNameValLayout_.at(currentStat));
++currentStat;
}
catch (const std::exception& e)
{
std::cout << "Removing statistic due to error: " << e.what() << std::endl;
// Store vector position of unavailable statistic
delEntries.push_back(unavailableStatisticPos);
}
}
// Remove unavailable statistics from statistic list
for (auto ri = delEntries.rbegin(); ri != delEntries.rend(); ++ri)
statisticsList_.erase(statisticsList_.begin() + *ri);
std::cout << "Done initializing" << std::endl;
}
void MainWidget::initalizeTooltip()
{
// Mouse position information
view_->setMouseTracking(true);
QApplication::setOverrideCursor(Qt::ArrowCursor);
// Show mouse position and pixel data
view_->RegisterEventMouseMoved([&](Cvb::Point2D<int> mousePos, const std::vector<double>& pixelVal) {
Cvb::StringStream titleStream;
// Check if Image is RGB like or mono
if (pixelVal.size() == 3)
{
titleStream << "(X:" << mousePos.X() << ", Y:" << mousePos.Y() << ") (R:" << qFloor(pixelVal[0])
<< ", G:" << qFloor(pixelVal[1]) << ", B:" << qFloor(pixelVal[2]) << ")";
}
else if (pixelVal.size() == 1)
{
titleStream << "(X:" << mousePos.X() << ", Y:" << mousePos.Y() << ") (Mono:" << qFloor(pixelVal[0]) << ")";
}
else
{
titleStream << "(X:" << mousePos.X() << ", Y:" << mousePos.Y() << ") (Mono:";
for (auto& pix : pixelVal)
titleStream << qFloor(pix) << " | ";
titleStream << ")";
}
view_->setToolTip(QString::fromStdString(titleStream.str()));
});
}
void MainWidget::blockUI(const bool block)
{
chkGrab_->blockSignals(block);
pbSnap_->blockSignals(block);
cbSelectedPort_->blockSignals(block);
view_->blockSignals(block);
gbSelectedPort_->blockSignals(block);
gbStatistics_->blockSignals(block);
updateStatTimer_->blockSignals(block);
}
static std::vector< DiscoveryInformation > Discover()
static std::shared_ptr< T > Open(const String &provider, AcquisitionStack acquisitionStack=AcquisitionStack::PreferVin)
static std::unique_ptr< Image > Load(const String &fileName)
T X() const noexcept
T Y() const noexcept
static std::unique_ptr< SingleStreamHandler > Create(const Driver::StreamPtr &stream)
std::string String
std::stringstream StringStream
std::shared_ptr< Device > DevicePtr

main_widget.hpp:

#ifndef MAINWIDGET_HPP_B6881A7A_C21F_488F_834C_2046B8CE3362
#define MAINWIDGET_HPP_B6881A7A_C21F_488F_834C_2046B8CE3362
#include <iostream>
#include <QApplication>
#include <QHBoxLayout>
#include <QLabel>
#include <QScopedPointer>
#include <QSharedPointer>
#include <QTimer>
#include <QToolTip>
#include <QVBoxLayout>
#include <QWidget>
#include <tuple>
#include <cvb/async/single_stream_handler.hpp>
#include <cvb/ui/image_view.hpp>
class QCheckBox;
class QGroupBox;
class QPushButton;
class QComboBox;
class QRadioButton;
class StatisticsDisplay;
typedef std::tuple<Cvb::Driver::StreamInfo, Cvb::String> tuple_element;
typedef std::vector<std::tuple<Cvb::Driver::StreamInfo, Cvb::String> > tuple_list;
class MainWidget : public QWidget
{
Q_OBJECT
public:
explicit MainWidget();
~MainWidget();
public Q_SLOTS:
void onGrabChanged(int state);
void onOpen();
void onDiscover();
void onSave();
void onSnaped();
void onPortIndexChanged(const int index);
void updateStatistics();
private:
void blockUI(const bool block);
void loadDiscoveredDevice(const unsigned long devNum);
void initializeStatistics();
void initalizeTooltip();
// RAII signal blocker
class SignalGuard
{
public:
explicit SignalGuard(MainWidget* mainWidget) : mainWidget_(mainWidget)
{
mainWidget_->blockUI(true);
}
~SignalGuard() { mainWidget_->blockUI(false); }
private:
MainWidget* mainWidget_;
};
std::vector<QHBoxLayout*> gbHStatNameValLayout_;
QVBoxLayout* gbStatEntriesLayout_;
QPushButton* pbSnap_;
QCheckBox* chkGrab_;
QGroupBox* gbSelectedPort_;
QGroupBox* gbStatistics_;
QComboBox* cbSelectedPort_;
Cvb::UI::ImageView* view_;
Cvb::DevicePtr device_;
std::vector<Cvb::Driver::DiscoveryInformation> discover_;
tuple_list statisticsList_;
QTimer* updateStatTimer_;
std::vector<QLabel*> statNames_;
std::vector<QLabel*> statValues_;
QLabel* mouseText_;
};
#endif
std::shared_ptr< SingleStreamHandler > SingleStreamHandlerPtr
std::shared_ptr< Image > ImagePtr