53 QGridLayout* grid =
new QGridLayout(
this);
58 QPushButton* show_button =
new QPushButton(tr(
"Show matches"),
this);
59 connect(show_button, &QPushButton::released,
this,
61 grid->addWidget(show_button, 0, 1, Qt::AlignRight);
68 table_widget_->setSelectionBehavior(QAbstractItemView::SelectRows);
69 table_widget_->setSelectionMode(QAbstractItemView::SingleSelection);
70 table_widget_->setEditTriggers(QAbstractItemView::NoEditTriggers);
71 table_widget_->horizontalHeader()->setStretchLastSection(
true);
79 QItemSelectionModel* select =
table_widget_->selectionModel();
81 if (!select->hasSelection()) {
82 QMessageBox::critical(
this,
"", tr(
"No image pair selected."));
86 if (select->selectedRows().size() > 1) {
87 QMessageBox::critical(
this,
"", tr(
"Only one image pair may be selected."));
93 const auto& selection =
matches_[idx];
95 const std::string path2 =
104 keypoints2, selection.second);
113 [&](
const size_t idx1,
const size_t idx2) {
114 return matches_[idx1].second.size() >
115 matches_[idx2].second.size();
119 info += QString(
"Matched images: ") + QString::number(
matches_.size());
128 QTableWidgetItem* image_id_item =
129 new QTableWidgetItem(QString::number(
matches_[idx].first->ImageId()));
132 QTableWidgetItem* num_matches_item =
133 new QTableWidgetItem(QString::number(
matches_[idx].second.size()));
138 QTableWidgetItem* config_item =
139 new QTableWidgetItem(QString::number(
configs_[idx]));
150 QStringList table_header;
151 table_header <<
"image_id"
162 for (
const auto&
image : images) {
163 if (
image.ImageId() == image_id) {
171 if (matches.size() > 0) {
184 QStringList table_header;
185 table_header <<
"image_id"
198 for (
const auto&
image : images) {
199 if (
image.ImageId() == image_id) {
205 const auto two_view_geometry =
208 if (two_view_geometry.inlier_matches.size() > 0) {
209 matches_.emplace_back(&
image, two_view_geometry.inlier_matches);
210 configs_.push_back(two_view_geometry.config);
221 : parent_(parent), options_(options) {
224 setWindowFlags(Qt::Window);
225 resize(parent->size().width() - 20, parent->size().height() - 20);
227 QGridLayout* grid =
new QGridLayout(
this);
229 tab_widget_ =
new QTabWidget(
this);
231 matches_tab_ =
new MatchesTab(
this, options_, database);
232 tab_widget_->addTab(matches_tab_, tr(
"Matches"));
235 tab_widget_->addTab(two_view_geometries_tab_, tr(
"Two-view geometries"));
237 grid->addWidget(tab_widget_, 0, 0);
239 QPushButton* close_button =
new QPushButton(tr(
"Close"),
this);
240 connect(close_button, &QPushButton::released,
this,
241 &OverlappingImagesWidget::close);
242 grid->addWidget(close_button, 1, 0, Qt::AlignRight);
247 parent_->setDisabled(
true);
250 QString::fromStdString(
"Matches for image " +
std::to_string(image_id)));
252 matches_tab_->
Reload(images, image_id);
253 two_view_geometries_tab_->
Reload(images, image_id);
256 void OverlappingImagesWidget::closeEvent(QCloseEvent*) {
257 matches_tab_->
Clear();
258 two_view_geometries_tab_->
Clear();
259 parent_->setEnabled(
true);
263 : QWidget(parent), database_(database) {
264 QGridLayout* grid =
new QGridLayout(
this);
266 info_label_ =
new QLabel(
this);
267 grid->addWidget(info_label_, 0, 0);
269 QPushButton* add_camera_button =
new QPushButton(tr(
"Add camera"),
this);
270 connect(add_camera_button, &QPushButton::released,
this, &CameraTab::Add);
271 grid->addWidget(add_camera_button, 0, 1, Qt::AlignRight);
273 QPushButton* set_model_button =
new QPushButton(tr(
"Set model"),
this);
274 connect(set_model_button, &QPushButton::released,
this, &CameraTab::SetModel);
275 grid->addWidget(set_model_button, 0, 2, Qt::AlignRight);
277 table_widget_ =
new QTableWidget(
this);
278 table_widget_->setColumnCount(6);
280 QStringList table_header;
281 table_header <<
"camera_id"
286 <<
"prior_focal_length";
287 table_widget_->setHorizontalHeaderLabels(table_header);
289 table_widget_->setShowGrid(
true);
290 table_widget_->setSelectionBehavior(QAbstractItemView::SelectRows);
291 table_widget_->horizontalHeader()->setStretchLastSection(
true);
292 table_widget_->verticalHeader()->setVisible(
false);
293 table_widget_->verticalHeader()->setDefaultSectionSize(20);
295 connect(table_widget_, &QTableWidget::itemChanged,
this,
296 &CameraTab::itemChanged);
298 grid->addWidget(table_widget_, 1, 0, 1, 3);
300 grid->setColumnStretch(0, 1);
305 info += QString(
"Cameras: ") + QString::number(database_->
NumCameras());
306 info_label_->setText(info);
311 table_widget_->blockSignals(
true);
313 table_widget_->clearContents();
314 table_widget_->setRowCount(cameras_.size());
316 std::sort(cameras_.begin(), cameras_.end(),
318 return camera1.CameraId() < camera2.CameraId();
321 for (
size_t i = 0; i < cameras_.size(); ++i) {
322 const Camera& camera = cameras_[i];
323 QTableWidgetItem* id_item =
324 new QTableWidgetItem(QString::number(camera.
CameraId()));
325 id_item->setFlags(Qt::ItemIsSelectable);
326 table_widget_->setItem(i, 0, id_item);
328 QTableWidgetItem* model_item =
329 new QTableWidgetItem(QString::fromStdString(camera.
ModelName()));
330 model_item->setFlags(Qt::ItemIsSelectable);
331 table_widget_->setItem(i, 1, model_item);
333 table_widget_->setItem(
334 i, 2,
new QTableWidgetItem(QString::number(camera.
Width())));
335 table_widget_->setItem(
336 i, 3,
new QTableWidgetItem(QString::number(camera.
Height())));
338 table_widget_->setItem(i, 4,
339 new QTableWidgetItem(QString::fromStdString(
341 table_widget_->setItem(
345 table_widget_->resizeColumnsToContents();
347 table_widget_->blockSignals(
false);
352 table_widget_->clearContents();
355 void CameraTab::itemChanged(QTableWidgetItem* item) {
356 Camera& camera = cameras_.at(item->row());
357 const std::vector<double> prev_params = camera.
Params();
359 switch (item->column()) {
363 camera.
SetWidth(
static_cast<size_t>(item->data(Qt::DisplayRole).toInt()));
367 static_cast<size_t>(item->data(Qt::DisplayRole).toInt()));
371 QMessageBox::critical(
this,
"", tr(
"Invalid camera parameters."));
372 table_widget_->blockSignals(
true);
373 item->setText(QString::fromStdString(
VectorToCSV(prev_params)));
374 table_widget_->blockSignals(
false);
379 static_cast<bool>(item->data(Qt::DisplayRole).toInt()));
388 void CameraTab::Add() {
389 QStringList camera_models;
390 #define CAMERA_MODEL_CASE(CameraModel) \
391 << QString::fromStdString(CameraModelIdToName(CameraModel::model_id))
393 #undef CAMERA_MODEL_CASE
396 const QString camera_model = QInputDialog::getItem(
397 this,
"", tr(
"Model:"), camera_models, 0,
false, &ok);
404 const double kDefaultFocalLength = 1.0;
405 const size_t kDefaultWidth = 1;
406 const size_t kDefaultHeight = 1;
408 kDefaultFocalLength, kDefaultWidth, kDefaultHeight);
415 table_widget_->selectRow(cameras_.size() - 1);
418 void CameraTab::SetModel() {
419 QItemSelectionModel* select = table_widget_->selectionModel();
421 if (!select->hasSelection()) {
422 QMessageBox::critical(
this,
"", tr(
"No camera selected."));
426 QStringList camera_models;
427 #define CAMERA_MODEL_CASE(CameraModel) \
428 << QString::fromStdString(CameraModelIdToName(CameraModel::model_id))
430 #undef CAMERA_MODEL_CASE
433 const QString camera_model = QInputDialog::getItem(
434 this,
"", tr(
"Model:"), camera_models, 0,
false, &ok);
440 table_widget_->blockSignals(
true);
442 for (QModelIndex& index : select->selectedRows()) {
444 auto& camera = cameras_.at(index.row());
445 camera.InitializeWithName(camera_model.toUtf8().constData(),
446 camera.MeanFocalLength(), camera.Width(),
451 table_widget_->blockSignals(
false);
459 camera_tab_(camera_tab),
461 database_(database) {
462 QGridLayout* grid =
new QGridLayout(
this);
464 info_label_ =
new QLabel(
this);
465 grid->addWidget(info_label_, 0, 0);
467 QPushButton* set_camera_button =
new QPushButton(tr(
"Set camera"),
this);
468 connect(set_camera_button, &QPushButton::released,
this,
469 &ImageTab::SetCamera);
470 grid->addWidget(set_camera_button, 0, 1, Qt::AlignRight);
472 QPushButton* split_camera_button =
new QPushButton(tr(
"Split camera"),
this);
473 connect(split_camera_button, &QPushButton::released,
this,
474 &ImageTab::SplitCamera);
475 grid->addWidget(split_camera_button, 0, 2, Qt::AlignRight);
477 QPushButton* show_image_button =
new QPushButton(tr(
"Show image"),
this);
478 connect(show_image_button, &QPushButton::released,
this,
479 &ImageTab::ShowImage);
480 grid->addWidget(show_image_button, 0, 3, Qt::AlignRight);
482 QPushButton* overlapping_images_button =
483 new QPushButton(tr(
"Overlapping images"),
this);
484 connect(overlapping_images_button, &QPushButton::released,
this,
485 &ImageTab::ShowMatches);
486 grid->addWidget(overlapping_images_button, 0, 4, Qt::AlignRight);
488 table_widget_ =
new QTableWidget(
this);
489 table_widget_->setColumnCount(10);
491 QStringList table_header;
492 table_header <<
"image_id"
502 table_widget_->setHorizontalHeaderLabels(table_header);
504 table_widget_->setShowGrid(
true);
505 table_widget_->setSelectionBehavior(QAbstractItemView::SelectRows);
506 table_widget_->horizontalHeader()->setStretchLastSection(
true);
507 table_widget_->verticalHeader()->setVisible(
false);
508 table_widget_->verticalHeader()->setDefaultSectionSize(20);
510 connect(table_widget_, &QTableWidget::itemChanged,
this,
511 &ImageTab::itemChanged);
513 grid->addWidget(table_widget_, 1, 0, 1, 5);
515 grid->setColumnStretch(0, 3);
518 overlapping_images_widget_ =
524 info += QString(
"Images: ") + QString::number(database_->
NumImages());
525 info += QString(
"\n");
526 info += QString(
"Features: ") + QString::number(database_->
NumKeypoints());
527 info_label_->setText(info);
532 table_widget_->blockSignals(
true);
534 table_widget_->clearContents();
535 table_widget_->setRowCount(images_.size());
537 for (
size_t i = 0; i < images_.size(); ++i) {
538 const auto&
image = images_[i];
539 QTableWidgetItem* id_item =
540 new QTableWidgetItem(QString::number(
image.ImageId()));
541 id_item->setFlags(Qt::ItemIsSelectable);
542 table_widget_->setItem(i, 0, id_item);
543 table_widget_->setItem(
544 i, 1,
new QTableWidgetItem(QString::fromStdString(
image.Name())));
545 table_widget_->setItem(
546 i, 2,
new QTableWidgetItem(QString::number(
image.CameraId())));
547 table_widget_->setItem(
548 i, 3,
new QTableWidgetItem(QString::number(
image.QvecPrior(0))));
549 table_widget_->setItem(
550 i, 4,
new QTableWidgetItem(QString::number(
image.QvecPrior(1))));
551 table_widget_->setItem(
552 i, 5,
new QTableWidgetItem(QString::number(
image.QvecPrior(2))));
553 table_widget_->setItem(
554 i, 6,
new QTableWidgetItem(QString::number(
image.QvecPrior(3))));
555 table_widget_->setItem(
556 i, 7,
new QTableWidgetItem(QString::number(
image.TvecPrior(0))));
557 table_widget_->setItem(
558 i, 8,
new QTableWidgetItem(QString::number(
image.TvecPrior(1))));
559 table_widget_->setItem(
560 i, 9,
new QTableWidgetItem(QString::number(
image.TvecPrior(2))));
562 table_widget_->resizeColumnsToContents();
564 table_widget_->blockSignals(
false);
569 table_widget_->clearContents();
572 void ImageTab::itemChanged(QTableWidgetItem* item) {
576 switch (item->column()) {
579 image.SetName(item->text().toUtf8().constData());
582 camera_id =
static_cast<camera_t>(item->data(Qt::DisplayRole).toInt());
584 QMessageBox::critical(
this,
"", tr(
"camera_id does not exist."));
585 table_widget_->blockSignals(
true);
586 item->setText(QString::number(
image.CameraId()));
587 table_widget_->blockSignals(
false);
589 image.SetCameraId(camera_id);
593 image.QvecPrior(0) = item->data(Qt::DisplayRole).toReal();
596 image.QvecPrior(1) = item->data(Qt::DisplayRole).toReal();
599 image.QvecPrior(2) = item->data(Qt::DisplayRole).toReal();
602 image.QvecPrior(3) = item->data(Qt::DisplayRole).toReal();
605 image.TvecPrior(0) = item->data(Qt::DisplayRole).toReal();
608 image.TvecPrior(1) = item->data(Qt::DisplayRole).toReal();
611 image.TvecPrior(2) = item->data(Qt::DisplayRole).toReal();
620 void ImageTab::ShowImage() {
621 QItemSelectionModel* select = table_widget_->selectionModel();
623 if (!select->hasSelection()) {
624 QMessageBox::critical(
this,
"", tr(
"No image selected."));
628 if (select->selectedRows().size() > 1) {
629 QMessageBox::critical(
this,
"", tr(
"Only one image may be selected."));
633 const auto&
image = images_[select->selectedRows().begin()->row()];
636 const std::vector<char> tri_mask(keypoints.size(),
false);
640 image_viewer_widget_->setWindowTitle(
644 void ImageTab::ShowMatches() {
645 QItemSelectionModel* select = table_widget_->selectionModel();
647 if (!select->hasSelection()) {
648 QMessageBox::critical(
this,
"", tr(
"No image selected."));
652 if (select->selectedRows().size() > 1) {
653 QMessageBox::critical(
this,
"", tr(
"Only one image may be selected."));
657 const auto&
image = images_[select->selectedRows().begin()->row()];
660 overlapping_images_widget_->show();
661 overlapping_images_widget_->raise();
664 void ImageTab::SetCamera() {
665 QItemSelectionModel* select = table_widget_->selectionModel();
667 if (!select->hasSelection()) {
668 QMessageBox::critical(
this,
"", tr(
"No image selected."));
674 QInputDialog::getInt(
this,
"", tr(
"camera_id"), 0, 0, INT_MAX, 1, &ok));
680 QMessageBox::critical(
this,
"", tr(
"camera_id does not exist."));
685 table_widget_->blockSignals(
true);
687 for (QModelIndex& index : select->selectedRows()) {
688 table_widget_->setItem(index.row(), 2,
689 new QTableWidgetItem(QString::number(camera_id)));
690 auto&
image = images_[index.row()];
691 image.SetCameraId(camera_id);
695 table_widget_->blockSignals(
false);
698 void ImageTab::SplitCamera() {
699 QItemSelectionModel* select = table_widget_->selectionModel();
701 if (!select->hasSelection()) {
702 QMessageBox::critical(
this,
"", tr(
"No image selected."));
708 QInputDialog::getInt(
this,
"", tr(
"camera_id"), 0, 0, INT_MAX, 1, &ok));
714 QMessageBox::critical(
this,
"", tr(
"camera_id does not exist."));
718 const auto camera = database_->
ReadCamera(camera_id);
721 table_widget_->blockSignals(
true);
723 for (QModelIndex& index : select->selectedRows()) {
724 auto&
image = images_[index.row()];
727 table_widget_->setItem(
729 new QTableWidgetItem(QString::number(
image.CameraId())));
732 table_widget_->blockSignals(
false);
739 : parent_(parent), options_(options) {
740 setWindowFlags(Qt::Window);
741 setWindowTitle(
"Database management");
742 resize(parent->size().width() - 20, parent->size().height() - 20);
744 QGridLayout* grid =
new QGridLayout(
this);
746 tab_widget_ =
new QTabWidget(
this);
748 camera_tab_ =
new CameraTab(
this, &database_);
749 image_tab_ =
new ImageTab(
this, camera_tab_, options_, &database_);
751 tab_widget_->addTab(image_tab_, tr(
"Images"));
752 tab_widget_->addTab(camera_tab_, tr(
"Cameras"));
754 grid->addWidget(tab_widget_, 0, 0, 1, 4);
756 QPushButton* clear_matches_button =
757 new QPushButton(tr(
"Clear Matches"),
this);
758 connect(clear_matches_button, &QPushButton::released,
this,
759 &DatabaseManagementWidget::ClearMatches);
760 grid->addWidget(clear_matches_button, 1, 0, Qt::AlignLeft);
762 QPushButton* clear_two_view_geometries_button =
763 new QPushButton(tr(
"Clear two-view geometries"),
this);
764 connect(clear_two_view_geometries_button, &QPushButton::released,
this,
765 &DatabaseManagementWidget::ClearTwoViewGeometries);
766 grid->addWidget(clear_two_view_geometries_button, 1, 1, Qt::AlignLeft);
768 grid->setColumnStretch(1, 1);
771 void DatabaseManagementWidget::showEvent(QShowEvent*) {
772 parent_->setDisabled(
true);
780 void DatabaseManagementWidget::hideEvent(QHideEvent*) {
781 parent_->setEnabled(
true);
784 camera_tab_->
Clear();
789 void DatabaseManagementWidget::ClearMatches() {
790 QMessageBox::StandardButton reply = QMessageBox::question(
791 this,
"", tr(
"Do you really want to clear all matches?"),
792 QMessageBox::Yes | QMessageBox::No);
793 if (reply == QMessageBox::No) {
799 void DatabaseManagementWidget::ClearTwoViewGeometries() {
800 QMessageBox::StandardButton reply = QMessageBox::question(
801 this,
"", tr(
"Do you really want to clear all two-view geometries?"),
802 QMessageBox::Yes | QMessageBox::No);
803 if (reply == QMessageBox::No) {
std::shared_ptr< core::Tensor > image
#define CAMERA_MODEL_CASES
CameraTab(QWidget *parent, Database *database)
void SetWidth(const size_t width)
void InitializeWithName(const std::string &model_name, const double focal_length, const size_t width, const size_t height)
void SetPriorFocalLength(const bool prior)
const std::vector< double > & Params() const
bool SetParamsFromString(const std::string &string)
camera_t CameraId() const
std::string ModelName() const
bool HasPriorFocalLength() const
void SetHeight(const size_t height)
FeatureMatches ReadMatches(const image_t image_id1, const image_t image_id2) const
bool ExistsMatches(const image_t image_id1, const image_t image_id2) const
FeatureKeypoints ReadKeypoints(const image_t image_id) const
size_t NumKeypoints() const
bool ExistsInlierMatches(const image_t image_id1, const image_t image_id2) const
std::vector< Camera > ReadAllCameras() const
bool ExistsCamera(const camera_t camera_id) const
void Open(const std::string &path)
void ClearTwoViewGeometries() const
void ClearMatches() const
void UpdateCamera(const Camera &camera) const
TwoViewGeometry ReadTwoViewGeometry(const image_t image_id1, const image_t image_id2) const
Camera ReadCamera(const camera_t camera_id) const
void UpdateImage(const Image &image) const
size_t NumCameras() const
std::vector< Image > ReadAllImages() const
camera_t WriteCamera(const Camera &camera, const bool use_camera_id=false) const
ImageTab(QWidget *parent, CameraTab *camera_tab, OptionManager *options, Database *database)
const std::string & Name() const
void Reload(const std::vector< Image > &images, const image_t image_id)
MatchesTab(QWidget *parent, OptionManager *options, Database *database)
std::shared_ptr< std::string > database_path
std::shared_ptr< std::string > image_path
TwoViewGeometriesTab(QWidget *parent, OptionManager *options, Database *database)
void Reload(const std::vector< Image > &images, const image_t image_id)
std::vector< int > configs_
void InitializeTable(const QStringList &table_header)
std::vector< size_t > sorted_matches_idxs_
QTableWidget * table_widget_
std::vector< std::pair< const Image *, FeatureMatches > > matches_
FeatureImageViewerWidget * matches_viewer_widget_
QTextStream & endl(QTextStream &stream)
const camera_t kInvalidCameraId
std::string JoinPaths(T const &... paths)
std::string VectorToCSV(const std::vector< T > &values)
std::string to_string(const T &n)