ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ReconstructionWidget.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "ReconstructionWidget.h"
9 
10 #include <ecvDisplayTools.h>
11 
12 #include "MainWindow.h"
14 #include "RenderOptionsWidget.h"
15 #include "ui/render_options.h"
16 #include "util/misc.h"
17 #include "util/version.h"
18 
19 namespace cloudViewer {
20 
21 using namespace colmap;
22 
24  : QWidget(ecvDisplayTools::GetMainScreen()),
25  app_(app),
26  thread_control_widget_(new ThreadControlWidget(this)),
27  statusbar_timer_label_(nullptr) {
28  CreateWidgets();
29  CreateActions();
30  CreateMenus();
31  CreateToolbar();
32  CreateStatusbar();
33  CreateControllers();
34  options_.AddAllOptions();
35 
36  // CloudViewer default: use ORTHOGRAPHIC projection (colmap default is
37  // PERSPECTIVE)
38  options_.render->projection_type =
39  colmap::RenderOptions::ProjectionType::ORTHOGRAPHIC;
40 
41  hideLog();
43 }
44 
46  QSettings settings;
47  settings.beginGroup("Reconstruction");
48 
49  // import path
50  std::string import_path =
51  CVTools::FromQString(settings.value("import_path", "").toString());
52 
53  // project path
54  std::string project_path =
55  CVTools::FromQString(settings.value("project_path", "").toString());
56  if (!import_path.empty() && project_path.empty()) {
57  project_path = JoinPaths(import_path, "project.ini");
58  }
59 
60  if (project_path != "") {
61  // Only try to read the configuration file if it exists
62  if (ExistsFile(project_path)) {
63  if (options_.ReRead(project_path)) {
64  *options_.project_path = project_path;
65  project_widget_->SetDatabasePath(*options_.database_path);
66  project_widget_->SetImagePath(*options_.image_path);
67  } else {
68  std::string database_path = CVTools::FromQString(
69  settings.value("database_path", "").toString());
70  std::string image_path = CVTools::FromQString(
71  settings.value("image_path", "").toString());
72  if (!database_path.empty() && !image_path.empty()) {
73  *options_.project_path = project_path;
74  *options_.database_path = database_path;
75  *options_.image_path = image_path;
76  project_widget_->SetDatabasePath(database_path);
77  project_widget_->SetImagePath(image_path);
78  } else {
79  ShowInvalidProjectError();
80  }
81  }
82  } else {
83  // Configuration file doesn't exist, try to use saved database and
84  // image paths
85  std::string database_path = CVTools::FromQString(
86  settings.value("database_path", "").toString());
87  std::string image_path = CVTools::FromQString(
88  settings.value("image_path", "").toString());
89  if (!database_path.empty() && !image_path.empty()) {
90  *options_.project_path = project_path;
91  *options_.database_path = database_path;
92  *options_.image_path = image_path;
93  project_widget_->SetDatabasePath(database_path);
94  project_widget_->SetImagePath(image_path);
95  } else {
96  ShowInvalidProjectError();
97  }
98  }
99  }
100 
101  settings.endGroup();
102 }
103 
105  const size_t idx = reconstruction_manager_.Read(path);
106  reconstruction_manager_widget_->Update();
107  reconstruction_manager_widget_->SelectReconstruction(idx);
108  RenderNow();
109 }
110 
112  if (project_widget_->IsValid() && *options_.project_path == "") {
113  // Project was created, but not yet saved
114  QMessageBox::StandardButton reply;
115  reply = QMessageBox::question(
116  this, "",
117  tr("You have not saved your reconstruction project. Do you "
118  "want to save it?"),
119  QMessageBox::Yes | QMessageBox::No);
120  if (reply == QMessageBox::Yes) {
121  ProjectSave();
122  }
123  }
124 
125  if (mapper_controller_) {
126  mapper_controller_->Stop();
127  mapper_controller_->Wait();
128  }
129 
130  log_widget_->hide();
131  log_widget_->close();
132 }
133 
135  if (model_viewer_widget_) {
136  model_viewer_widget_->Release();
137  }
138  this->close();
139 }
140 
141 void ReconstructionWidget::CreateWidgets() {
142  model_viewer_widget_ = new ModelViewerWidget(this, &options_, app_);
143 
144  project_widget_ = new ProjectWidget(this, &options_);
145  project_widget_->SetDatabasePath(*options_.database_path);
146  project_widget_->SetImagePath(*options_.image_path);
147 
148  feature_extraction_widget_ = new FeatureExtractionWidget(this, &options_);
149  feature_matching_widget_ = new FeatureMatchingWidget(this, &options_);
150  database_management_widget_ = new DatabaseManagementWidget(this, &options_);
151  automatic_reconstruction_widget_ = new AutomaticReconstructionWidget(this);
152  reconstruction_options_widget_ =
153  new ReconstructionOptionsWidget(this, &options_);
154  bundle_adjustment_widget_ = new BundleAdjustmentWidget(this, &options_);
155  dense_reconstruction_widget_ =
156  new DenseReconstructionWidget(this, &options_);
157  render_options_widget_ =
158  new RenderOptionsWidget(this, &options_, model_viewer_widget_);
159  log_widget_ = new LogWidget(this);
160  undistortion_widget_ = new UndistortionWidget(this, &options_);
161  reconstruction_manager_widget_ =
162  new ReconstructionManagerWidget(this, &reconstruction_manager_);
163  reconstruction_stats_widget_ = new ReconstructionStatsWidget(this);
164  match_matrix_widget_ = new MatchMatrixWidget(this, &options_);
165 
166  dock_log_widget_ = new QDockWidget("Log", this);
167  dock_log_widget_->setWidget(log_widget_);
168 }
169 
170 void ReconstructionWidget::CreateActions() {
172  // File actions
174 
175  action_project_new_ = new QAction(QIcon(":/media/project-new.png"),
176  tr("New project"), this);
177  // action_project_new_->setShortcuts(QKeySequence::New);
178  connect(action_project_new_, &QAction::triggered, this,
179  &ReconstructionWidget::ProjectNew);
180 
181  action_project_open_ = new QAction(QIcon(":/media/project-open.png"),
182  tr("Open project"), this);
183  // action_project_open_->setShortcuts(QKeySequence::Open);
184  connect(action_project_open_, &QAction::triggered, this,
185  &ReconstructionWidget::ProjectOpen);
186 
187  action_project_edit_ = new QAction(QIcon(":/media/project-edit.png"),
188  tr("Edit project"), this);
189  connect(action_project_edit_, &QAction::triggered, this,
190  &ReconstructionWidget::ProjectEdit);
191 
192  action_project_save_ = new QAction(QIcon(":/media/project-save.png"),
193  tr("Save project"), this);
194  // action_project_save_->setShortcuts(QKeySequence::Save);
195  connect(action_project_save_, &QAction::triggered, this,
196  &ReconstructionWidget::ProjectSave);
197 
198  action_project_save_as_ = new QAction(QIcon(":/media/project-save-as.png"),
199  tr("Save project as..."), this);
200  // action_project_save_as_->setShortcuts(QKeySequence::SaveAs);
201  connect(action_project_save_as_, &QAction::triggered, this,
202  &ReconstructionWidget::ProjectSaveAs);
203 
204  action_import_ =
205  new QAction(QIcon(":/media/import.png"), tr("Import model"), this);
206  connect(action_import_, &QAction::triggered, this,
207  &ReconstructionWidget::Import);
208  blocking_actions_.push_back(action_import_);
209 
210  action_import_from_ = new QAction(QIcon(":/media/import-from.png"),
211  tr("Import model from..."), this);
212  connect(action_import_from_, &QAction::triggered, this,
213  &ReconstructionWidget::ImportFrom);
214  blocking_actions_.push_back(action_import_from_);
215 
216  action_export_ =
217  new QAction(QIcon(":/media/export.png"), tr("Export model"), this);
218  connect(action_export_, &QAction::triggered, this,
219  &ReconstructionWidget::Export);
220  blocking_actions_.push_back(action_export_);
221 
222  action_export_all_ = new QAction(QIcon(":/media/export-all.png"),
223  tr("Export all models"), this);
224  connect(action_export_all_, &QAction::triggered, this,
225  &ReconstructionWidget::ExportAll);
226  blocking_actions_.push_back(action_export_all_);
227 
228  action_export_as_ = new QAction(QIcon(":/media/export-as.png"),
229  tr("Export model as..."), this);
230  connect(action_export_as_, &QAction::triggered, this,
231  &ReconstructionWidget::ExportAs);
232  blocking_actions_.push_back(action_export_as_);
233 
234  action_export_as_text_ = new QAction(QIcon(":/media/export-as-text.png"),
235  tr("Export model as text"), this);
236  connect(action_export_as_text_, &QAction::triggered, this,
237  &ReconstructionWidget::ExportAsText);
238  blocking_actions_.push_back(action_export_as_text_);
239 
240  action_quit_ = new QAction(tr("Quit"), this);
241  connect(action_quit_, &QAction::triggered, this,
243 
245  // Processing action
247 
248  action_feature_extraction_ =
249  new QAction(QIcon(":/media/feature-extraction.png"),
250  tr("Feature extraction"), this);
251  connect(action_feature_extraction_, &QAction::triggered, this,
252  &ReconstructionWidget::FeatureExtraction);
253  blocking_actions_.push_back(action_feature_extraction_);
254 
255  action_feature_matching_ =
256  new QAction(QIcon(":/media/feature-matching.png"),
257  tr("Feature matching"), this);
258  connect(action_feature_matching_, &QAction::triggered, this,
259  &ReconstructionWidget::FeatureMatching);
260  blocking_actions_.push_back(action_feature_matching_);
261 
262  action_database_management_ =
263  new QAction(QIcon(":/media/database-management.png"),
264  tr("Database management"), this);
265  connect(action_database_management_, &QAction::triggered, this,
266  &ReconstructionWidget::DatabaseManagement);
267  blocking_actions_.push_back(action_database_management_);
268 
270  // Reconstruction actions
272 
273  action_automatic_reconstruction_ =
274  new QAction(QIcon(":/media/automatic-reconstruction.png"),
275  tr("Automatic reconstruction"), this);
276  connect(action_automatic_reconstruction_, &QAction::triggered, this,
277  &ReconstructionWidget::AutomaticReconstruction);
278 
279  action_reconstruction_start_ =
280  new QAction(QIcon(":/media/reconstruction-start.png"),
281  tr("Start reconstruction"), this);
282  connect(action_reconstruction_start_, &QAction::triggered, this,
283  &ReconstructionWidget::ReconstructionStart);
284  blocking_actions_.push_back(action_reconstruction_start_);
285 
286  action_reconstruction_step_ =
287  new QAction(QIcon(":/media/reconstruction-step.png"),
288  tr("Reconstruct next image"), this);
289  connect(action_reconstruction_step_, &QAction::triggered, this,
290  &ReconstructionWidget::ReconstructionStep);
291  blocking_actions_.push_back(action_reconstruction_step_);
292 
293  action_reconstruction_pause_ =
294  new QAction(QIcon(":/media/reconstruction-pause.png"),
295  tr("Pause reconstruction"), this);
296  connect(action_reconstruction_pause_, &QAction::triggered, this,
297  &ReconstructionWidget::ReconstructionPause);
298  action_reconstruction_pause_->setEnabled(false);
299  blocking_actions_.push_back(action_reconstruction_pause_);
300 
301  action_reconstruction_reset_ =
302  new QAction(QIcon(":/media/reconstruction-reset.png"),
303  tr("Reset reconstruction"), this);
304  connect(action_reconstruction_reset_, &QAction::triggered, this,
305  &ReconstructionWidget::ReconstructionOverwrite);
306 
307  action_reconstruction_normalize_ =
308  new QAction(QIcon(":/media/reconstruction-normalize.png"),
309  tr("Normalize reconstruction"), this);
310  connect(action_reconstruction_normalize_, &QAction::triggered, this,
311  &ReconstructionWidget::ReconstructionNormalize);
312  blocking_actions_.push_back(action_reconstruction_normalize_);
313 
314  action_reconstruction_options_ =
315  new QAction(QIcon(":/media/reconstruction-options.png"),
316  tr("Reconstruction options"), this);
317  connect(action_reconstruction_options_, &QAction::triggered, this,
318  &ReconstructionWidget::ReconstructionOptions);
319  blocking_actions_.push_back(action_reconstruction_options_);
320 
321  action_bundle_adjustment_ =
322  new QAction(QIcon(":/media/bundle-adjustment.png"),
323  tr("Bundle adjustment"), this);
324  connect(action_bundle_adjustment_, &QAction::triggered, this,
325  &ReconstructionWidget::BundleAdjustment);
326  action_bundle_adjustment_->setEnabled(false);
327  blocking_actions_.push_back(action_bundle_adjustment_);
328 
329  action_dense_reconstruction_ =
330  new QAction(QIcon(":/media/dense-reconstruction.png"),
331  tr("Dense reconstruction"), this);
332  connect(action_dense_reconstruction_, &QAction::triggered, this,
333  &ReconstructionWidget::DenseReconstruction);
334 
336  // Render actions
338 
339  action_render_toggle_ = new QAction(QIcon(":/media/render-enabled.png"),
340  tr("Disable rendering"), this);
341  connect(action_render_toggle_, &QAction::triggered, this,
342  &ReconstructionWidget::RenderToggle);
343 
344  action_render_reset_view_ = new QAction(
345  QIcon(":/media/render-reset-view.png"), tr("Reset view"), this);
346  connect(action_render_reset_view_, &QAction::triggered,
347  model_viewer_widget_, &ModelViewerWidget::ResetView);
348 
349  action_render_options_ = new QAction(QIcon(":/media/render-options.png"),
350  tr("Render options"), this);
351  connect(action_render_options_, &QAction::triggered, this,
352  &ReconstructionWidget::RenderOptions);
353 
354  connect(reconstruction_manager_widget_,
355  static_cast<void (QComboBox::*)(int)>(
356  &QComboBox::currentIndexChanged),
357  this, &ReconstructionWidget::SelectReconstructionIdx);
358 
360  // Extras actions
362 
363  action_reconstruction_stats_ =
364  new QAction(QIcon(":/media/reconstruction-stats.png"),
365  tr("Show model statistics"), this);
366  connect(action_reconstruction_stats_, &QAction::triggered, this,
367  &ReconstructionWidget::ReconstructionStats);
368 
369  action_match_matrix_ = new QAction(QIcon(":/media/match-matrix.png"),
370  tr("Show match matrix"), this);
371  connect(action_match_matrix_, &QAction::triggered, this,
372  &ReconstructionWidget::MatchMatrix);
373 
374  action_log_show_ =
375  new QAction(QIcon(":/media/log.png"), tr("Show log"), this);
376  connect(action_log_show_, &QAction::triggered, this,
378 
379  action_grab_image_ = new QAction(QIcon(":/media/grab-image.png"),
380  tr("Grab image"), this);
381  connect(action_grab_image_, &QAction::triggered, this,
382  &ReconstructionWidget::GrabImage);
383 
384  action_grab_movie_ = new QAction(QIcon(":/media/grab-movie.png"),
385  tr("Grab movie"), this);
386  connect(action_grab_movie_, &QAction::triggered, model_viewer_widget_,
388 
389  action_undistort_ = new QAction(QIcon(":/media/undistort.png"),
390  tr("Undistortion"), this);
391  connect(action_undistort_, &QAction::triggered, this,
392  &ReconstructionWidget::UndistortImages);
393  blocking_actions_.push_back(action_undistort_);
394 
395  action_extract_colors_ = new QAction(tr("Extract colors"), this);
396  connect(action_extract_colors_, &QAction::triggered, this,
397  &ReconstructionWidget::ExtractColors);
398 
399  action_set_options_ = new QAction(tr("Set options for ..."), this);
400  connect(action_set_options_, &QAction::triggered, this,
401  &ReconstructionWidget::SetOptions);
402 
403  action_reset_options_ = new QAction(tr("Set default options"), this);
404  connect(action_reset_options_, &QAction::triggered, this,
405  &ReconstructionWidget::ResetOptions);
406 
408  // Misc actions
410 
411  action_render_ = new QAction(tr("Render"), this);
412  connect(action_render_, &QAction::triggered, this,
413  &ReconstructionWidget::Render, Qt::BlockingQueuedConnection);
414 
415  action_render_now_ = new QAction(tr("Render now"), this);
416  connect(action_render_now_, &QAction::triggered, this,
417  &ReconstructionWidget::RenderNow, Qt::BlockingQueuedConnection);
418 
419  action_reconstruction_finish_ =
420  new QAction(tr("Finish reconstruction"), this);
421  connect(action_reconstruction_finish_, &QAction::triggered, this,
422  &ReconstructionWidget::ReconstructionFinish,
423  Qt::BlockingQueuedConnection);
424 }
425 
426 void ReconstructionWidget::CreateMenus() {
427  QMenu* file_menu = new QMenu(tr("ProjectFile"), this);
428  file_menu->addAction(action_project_new_);
429  file_menu->addAction(action_project_open_);
430  file_menu->addAction(action_project_edit_);
431  file_menu->addAction(action_project_save_);
432  file_menu->addAction(action_project_save_as_);
433  file_menu->addSeparator();
434  file_menu->addAction(action_import_);
435  file_menu->addAction(action_import_from_);
436  file_menu->addSeparator();
437  file_menu->addAction(action_export_);
438  file_menu->addAction(action_export_all_);
439  file_menu->addAction(action_export_as_);
440  file_menu->addAction(action_export_as_text_);
441  file_menu->addSeparator();
442  file_menu->addAction(action_quit_);
443  menus_list_.push_back(file_menu);
444 
445  QMenu* preprocessing_menu = new QMenu(tr("Processing"), this);
446  preprocessing_menu->addAction(action_feature_extraction_);
447  preprocessing_menu->addAction(action_feature_matching_);
448  preprocessing_menu->addAction(action_database_management_);
449  menus_list_.push_back(preprocessing_menu);
450 
451  QMenu* reconstruction_menu = new QMenu(tr("Reconstruction"), this);
452  reconstruction_menu->addAction(action_automatic_reconstruction_);
453  reconstruction_menu->addSeparator();
454  reconstruction_menu->addAction(action_reconstruction_start_);
455  reconstruction_menu->addAction(action_reconstruction_pause_);
456  reconstruction_menu->addAction(action_reconstruction_step_);
457  reconstruction_menu->addSeparator();
458  reconstruction_menu->addAction(action_reconstruction_reset_);
459  reconstruction_menu->addAction(action_reconstruction_normalize_);
460  reconstruction_menu->addAction(action_reconstruction_options_);
461  reconstruction_menu->addSeparator();
462  reconstruction_menu->addAction(action_bundle_adjustment_);
463  reconstruction_menu->addAction(action_dense_reconstruction_);
464  menus_list_.push_back(reconstruction_menu);
465 
466  QMenu* render_menu = new QMenu(tr("Render"), this);
467  render_menu->addAction(action_render_toggle_);
468  render_menu->addAction(action_render_reset_view_);
469  render_menu->addAction(action_render_options_);
470  menus_list_.push_back(render_menu);
471 
472  QMenu* extras_menu = new QMenu(tr("Extras"), this);
473  extras_menu->addAction(action_log_show_);
474  extras_menu->addAction(action_match_matrix_);
475  extras_menu->addAction(action_reconstruction_stats_);
476  extras_menu->addSeparator();
477  extras_menu->addAction(action_grab_image_);
478  extras_menu->addAction(action_grab_movie_);
479  extras_menu->addSeparator();
480  extras_menu->addAction(action_undistort_);
481  extras_menu->addAction(action_extract_colors_);
482  extras_menu->addSeparator();
483  extras_menu->addAction(action_set_options_);
484  extras_menu->addAction(action_reset_options_);
485  menus_list_.push_back(extras_menu);
486 }
487 
488 void ReconstructionWidget::CreateToolbar() {
489  reconstruction_toolbar_ = new QToolBar(tr("Reconstruction"), this);
490  reconstruction_toolbar_->setObjectName(QString::fromUtf8("Reconstruction"));
491  reconstruction_toolbar_->addAction(action_project_new_);
492  reconstruction_toolbar_->addAction(action_project_open_);
493  reconstruction_toolbar_->addAction(action_project_edit_);
494  reconstruction_toolbar_->addAction(action_project_save_);
495  reconstruction_toolbar_->addAction(action_import_);
496  reconstruction_toolbar_->addAction(action_export_);
497  reconstruction_toolbar_->addAction(action_feature_extraction_);
498  reconstruction_toolbar_->addAction(action_feature_matching_);
499  reconstruction_toolbar_->addAction(action_database_management_);
500  reconstruction_toolbar_->addAction(action_automatic_reconstruction_);
501  reconstruction_toolbar_->addAction(action_reconstruction_start_);
502  reconstruction_toolbar_->addAction(action_reconstruction_step_);
503  reconstruction_toolbar_->addAction(action_reconstruction_pause_);
504  reconstruction_toolbar_->addAction(action_reconstruction_reset_);
505  reconstruction_toolbar_->addAction(action_reconstruction_normalize_);
506  reconstruction_toolbar_->addAction(action_reconstruction_options_);
507  reconstruction_toolbar_->addAction(action_bundle_adjustment_);
508  reconstruction_toolbar_->addAction(action_dense_reconstruction_);
509  reconstruction_toolbar_->addAction(action_render_toggle_);
510  reconstruction_toolbar_->addAction(action_render_reset_view_);
511  reconstruction_toolbar_->addAction(action_render_options_);
512  reconstruction_toolbar_->addWidget(reconstruction_manager_widget_);
513  reconstruction_toolbar_->addAction(action_log_show_);
514  reconstruction_toolbar_->addAction(action_match_matrix_);
515  reconstruction_toolbar_->addAction(action_reconstruction_stats_);
516  reconstruction_toolbar_->addAction(action_grab_image_);
517  reconstruction_toolbar_->addAction(action_grab_movie_);
518  // Icon size will be set by MainWindow::setupDefaultLayout() based on screen
519  // resolution Don't set a fixed small size here
520  toolbar_list_.push_back(reconstruction_toolbar_);
521 }
522 
523 void ReconstructionWidget::CreateStatusbar() {
524  QFont font;
525  font.setPointSize(11);
526 
527  statusbar_timer_label_ = new QLabel("Time 00:00:00:00", this);
528  statusbar_timer_label_->setFont(font);
529  statusbar_timer_label_->setAlignment(Qt::AlignCenter);
530  statusbar_timer_ = new QTimer(this);
531  connect(statusbar_timer_, &QTimer::timeout, this,
532  &ReconstructionWidget::UpdateTimer);
533  statusbar_timer_->start(1000);
534 
535  model_viewer_widget_->statusbar_status_label =
536  new QLabel("0 Images - 0 Points", this);
537  model_viewer_widget_->statusbar_status_label->setFont(font);
538  model_viewer_widget_->statusbar_status_label->setAlignment(Qt::AlignCenter);
539 }
540 
541 void ReconstructionWidget::CreateControllers() {
542  if (mapper_controller_) {
543  mapper_controller_->Stop();
544  mapper_controller_->Wait();
545  }
546 
547  mapper_controller_.reset(new IncrementalMapperController(
548  options_.mapper.get(), *options_.image_path,
549  *options_.database_path, &reconstruction_manager_));
550  mapper_controller_->AddCallback(
551  IncrementalMapperController::INITIAL_IMAGE_PAIR_REG_CALLBACK,
552  [this]() {
553  if (!mapper_controller_->IsStopped()) {
554  action_render_now_->trigger();
555  }
556  });
557  mapper_controller_->AddCallback(
558  IncrementalMapperController::NEXT_IMAGE_REG_CALLBACK, [this]() {
559  if (!mapper_controller_->IsStopped()) {
560  action_render_->trigger();
561  }
562  });
563  mapper_controller_->AddCallback(
564  IncrementalMapperController::LAST_IMAGE_REG_CALLBACK, [this]() {
565  if (!mapper_controller_->IsStopped()) {
566  action_render_now_->trigger();
567  }
568  });
569  mapper_controller_->AddCallback(
570  IncrementalMapperController::FINISHED_CALLBACK, [this]() {
571  if (!mapper_controller_->IsStopped()) {
572  action_render_now_->trigger();
573  action_reconstruction_finish_->trigger();
574  }
575  if (reconstruction_manager_.Size() == 0) {
576  action_reconstruction_reset_->trigger();
577  }
578  });
579 }
580 
581 void ReconstructionWidget::ProjectNew() {
582  if (ReconstructionOverwrite()) {
583  project_widget_->Reset();
584  project_widget_->show();
585  project_widget_->raise();
586  }
587 }
588 
589 bool ReconstructionWidget::ProjectOpen() {
590  if (!ReconstructionOverwrite()) {
591  return false;
592  }
593 
594  QSettings settings;
595  settings.beginGroup("Reconstruction");
596  QString last_project_path = settings.value("project_path", "").toString();
597  settings.endGroup();
598 
599  const std::string project_path =
600  QFileDialog::getOpenFileName(
601  this, tr("Select project file"),
602  QFileInfo(last_project_path).dir().absolutePath(),
603  tr("Project file (*.ini)"))
604  .toUtf8()
605  .constData();
606  // If selection not canceled
607  if (project_path != "") {
608  if (options_.ReRead(project_path)) {
609  *options_.project_path = project_path;
610  project_widget_->SetDatabasePath(*options_.database_path);
611  project_widget_->SetImagePath(*options_.image_path);
612 
613  project_widget_->persistSave(*options_.project_path,
614  *options_.database_path,
615  *options_.image_path);
616  return true;
617  } else {
618  ShowInvalidProjectError();
619  }
620  }
621 
622  return false;
623 }
624 
625 void ReconstructionWidget::ProjectEdit() {
626  project_widget_->show();
627  project_widget_->raise();
628 }
629 
630 void ReconstructionWidget::ProjectSave() {
631  if (!ExistsFile(*options_.project_path)) {
632  QSettings settings;
633  settings.beginGroup("Reconstruction");
634  QString last_project_path =
635  settings.value("project_path", "").toString();
636  settings.endGroup();
637 
638  std::string project_path =
639  QFileDialog::getSaveFileName(
640  this, tr("Select project file"),
641  QFileInfo(last_project_path).dir().absolutePath(),
642  tr("Project file (*.ini)"))
643  .toUtf8()
644  .constData();
645  // If selection not canceled
646  if (project_path != "") {
647  if (!HasFileExtension(project_path, ".ini")) {
648  project_path += ".ini";
649  }
650  *options_.project_path = project_path;
651  options_.Write(*options_.project_path);
652  }
653  } else {
654  // Project path was chosen previously, either here or via command-line.
655  options_.Write(*options_.project_path);
656  }
657 
658  if (ExistsFile(*options_.project_path)) {
659  project_widget_->persistSave(*options_.project_path,
660  *options_.database_path,
661  *options_.image_path);
662  }
663 }
664 
665 void ReconstructionWidget::ProjectSaveAs() {
666  QSettings settings;
667  settings.beginGroup("Reconstruction");
668  QString last_project_path = settings.value("project_path", "").toString();
669 
670  const std::string new_project_path =
671  QFileDialog::getSaveFileName(
672  this, tr("Select project file"),
673  QFileInfo(last_project_path).dir().absolutePath(),
674  tr("Project file (*.ini)"))
675  .toUtf8()
676  .constData();
677  if (new_project_path != "") {
678  *options_.project_path = new_project_path;
679  options_.Write(*options_.project_path);
680 
681  project_widget_->persistSave(*options_.project_path,
682  *options_.database_path,
683  *options_.image_path);
684  }
685 
686  settings.endGroup();
687 }
688 
689 void ReconstructionWidget::Import() {
690  QSettings settings;
691  settings.beginGroup("Reconstruction");
692  QString last_import_path = settings.value("import_path", "").toString();
693 
694  const std::string import_path =
695  QFileDialog::getExistingDirectory(this, tr("Select source..."),
696  last_import_path,
697  QFileDialog::ShowDirsOnly)
698  .toUtf8()
699  .constData();
700 
701  // Selection canceled?
702  if (import_path == "") {
703  settings.endGroup();
704  return;
705  }
706 
707  const std::string project_path = JoinPaths(import_path, "project.ini");
708  const std::string cameras_bin_path = JoinPaths(import_path, "cameras.bin");
709  const std::string images_bin_path = JoinPaths(import_path, "images.bin");
710  const std::string points3D_bin_path =
711  JoinPaths(import_path, "points3D.bin");
712  const std::string cameras_txt_path = JoinPaths(import_path, "cameras.txt");
713  const std::string images_txt_path = JoinPaths(import_path, "images.txt");
714  const std::string points3D_txt_path =
715  JoinPaths(import_path, "points3D.txt");
716 
717  if ((!ExistsFile(cameras_bin_path) || !ExistsFile(images_bin_path) ||
718  !ExistsFile(points3D_bin_path)) &&
719  (!ExistsFile(cameras_txt_path) || !ExistsFile(images_txt_path) ||
720  !ExistsFile(points3D_txt_path))) {
721  QMessageBox::critical(
722  this, "",
723  tr("cameras, images, and points3D files do not exist "
724  "in chosen directory."));
725  settings.endGroup();
726  return;
727  }
728 
729  settings.setValue("import_path", CVTools::ToQString(import_path));
730  settings.setValue("project_path", CVTools::ToQString(project_path));
731  settings.setValue("cameras_path", CVTools::ToQString(cameras_bin_path));
732  settings.setValue("images_path", CVTools::ToQString(images_bin_path));
733  settings.setValue("points3D_path", CVTools::ToQString(points3D_bin_path));
734  settings.endGroup();
735 
736  if (!ReconstructionOverwrite()) {
737  return;
738  }
739 
740  bool edit_project = false;
741  if (ExistsFile(project_path)) {
742  options_.ReRead(project_path);
743  } else {
744  QMessageBox::StandardButton reply = QMessageBox::question(
745  this, "",
746  tr("Directory does not contain a <i>project.ini</i>. To "
747  "resume the reconstruction, you need to specify a valid "
748  "database and image path. Do you want to select the paths "
749  "now (or press <i>No</i> to only visualize the "
750  "reconstruction)?"),
751  QMessageBox::Yes | QMessageBox::No);
752  if (reply == QMessageBox::Yes) {
753  edit_project = true;
754  }
755  }
756 
757  thread_control_widget_->StartFunction(
758  "Importing...", [this, import_path, edit_project]() {
759  const size_t idx = reconstruction_manager_.Read(import_path);
760  reconstruction_manager_widget_->Update();
761  reconstruction_manager_widget_->SelectReconstruction(idx);
762  action_bundle_adjustment_->setEnabled(true);
763  action_render_now_->trigger();
764  if (edit_project) {
765  action_project_edit_->trigger();
766  }
767  });
768 }
769 
770 void ReconstructionWidget::ImportFrom() {
771  QSettings settings;
772  settings.beginGroup("Reconstruction");
773  QString last_model_import_path =
774  settings.value("model_import_path", "").toString();
775 
776  const std::string import_path =
777  QFileDialog::getOpenFileName(this, tr("Select source..."),
778  last_model_import_path)
779  .toUtf8()
780  .constData();
781 
782  // Selection canceled?
783  if (import_path == "") {
784  settings.endGroup();
785  return;
786  }
787 
788  if (!ExistsFile(import_path)) {
789  QMessageBox::critical(this, "", tr("Invalid file"));
790  settings.endGroup();
791  return;
792  }
793 
794  if (!HasFileExtension(import_path, ".ply")) {
795  QMessageBox::critical(
796  this, "", tr("Invalid file format (supported formats: PLY)"));
797  settings.endGroup();
798  return;
799  }
800 
801  settings.setValue("model_import_path", CVTools::ToQString(import_path));
802  settings.endGroup();
803 
804  thread_control_widget_->StartFunction("Importing...", [this,
805  import_path]() {
806  const size_t reconstruction_idx = reconstruction_manager_.Add();
807  reconstruction_manager_.Get(reconstruction_idx).ImportPLY(import_path);
808  options_.render->min_track_len = 0;
809  reconstruction_manager_widget_->Update();
810  reconstruction_manager_widget_->SelectReconstruction(
811  reconstruction_idx);
812  action_render_now_->trigger();
813  });
814 }
815 
816 void ReconstructionWidget::Export() {
817  if (!IsSelectedReconstructionValid()) {
818  return;
819  }
820 
821  QSettings settings;
822  settings.beginGroup("Reconstruction");
823  QString last_export_path = settings.value("export_path", "").toString();
824 
825  const std::string export_path =
826  QFileDialog::getExistingDirectory(this, tr("Select destination..."),
827  last_export_path,
828  QFileDialog::ShowDirsOnly)
829  .toUtf8()
830  .constData();
831 
832  // Selection canceled?
833  if (export_path == "") {
834  settings.endGroup();
835  return;
836  }
837 
838  const std::string cameras_name = "cameras.bin";
839  const std::string images_name = "images.bin";
840  const std::string points3D_name = "points3D.bin";
841 
842  const std::string project_path = JoinPaths(export_path, "project.ini");
843  const std::string cameras_path = JoinPaths(export_path, cameras_name);
844  const std::string images_path = JoinPaths(export_path, images_name);
845  const std::string points3D_path = JoinPaths(export_path, points3D_name);
846 
847  settings.setValue("project_path", CVTools::ToQString(project_path));
848  settings.setValue("export_path", CVTools::ToQString(export_path));
849  settings.setValue("cameras_path", CVTools::ToQString(cameras_path));
850  settings.setValue("images_path", CVTools::ToQString(images_path));
851  settings.setValue("points3D_path", CVTools::ToQString(points3D_path));
852  settings.endGroup();
853 
854  if (ExistsFile(cameras_path) || ExistsFile(images_path) ||
855  ExistsFile(points3D_path)) {
856  QMessageBox::StandardButton reply = QMessageBox::question(
857  this, "",
858  StringPrintf(
859  "The files <i>%s</i>, <i>%s</i>, or <i>%s</i> already "
860  "exist in the selected destination. Do you want to "
861  "overwrite them?",
862  cameras_name.c_str(), images_name.c_str(),
863  points3D_name.c_str())
864  .c_str(),
865  QMessageBox::Yes | QMessageBox::No);
866  if (reply == QMessageBox::No) {
867  return;
868  }
869  }
870 
871  thread_control_widget_->StartFunction("Exporting...", [this, export_path,
872  project_path]() {
873  const auto& reconstruction =
874  reconstruction_manager_.Get(SelectedReconstructionIdx());
875  reconstruction.WriteBinary(export_path);
876  options_.Write(project_path);
877  });
878 }
879 
880 void ReconstructionWidget::ExportAll() {
881  if (!IsSelectedReconstructionValid()) {
882  return;
883  }
884 
885  QSettings settings;
886  settings.beginGroup("Reconstruction");
887  QString last_export_path = settings.value("export_path", "").toString();
888 
889  const std::string export_path =
890  QFileDialog::getExistingDirectory(this, tr("Select destination..."),
891  last_export_path,
892  QFileDialog::ShowDirsOnly)
893  .toUtf8()
894  .constData();
895 
896  // Selection canceled?
897  if (export_path == "") {
898  settings.endGroup();
899  return;
900  } else {
901  settings.setValue("export_path", CVTools::ToQString(export_path));
902  settings.endGroup();
903 
904  thread_control_widget_->StartFunction(
905  "Exporting...", [this, export_path]() {
906  reconstruction_manager_.Write(export_path, &options_);
907  });
908  }
909 }
910 
911 void ReconstructionWidget::ExportAs() {
912  if (!IsSelectedReconstructionValid()) {
913  return;
914  }
915 
916  QSettings settings;
917  settings.beginGroup("Reconstruction");
918  QString last_export_path =
919  settings.value("model_export_path", "").toString();
920 
921  QString filter("NVM (*.nvm)");
922  const std::string export_path =
923  QFileDialog::getSaveFileName(
924  this, tr("Select destination..."), last_export_path,
925  "NVM (*.nvm);;Bundler (*.out);;PLY (*.ply);;VRML (*.wrl)",
926  &filter)
927  .toUtf8()
928  .constData();
929 
930  // Selection canceled?
931  if (export_path == "") {
932  settings.endGroup();
933  return;
934  }
935 
936  settings.setValue("model_export_path", CVTools::ToQString(export_path));
937  settings.endGroup();
938 
939  thread_control_widget_->StartFunction("Exporting...", [this, export_path,
940  filter]() {
941  const Reconstruction& reconstruction =
942  reconstruction_manager_.Get(SelectedReconstructionIdx());
943  if (filter == "NVM (*.nvm)") {
944  reconstruction.ExportNVM(export_path);
945  } else if (filter == "Bundler (*.out)") {
946  reconstruction.ExportBundler(export_path,
947  export_path + ".list.txt");
948  } else if (filter == "PLY (*.ply)") {
949  reconstruction.ExportPLY(export_path);
950  } else if (filter == "VRML (*.wrl)") {
951  const auto base_path =
952  export_path.substr(0, export_path.find_last_of("."));
953  reconstruction.ExportVRML(base_path + ".images.wrl",
954  base_path + ".points3D.wrl", 1,
955  Eigen::Vector3d(1, 0, 0));
956  }
957  });
958 }
959 
960 void ReconstructionWidget::ExportAsText() {
961  if (!IsSelectedReconstructionValid()) {
962  return;
963  }
964 
965  QSettings settings;
966  settings.beginGroup("Reconstruction");
967  QString last_export_path = settings.value("export_path", "").toString();
968 
969  const std::string export_path =
970  QFileDialog::getExistingDirectory(this, tr("Select destination..."),
971  last_export_path,
972  QFileDialog::ShowDirsOnly)
973  .toUtf8()
974  .constData();
975 
976  // Selection canceled?
977  if (export_path == "") {
978  settings.endGroup();
979  return;
980  }
981 
982  const std::string cameras_name = "cameras.txt";
983  const std::string images_name = "images.txt";
984  const std::string points3D_name = "points3D.txt";
985 
986  const std::string project_path = JoinPaths(export_path, "project.ini");
987  const std::string cameras_path = JoinPaths(export_path, cameras_name);
988  const std::string images_path = JoinPaths(export_path, images_name);
989  const std::string points3D_path = JoinPaths(export_path, points3D_name);
990 
991  settings.setValue("export_path", CVTools::ToQString(export_path));
992  settings.setValue("project_path", CVTools::ToQString(project_path));
993  settings.setValue("cameras_path", CVTools::ToQString(cameras_path));
994  settings.setValue("images_path", CVTools::ToQString(images_path));
995  settings.setValue("points3D_path", CVTools::ToQString(points3D_path));
996  settings.endGroup();
997 
998  if (ExistsFile(cameras_path) || ExistsFile(images_path) ||
999  ExistsFile(points3D_path)) {
1000  QMessageBox::StandardButton reply = QMessageBox::question(
1001  this, "",
1002  StringPrintf(
1003  "The files <i>%s</i>, <i>%s</i>, or <i>%s</i> already "
1004  "exist in the selected destination. Do you want to "
1005  "overwrite them?",
1006  cameras_name.c_str(), images_name.c_str(),
1007  points3D_name.c_str())
1008  .c_str(),
1009  QMessageBox::Yes | QMessageBox::No);
1010  if (reply == QMessageBox::No) {
1011  return;
1012  }
1013  }
1014 
1015  thread_control_widget_->StartFunction("Exporting...", [this, export_path,
1016  project_path]() {
1017  const auto& reconstruction =
1018  reconstruction_manager_.Get(SelectedReconstructionIdx());
1019  reconstruction.WriteText(export_path);
1020  options_.Write(project_path);
1021  });
1022 }
1023 
1024 void ReconstructionWidget::FeatureExtraction() {
1025  if (options_.Check()) {
1026  feature_extraction_widget_->show();
1027  feature_extraction_widget_->raise();
1028  } else {
1029  ShowInvalidProjectError();
1030  }
1031 }
1032 
1033 void ReconstructionWidget::FeatureMatching() {
1034  if (options_.Check()) {
1035  feature_matching_widget_->show();
1036  feature_matching_widget_->raise();
1037  } else {
1038  ShowInvalidProjectError();
1039  }
1040 }
1041 
1042 void ReconstructionWidget::DatabaseManagement() {
1043  if (options_.Check()) {
1044  database_management_widget_->show();
1045  database_management_widget_->raise();
1046  } else {
1047  ShowInvalidProjectError();
1048  }
1049 }
1050 
1051 void ReconstructionWidget::AutomaticReconstruction() {
1052  automatic_reconstruction_widget_->show();
1053  automatic_reconstruction_widget_->raise();
1054 }
1055 
1056 void ReconstructionWidget::ReconstructionStart() {
1057  if (!mapper_controller_->IsStarted() && !options_.Check()) {
1058  ShowInvalidProjectError();
1059  return;
1060  }
1061 
1062  if (mapper_controller_->IsFinished() && HasSelectedReconstruction()) {
1063  QMessageBox::critical(this, "",
1064  tr("Reset reconstruction before starting."));
1065  return;
1066  }
1067 
1068  if (mapper_controller_->IsStarted()) {
1069  // Resume existing reconstruction.
1070  timer_.Resume();
1071  mapper_controller_->Resume();
1072  } else {
1073  // Start new reconstruction.
1074  CreateControllers();
1075  timer_.Restart();
1076  mapper_controller_->Start();
1077  action_reconstruction_start_->setText(tr("Resume reconstruction"));
1078  }
1079 
1080  DisableBlockingActions();
1081  action_reconstruction_pause_->setEnabled(true);
1082 }
1083 
1084 void ReconstructionWidget::ReconstructionStep() {
1085  if (mapper_controller_->IsFinished() && HasSelectedReconstruction()) {
1086  QMessageBox::critical(this, "",
1087  tr("Reset reconstruction before starting."));
1088  return;
1089  }
1090 
1091  action_reconstruction_step_->setEnabled(false);
1092  ReconstructionStart();
1093  ReconstructionPause();
1094  action_reconstruction_step_->setEnabled(true);
1095 }
1096 
1097 void ReconstructionWidget::ReconstructionPause() {
1098  timer_.Pause();
1099  mapper_controller_->Pause();
1100  EnableBlockingActions();
1101  action_reconstruction_pause_->setEnabled(false);
1102 }
1103 
1104 void ReconstructionWidget::ReconstructionOptions() {
1105  reconstruction_options_widget_->show();
1106  reconstruction_options_widget_->raise();
1107 }
1108 
1109 void ReconstructionWidget::ReconstructionFinish() {
1110  timer_.Pause();
1111  mapper_controller_->Stop();
1112  EnableBlockingActions();
1113  action_reconstruction_start_->setEnabled(false);
1114  action_reconstruction_step_->setEnabled(false);
1115  action_reconstruction_pause_->setEnabled(false);
1116 }
1117 
1118 void ReconstructionWidget::ReconstructionReset() {
1119  CreateControllers();
1120 
1121  reconstruction_manager_.Clear();
1122  reconstruction_manager_widget_->Update();
1123 
1124  timer_.Reset();
1125  UpdateTimer();
1126 
1127  EnableBlockingActions();
1128  action_reconstruction_start_->setText(tr("Start reconstruction"));
1129  action_reconstruction_pause_->setEnabled(false);
1130 
1131  RenderClear();
1132 }
1133 
1134 void ReconstructionWidget::ReconstructionNormalize() {
1135  if (!IsSelectedReconstructionValid()) {
1136  return;
1137  }
1138  action_reconstruction_step_->setEnabled(false);
1139  reconstruction_manager_.Get(SelectedReconstructionIdx()).Normalize();
1140  action_reconstruction_step_->setEnabled(true);
1141 }
1142 
1143 bool ReconstructionWidget::ReconstructionOverwrite() {
1144  if (reconstruction_manager_.Size() == 0) {
1145  ReconstructionReset();
1146  return true;
1147  }
1148 
1149  QMessageBox::StandardButton reply = QMessageBox::question(
1150  this, "",
1151  tr("Do you really want to overwrite the existing reconstruction?"),
1152  QMessageBox::Yes | QMessageBox::No);
1153  if (reply == QMessageBox::No) {
1154  return false;
1155  } else {
1156  ReconstructionReset();
1157  return true;
1158  }
1159 }
1160 
1161 void ReconstructionWidget::BundleAdjustment() {
1162  if (!IsSelectedReconstructionValid()) {
1163  return;
1164  }
1165 
1166  bundle_adjustment_widget_->Show(
1167  &reconstruction_manager_.Get(SelectedReconstructionIdx()));
1168 }
1169 
1170 void ReconstructionWidget::DenseReconstruction() {
1171  if (HasSelectedReconstruction()) {
1172  dense_reconstruction_widget_->Show(
1173  &reconstruction_manager_.Get(SelectedReconstructionIdx()));
1174  } else {
1175  dense_reconstruction_widget_->Show(nullptr);
1176  }
1177 }
1178 
1179 void ReconstructionWidget::Render() {
1180  if (reconstruction_manager_.Size() == 0) {
1181  return;
1182  }
1183 
1184  const Reconstruction& reconstruction =
1185  reconstruction_manager_.Get(SelectedReconstructionIdx());
1186 
1187  int refresh_rate;
1188  if (options_.render->adapt_refresh_rate) {
1189  refresh_rate = static_cast<int>(reconstruction.NumRegImages() / 50 + 1);
1190  } else {
1191  refresh_rate = options_.render->refresh_rate;
1192  }
1193 
1194  if (!render_options_widget_->automatic_update ||
1195  render_options_widget_->counter % refresh_rate != 0) {
1196  render_options_widget_->counter += 1;
1197  return;
1198  }
1199 
1200  render_options_widget_->counter += 1;
1201 
1202  RenderNow();
1203 }
1204 
1205 void ReconstructionWidget::RenderNow() {
1206  reconstruction_manager_widget_->Update();
1207  RenderSelectedReconstruction();
1208 }
1209 
1210 void ReconstructionWidget::RenderSelectedReconstruction() {
1211  if (reconstruction_manager_.Size() == 0) {
1212  RenderClear();
1213  return;
1214  }
1215 
1216  const size_t reconstruction_idx = SelectedReconstructionIdx();
1217  model_viewer_widget_->reconstruction =
1218  &reconstruction_manager_.Get(reconstruction_idx);
1219  model_viewer_widget_->ReloadReconstruction();
1220 }
1221 
1222 void ReconstructionWidget::RenderClear() {
1223  reconstruction_manager_widget_->SelectReconstruction(
1225  model_viewer_widget_->ClearReconstruction();
1226 }
1227 
1228 void ReconstructionWidget::RenderOptions() {
1229  render_options_widget_->show();
1230  render_options_widget_->raise();
1231 }
1232 
1233 void ReconstructionWidget::SelectReconstructionIdx(const size_t) {
1234  RenderSelectedReconstruction();
1235 }
1236 
1237 size_t ReconstructionWidget::SelectedReconstructionIdx() {
1238  size_t reconstruction_idx =
1239  reconstruction_manager_widget_->SelectedReconstructionIdx();
1240  if (reconstruction_idx ==
1242  if (reconstruction_manager_.Size() > 0) {
1243  reconstruction_idx = reconstruction_manager_.Size() - 1;
1244  }
1245  }
1246  return reconstruction_idx;
1247 }
1248 
1249 bool ReconstructionWidget::HasSelectedReconstruction() {
1250  const size_t reconstruction_idx =
1251  reconstruction_manager_widget_->SelectedReconstructionIdx();
1252  if (reconstruction_idx ==
1254  if (reconstruction_manager_.Size() == 0) {
1255  return false;
1256  }
1257  }
1258  return true;
1259 }
1260 
1261 bool ReconstructionWidget::IsSelectedReconstructionValid() {
1262  if (!HasSelectedReconstruction()) {
1263  QMessageBox::critical(this, "", tr("No reconstruction selected"));
1264  return false;
1265  }
1266  return true;
1267 }
1268 
1269 void ReconstructionWidget::GrabImage() {
1270  QString file_name = QFileDialog::getSaveFileName(
1271  this, tr("Save image"), "", tr("Images (*.png *.jpg)"));
1272  if (file_name != "") {
1273  if (!HasFileExtension(file_name.toUtf8().constData(), ".png") &&
1274  !HasFileExtension(file_name.toUtf8().constData(), ".jpg")) {
1275  file_name += ".png";
1276  }
1277  QImage image = model_viewer_widget_->GrabImage();
1278  image.save(file_name);
1279  }
1280 }
1281 
1282 void ReconstructionWidget::UndistortImages() {
1283  if (!IsSelectedReconstructionValid()) {
1284  return;
1285  }
1286  undistortion_widget_->Show(
1287  reconstruction_manager_.Get(SelectedReconstructionIdx()));
1288 }
1289 
1290 void ReconstructionWidget::ReconstructionStats() {
1291  if (!IsSelectedReconstructionValid()) {
1292  return;
1293  }
1294  reconstruction_stats_widget_->show();
1295  reconstruction_stats_widget_->raise();
1296  reconstruction_stats_widget_->Show(
1297  reconstruction_manager_.Get(SelectedReconstructionIdx()));
1298 }
1299 
1300 void ReconstructionWidget::MatchMatrix() { match_matrix_widget_->Show(); }
1301 
1303  log_widget_->show();
1304  log_widget_->raise();
1305  dock_log_widget_->show();
1306  dock_log_widget_->raise();
1307 }
1308 
1310  log_widget_->hide();
1311  dock_log_widget_->hide();
1312 }
1313 
1314 void ReconstructionWidget::ExtractColors() {
1315  if (!IsSelectedReconstructionValid()) {
1316  return;
1317  }
1318 
1319  thread_control_widget_->StartFunction("Extracting colors...", [this]() {
1320  auto& reconstruction =
1321  reconstruction_manager_.Get(SelectedReconstructionIdx());
1322  reconstruction.ExtractColorsForAllImages(*options_.image_path);
1323  });
1324 }
1325 
1326 void ReconstructionWidget::SetOptions() {
1327  QStringList data_items;
1328  data_items << "Individual images"
1329  << "Video frames"
1330  << "Internet images";
1331  bool data_ok;
1332  const QString data_item = QInputDialog::getItem(
1333  this, "", "Data:", data_items, 0, false, &data_ok);
1334  if (!data_ok) {
1335  return;
1336  }
1337 
1338  QStringList quality_items;
1339  quality_items << "Low"
1340  << "Medium"
1341  << "High"
1342  << "Extreme";
1343  bool quality_ok;
1344  const QString quality_item = QInputDialog::getItem(
1345  this, "", "Quality:", quality_items, 2, false, &quality_ok);
1346  if (!quality_ok) {
1347  return;
1348  }
1349 
1350  const bool kResetPaths = false;
1351  options_.ResetOptions(kResetPaths);
1352 
1353  if (data_item == "Individual images") {
1354  options_.ModifyForIndividualData();
1355  } else if (data_item == "Video frames") {
1356  options_.ModifyForVideoData();
1357  } else if (data_item == "Internet images") {
1358  options_.ModifyForInternetData();
1359  } else {
1360  LOG(FATAL) << "Data type does not exist";
1361  }
1362 
1363  if (quality_item == "Low") {
1364  options_.ModifyForLowQuality();
1365  } else if (quality_item == "Medium") {
1366  options_.ModifyForMediumQuality();
1367  } else if (quality_item == "High") {
1368  options_.ModifyForHighQuality();
1369  } else if (quality_item == "Extreme") {
1370  options_.ModifyForExtremeQuality();
1371  } else {
1372  LOG(FATAL) << "Quality level does not exist";
1373  }
1374 }
1375 
1376 void ReconstructionWidget::ResetOptions() {
1377  const bool kResetPaths = false;
1378  options_.ResetOptions(kResetPaths);
1379 }
1380 
1381 void ReconstructionWidget::RenderToggle() {
1382  if (render_options_widget_->automatic_update) {
1383  render_options_widget_->automatic_update = false;
1384  render_options_widget_->counter = 0;
1385  action_render_toggle_->setIcon(QIcon(":/media/render-disabled.png"));
1386  action_render_toggle_->setText(tr("Enable rendering"));
1387  } else {
1388  render_options_widget_->automatic_update = true;
1389  render_options_widget_->counter = 0;
1390  Render();
1391  action_render_toggle_->setIcon(QIcon(":/media/render-enabled.png"));
1392  action_render_toggle_->setText(tr("Disable rendering"));
1393  }
1394 }
1395 
1396 void ReconstructionWidget::UpdateTimer() {
1397  const int elapsed_time = static_cast<int>(timer_.ElapsedSeconds());
1398  const int seconds = elapsed_time % 60;
1399  const int minutes = (elapsed_time / 60) % 60;
1400  const int hours = (elapsed_time / 3600) % 24;
1401  const int days = elapsed_time / 86400;
1402  if (statusbar_timer_label_) {
1403  statusbar_timer_label_->setText(QString().asprintf(
1404  "Time %02d:%02d:%02d:%02d", days, hours, minutes, seconds));
1405  }
1406 }
1407 
1408 void ReconstructionWidget::ShowInvalidProjectError() {
1409  QMessageBox::critical(this, "",
1410  tr("You must create a valid project using: <i>File > "
1411  "New project</i> or <i>File > Edit project</i>"));
1412 }
1413 
1414 void ReconstructionWidget::EnableBlockingActions() {
1415  for (auto& action : blocking_actions_) {
1416  action->setEnabled(true);
1417  }
1418 }
1419 
1420 void ReconstructionWidget::DisableBlockingActions() {
1421  for (auto& action : blocking_actions_) {
1422  action->setDisabled(true);
1423  }
1424 }
1425 
1426 } // namespace cloudViewer
std::shared_ptr< core::Tensor > image
static std::string FromQString(const QString &qs)
Definition: CVTools.cpp:100
static QString ToQString(const std::string &s)
Definition: CVTools.cpp:92
void Show(colmap::Reconstruction *reconstruction)
void Show(colmap::Reconstruction *reconstruction)
colmap::Reconstruction * reconstruction
void SetImagePath(const std::string &path)
void persistSave(const std::string &project_path, const std::string &database_path, const std::string &image_path)
void SetDatabasePath(const std::string &path)
void Show(const colmap::Reconstruction &reconstruction)
void ImportReconstruction(const std::string &path)
void StartFunction(const QString &progress_text, const std::function< void()> &func)
void Show(const colmap::Reconstruction &reconstruction)
static const std::string path
Definition: PointCloud.cpp:59
std::string JoinPaths(T const &...paths)
Definition: FileSystem.h:23
bool HasFileExtension(const std::string &file_name, const std::string &ext)
Definition: FileSystem.cpp:117
std::string StringPrintf(const char *format,...)
Definition: Helper.cpp:110
Generic file read and write utility for python interface.
colmap::IncrementalMapperController IncrementalMapperController
#define seconds
Definition: rename.h:375