#include "main_widget.hpp"
#include <QElapsedTimer>
#include <QFileDialog>
#include <QGraphicsRectItem>
#include <QGraphicsSceneMouseEvent>
#include <QGroupBox>
#include <QMessageBox>
#include <QPushButton>
#include <QRubberBand>
#include <QVBoxLayout>
#include <cvb/async/single_stream_handler.hpp>
#include <cvb/device.hpp>
#include <cvb/device_factory.hpp>
#include <cvb/driver/driver.hpp>
#include <cvb/image.hpp>
#include <cvb/shapefinder2/classifier_factory.hpp>
MainWidget::MainWidget() : QSplitter() {
imageScene_ = new CustomImageScene(this);
imageView_->SetUploadMode(Cvb::UI::UploadMode::Viewport);
imageView_->SetRenderEngine(Cvb::UI::RenderEngine::Raster);
imageView_->resize(800, 600);
imageView_->setDragMode(QGraphicsView::RubberBandDrag);
QObject::connect(imageScene_, SIGNAL(SelectionDone(QRectF)), this,
SLOT(HandleSelection(QRectF)));
ctrlWidget_ = new ControlWidget(this);
addWidget(imageView_);
addWidget(ctrlWidget_);
Cvb::AcquisitionStack::Vin);
imageView_->Refresh(device_->DeviceImage(), Cvb::UI::AutoRefresh::On);
streamHandler_ = CustomStreamHandler::Create(device_->Stream(), *this);
ctrlWidget_->EnableGrabCheckBox(true);
QObject::connect(this, SIGNAL(SearchDone()), this, SLOT(ShowSearchResult()));
resize(1000, 800);
device_->Stream()->GetSnapshot();
}
void MainWidget::HandleLoad() {
imageScene_->ClearScene();
auto fileName = QFileDialog::getOpenFileName(
this, "Load Image",
CVB_LIT("tutorial/ShapeFinder/Images/SF2/Lusterterminal"))),
"CVB Emulator Image Lists (*.emu);;CVB Drivers (*.vin);;Images (*.bmp "
"*.png *.tif *.tiff *.jpg)");
if (fileName.isEmpty())
return;
if (fileName.contains(".emu", Qt::CaseInsensitive))
fileName = fileName.replace("/", "\\");
try {
if (fileName.contains(".bmp", Qt::CaseInsensitive) ||
fileName.contains(".png", Qt::CaseInsensitive) ||
fileName.contains(".tif", Qt::CaseInsensitive) ||
fileName.contains(".jpg", Qt::CaseInsensitive)) {
imageView_->Refresh(image);
ctrlWidget_->EnableGrabCheckBox(false);
} else {
Cvb::AcquisitionStack::Vin);
imageView_->Refresh(device_->DeviceImage(), Cvb::UI::AutoRefresh::On);
streamHandler_ = CustomStreamHandler::Create(device_->Stream(), *this);
ctrlWidget_->EnableGrabCheckBox(true);
}
} catch (const std::exception &error) {
QMessageBox::critical(this, "Error", QString(error.what()));
}
}
void MainWidget::HandleGrab(int state) {
if (state == Qt::CheckState::Checked) {
imageScene_->ClearScene();
streamHandler_->Run();
} else {
bool wait = imageView_->IsWaitForRepaintEnabled();
if (wait)
imageView_->SetWaitForRepaintEnabled(!wait);
streamHandler_->Finish();
imageView_->SetWaitForRepaintEnabled(wait);
}
}
void MainWidget::HandleSnap() {
device_->Stream()->GetSnapshot();
if (continuedSearch_)
HandleSearch();
else
imageScene_->ClearScene();
}
void MainWidget::HandleSave() {
auto fileName = QFileDialog::getSaveFileName(
"Bitmap File (*.bmp);;CVB Emulator Image Lists (*.emu);;JPEG (*.jpg, "
"*.jpeg);;Portable Network Graphic (*.png);;Tagged Image File Format "
"(*.tif, *.tiff);;All Files (*.*)");
if (fileName.isEmpty())
return;
}
void MainWidget::HandleLoadModel() {
imageScene_->ClearScene();
auto fileName = QFileDialog::getOpenFileName(
this, "Load SF2 Model",
CVB_LIT("tutorial/ShapeFinder/Images/SF2/Lusterterminal"))),
"ShapeFinder2 models (*.sf2)");
if (fileName.isEmpty())
return;
}
void MainWidget::HandleSaveModel() {
auto fileName = QFileDialog::getSaveFileName(
this, "Save SF2 Model",
CVB_LIT("tutorial/ShapeFinder/Images/SF2/Lusterterminal"))),
"ShapeFinder2 models (*.sf2)");
if (fileName.isEmpty())
return;
}
void MainWidget::HandleTrain() {
if (isSelected_) {
ctrlWidget_->SetTrainView(*selection_);
imageScene_->ClearScene();
isSelected_ = false;
} else {
ctrlWidget_->SetTrainView(*imageView_->Image());
auto aoi = imageView_->Image()->Bounds();
selectionRect_ =
}
auto centerX = static_cast<int>(
std::round(selectionRect_.Left() +
((selectionRect_.Right() - selectionRect_.Left()) / 2)));
auto centerY = static_cast<int>(
std::round(selectionRect_.Top() +
((selectionRect_.Bottom() - selectionRect_.Top()) / 2)));
selectionRect_.Left() - centerX, selectionRect_.Top() - centerY,
selectionRect_.Right() - centerX, selectionRect_.Bottom() - centerY);
try {
classifier_ =
factory.
Learn(imageView_->Image()->Plane(0),
} catch (const std::exception &e) {
QMessageBox::critical(this, "Error", e.what());
}
}
void MainWidget::HandleSearch() {
if (!classifier_) {
QMessageBox::warning(
this, "SF2 Search",
"Please create (train) or load a model/classifier first.");
return;
}
Search();
}
void MainWidget::HandleContSearch(int state) {
imageScene_->ClearScene();
if (state == Qt::Checked)
continuedSearch_ = true;
else
continuedSearch_ = false;
}
}
void MainWidget::HandleSelection(QRectF selection) {
auto convertedArea = imageView_->Image()->ImageToPixelCoordinates(area);
selection_ = imageView_->Image()->Map(
isSelected_ = true;
selectionRect_ = boundingRect;
}
void MainWidget::Search() {
if (!classifier_)
return;
Cvb::ShapeFinder2::PrecisionMode::NoCorrelation;
double relativeThreshold = 0.55;
int minimumThreshold = 20;
int coarseLocality = 10;
try {
if (isSelected_) {
selectionRect_.Right(), selectionRect_.Bottom());
SearchWithCuda(imageView_->Image()->Plane(0), aoi, mode,
relativeThreshold, minimumThreshold, coarseLocality);
SearchWithoutCuda(imageView_->Image()->Plane(0), aoi, mode,
relativeThreshold, minimumThreshold, coarseLocality);
} else {
SearchWithCuda(imageView_->Image()->Plane(0),
imageView_->Image()->Bounds(), mode, relativeThreshold,
minimumThreshold, coarseLocality);
SearchWithoutCuda(imageView_->Image()->Plane(0),
imageView_->Image()->Bounds(), mode, relativeThreshold,
minimumThreshold, coarseLocality);
}
} catch (const std::exception &e) {
QMessageBox::critical(this, "Error", e.what());
}
emit SearchDone();
}
double relativeThreshold, int minimumThreshold,
int coarseLocality) {
classifier_->UseCuda(Cvb::ShapeFinder2::CudaStatus::Default);
std::chrono::steady_clock::time_point begin =
std::chrono::steady_clock::now();
searchResult_ = classifier_->SearchAll(plane, aoi, mode, relativeThreshold,
minimumThreshold, coarseLocality);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
durationWithCuda_ =
std::chrono::duration_cast<std::chrono::milliseconds>(end - begin)
.count();
}
double relativeThreshold,
int minimumThreshold, int coarseLocality) {
classifier_->UseCuda(Cvb::ShapeFinder2::CudaStatus::ForceDisable);
std::chrono::steady_clock::time_point begin =
std::chrono::steady_clock::now();
searchResult_ = classifier_->SearchAll(plane, aoi, mode, relativeThreshold,
minimumThreshold, coarseLocality);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
durationWithoutCuda_ =
std::chrono::duration_cast<std::chrono::milliseconds>(end - begin)
.count();
}
void MainWidget::ShowSearchResult() {
isSelected_ = false;
ctrlWidget_->SetResultInfo(searchResult_.size());
imageScene_->SetSearchResult(*imageView_->Image(), searchResult_,
durationWithCuda_, durationWithoutCuda_);
}
ControlWidget::ControlWidget(QWidget *parent) : QWidget(parent) {
auto mainLayout = new QGridLayout;
trainImageView_->SetUploadMode(Cvb::UI::UploadMode::Image);
trainImageView_->SetRenderEngine(Cvb::UI::RenderEngine::Raster);
QPushButton *openImgBtn = new QPushButton(tr("Open Image"));
QObject::connect(openImgBtn, SIGNAL(clicked()), parent, SLOT(HandleLoad()));
grabCheckBox_ = new QCheckBox(tr("Grab"));
QObject::connect(grabCheckBox_, SIGNAL(stateChanged(int)), parent,
SLOT(HandleGrab(int)));
QPushButton *snapBtn = new QPushButton(tr("Snap"));
QObject::connect(snapBtn, SIGNAL(clicked()), parent, SLOT(HandleSnap()));
QPushButton *saveBtn = new QPushButton(tr("Save"));
QObject::connect(saveBtn, SIGNAL(clicked()), parent, SLOT(HandleSave()));
contSearchCheckBox_ = new QCheckBox(tr("Continued Search"));
QObject::connect(contSearchCheckBox_, SIGNAL(stateChanged(int)), parent,
SLOT(HandleContSearch(int)));
QGroupBox *groupBox = new QGroupBox(tr(""));
QPushButton *loadModelBtn = new QPushButton(tr("Load Model"));
QObject::connect(loadModelBtn, SIGNAL(clicked()), parent,
SLOT(HandleLoadModel()));
QPushButton *saveModelBtn = new QPushButton(tr("Save Model"));
QObject::connect(saveModelBtn, SIGNAL(clicked()), parent,
SLOT(HandleSaveModel()));
QPushButton *trainBtn = new QPushButton(tr("Train"));
QObject::connect(trainBtn, SIGNAL(clicked()), parent, SLOT(HandleTrain()));
QPushButton *searchBtn = new QPushButton(tr("Search"));
QObject::connect(searchBtn, SIGNAL(clicked()), parent, SLOT(HandleSearch()));
resultLabel_ = new QLabel(tr("Number of search results: 0"));
QGridLayout *gbLayout = new QGridLayout;
gbLayout->addWidget(trainBtn, 0, 0);
gbLayout->addWidget(loadModelBtn, 0, 1);
gbLayout->addWidget(searchBtn, 1, 0);
gbLayout->addWidget(saveModelBtn, 1, 1);
gbLayout->addWidget(resultLabel_, 2, 0, 1, -1);
groupBox->setLayout(gbLayout);
mainLayout->addWidget(trainImageView_, 0, 0, 1, -1);
mainLayout->addWidget(openImgBtn, 1, 0, 1, 1);
mainLayout->addWidget(grabCheckBox_, 1, 1, 1, 1);
mainLayout->addWidget(snapBtn, 1, 2, 1, 1);
mainLayout->addWidget(saveBtn, 2, 0, 1, 1);
mainLayout->addWidget(contSearchCheckBox_, 2, 1, 1, -1);
mainLayout->addWidget(groupBox, 3, 0, 1, -1);
setLayout(mainLayout);
}
void ControlWidget::EnableGrabCheckBox(bool value) {
grabCheckBox_->setEnabled(value);
}
void ControlWidget::SetResultInfo(size_t numResults) {
QString count = "Number of search results: " + QString::number(numResults);
resultLabel_->setText(count);
}
void ControlWidget::SetTrainView(
const Cvb::Image &image) {
if (trainImageView_)
trainImageView_->Refresh(image);
}
CustomImageScene::CustomImageScene(QWidget *parent)
:
Cvb::UI::ImageScene(parent) {}
void CustomImageScene::SetSearchResult(
std::vector<Cvb::ShapeFinder2::SearchResult> result,
long long durationWithCuda, long long durationWithoutCuda) {
ClearScene();
searchResult_ = result;
for (int i = 0; i < searchResult_.size(); i++) {
QGraphicsRectItem *item =
new QGraphicsRectItem(QRectF(point.X(), point.Y(), 5, 5));
item->setBrush(QBrush(Qt::red));
this->addItem(item);
QString label =
"Q: " + QString::number(res.
Quality(),
'f', 2) +
", A: " + QString::number(res.
Rotation().
Deg(),
'f', 2);
QGraphicsRectItem *textLabel =
new QGraphicsRectItem(QRectF(point.X() + 5, point.Y() + 5, 100, 15));
textLabel->setBrush(QBrush(Qt::red));
this->addItem(textLabel);
QGraphicsTextItem *text = this->addText(label);
text->setPos(point.X() + 5, point.Y() + 2.5);
text->setDefaultTextColor(Qt::black);
QString label1 = "Duration with Cuda: ";
QString label2 = "Duration without Cuda: ";
label1.append(QString::number(durationWithCuda)).append("ms");
label2.append(QString::number(durationWithoutCuda)).append("ms");
QGraphicsTextItem *text1 = this->addText(label1);
text1->setPos(0, 0);
text1->setDefaultTextColor(Qt::green);
text1->setScale(2);
QGraphicsTextItem *text2 = this->addText(label2);
text2->setPos(0, 30);
text2->setDefaultTextColor(Qt::red);
text2->setScale(2);
}
}
void CustomImageScene::ClearScene() {
this->clear();
this->update();
}
void CustomImageScene::mousePressEvent(QGraphicsSceneMouseEvent *event) {
ClearScene();
this->ImageView()->setDragMode(QGraphicsView::RubberBandDrag);
pointStart_ = event->scenePos();
}
void CustomImageScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
pointEnd_ = event->scenePos();
this->addRect(QRectF(pointStart_, pointEnd_), QPen(Qt::blue, 0));
emit SelectionDone(QRectF(pointStart_, pointEnd_));
}
double Deg() const noexcept
static std::unique_ptr< Classifier > Create(const String &fileName)
static std::shared_ptr< T > Open(const String &provider, AcquisitionStack acquisitionStack=AcquisitionStack::PreferVin)
static std::unique_ptr< Image > Load(const String &fileName)
T Bottom() const noexcept
Size2D< T > Size() const noexcept
Point2D< T > Location() const noexcept
std::unique_ptr< Classifier > Learn(const ImagePlane &plane, Point2D< int > position, Rect< int > teachWindow, const std::vector< Point2D< int > > &dontCarePoints) const
double Quality() const noexcept
Angle Rotation() const noexcept
double Y() const noexcept
double X() const noexcept
Cvb::String QtToCvb(const QString text) noexcept
QString CvbToQt(const Cvb::String &text) noexcept
String ExpandPath(const String &path)
std::shared_ptr< Image > ImagePtr