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