ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
feature_matching_widget.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 
33 
34 #include "feature/matching.h"
35 #include "ui/options_widget.h"
37 
38 namespace colmap {
39 
40 class FeatureMatchingTab : public QWidget {
41  public:
42  FeatureMatchingTab(QWidget* parent, OptionManager* options);
43 
44  virtual void Run() = 0;
45 
46  protected:
47  void CreateGeneralOptions();
48 
51  QGridLayout* grid_layout_;
53 };
54 
56  public:
57  ExhaustiveMatchingTab(QWidget* parent, OptionManager* options);
58  void Run() override;
59 };
60 
62  public:
63  SequentialMatchingTab(QWidget* parent, OptionManager* options);
64  void Run() override;
65 };
66 
68  public:
69  VocabTreeMatchingTab(QWidget* parent, OptionManager* options);
70  void Run() override;
71 };
72 
74  public:
75  SpatialMatchingTab(QWidget* parent, OptionManager* options);
76  void Run() override;
77 };
78 
80  public:
81  TransitiveMatchingTab(QWidget* parent, OptionManager* options);
82  void Run() override;
83 };
84 
86  public:
87  CustomMatchingTab(QWidget* parent, OptionManager* options);
88  void Run() override;
89 
90  private:
91  std::string match_list_path_;
92  QComboBox* match_type_cb_;
93 };
94 
96  : QWidget(parent),
97  options_(options),
98  options_widget_(new OptionsWidget(this)),
99  grid_layout_(new QGridLayout(this)),
100  thread_control_widget_(new ThreadControlWidget(this)) {}
101 
105  options_widget_->AddSection("General Options");
107 
109  "num_threads", -1);
110  options_widget_->AddOptionBool(&options_->sift_matching->use_gpu, "use_gpu");
112  "gpu_index");
114  "max_ratio");
116  "max_distance");
118  "cross_check");
120  "max_num_matches");
122  "max_error");
124  "confidence", 0, 1, 0.00001, 5);
126  "max_num_trials");
128  "min_inlier_ratio", 0, 1, 0.001, 3);
130  "min_num_inliers");
132  "multiple_models");
134  "guided_matching");
135 
137 
138  QScrollArea* options_scroll_area = new QScrollArea(this);
139  options_scroll_area->setAlignment(Qt::AlignHCenter);
140  options_scroll_area->setWidget(options_widget_);
141  grid_layout_->addWidget(options_scroll_area, grid_layout_->rowCount(), 0);
142 
143  QPushButton* run_button = new QPushButton(tr("Run"), this);
144  grid_layout_->addWidget(run_button, grid_layout_->rowCount(), 0);
145  connect(run_button, &QPushButton::released, this, &FeatureMatchingTab::Run);
146 }
147 
149  OptionManager* options)
150  : FeatureMatchingTab(parent, options) {
152  "block_size", 2);
153 
155 }
156 
159 
163  thread_control_widget_->StartThread("Matching...", true, matcher);
164 }
165 
167  OptionManager* options)
168  : FeatureMatchingTab(parent, options) {
170  "overlap");
172  &options_->sequential_matching->quadratic_overlap, "quadratic_overlap");
174  "loop_detection");
176  &options_->sequential_matching->loop_detection_period,
177  "loop_detection_period");
179  &options_->sequential_matching->loop_detection_num_images,
180  "loop_detection_num_images");
182  &options_->sequential_matching->loop_detection_num_nearest_neighbors,
183  "loop_detection_num_nearest_neighbors");
185  &options_->sequential_matching->loop_detection_num_checks,
186  "loop_detection_num_checks", 1);
189  ->loop_detection_num_images_after_verification,
190  "loop_detection_num_images_after_verification", 0);
192  &options_->sequential_matching->loop_detection_max_num_features,
193  "loop_detection_max_num_features", -1);
195  &options_->sequential_matching->vocab_tree_path, "vocab_tree_path");
196 
198 }
199 
202 
203  if (options_->sequential_matching->loop_detection &&
204  !ExistsFile(options_->sequential_matching->vocab_tree_path)) {
205  QMessageBox::critical(this, "", tr("Invalid vocabulary tree path."));
206  return;
207  }
208 
212  thread_control_widget_->StartThread("Matching...", true, matcher);
213 }
214 
216  OptionManager* options)
217  : FeatureMatchingTab(parent, options) {
219  "num_images");
221  &options_->vocab_tree_matching->num_nearest_neighbors,
222  "num_nearest_neighbors");
224  "num_checks", 1);
226  &options_->vocab_tree_matching->num_images_after_verification,
227  "num_images_after_verification", 0);
229  &options_->vocab_tree_matching->max_num_features, "max_num_features", -1);
231  &options_->vocab_tree_matching->vocab_tree_path, "vocab_tree_path");
232 
234 }
235 
238 
239  if (!ExistsFile(options_->vocab_tree_matching->vocab_tree_path)) {
240  QMessageBox::critical(this, "", tr("Invalid vocabulary tree path."));
241  return;
242  }
243 
247  thread_control_widget_->StartThread("Matching...", true, matcher);
248 }
249 
251  : FeatureMatchingTab(parent, options) {
254  "ignore_z");
256  "max_num_neighbors");
258  "max_distance");
259 
261 }
262 
265 
269  thread_control_widget_->StartThread("Matching...", true, matcher);
270 }
271 
273  OptionManager* options)
274  : FeatureMatchingTab(parent, options) {
275  options_widget_->AddOptionInt(&options->transitive_matching->batch_size,
276  "batch_size");
277  options_widget_->AddOptionInt(&options->transitive_matching->num_iterations,
278  "num_iterations");
279 
281 }
282 
285 
289  thread_control_widget_->StartThread("Matching...", true, matcher);
290 }
291 
293  : FeatureMatchingTab(parent, options) {
294  match_type_cb_ = new QComboBox(this);
295  match_type_cb_->addItem(QString("Image pairs"));
296  match_type_cb_->addItem(QString("Raw feature matches"));
297  match_type_cb_->addItem(QString("Inlier feature matches"));
298  options_widget_->AddOptionRow("type", match_type_cb_, nullptr);
299 
300  options_widget_->AddOptionFilePath(&match_list_path_, "match_list_path");
302  "block_size", 2);
303 
305 }
306 
309 
310  if (!ExistsFile(match_list_path_)) {
311  QMessageBox::critical(this, "", tr("Path does not exist!"));
312  return;
313  }
314 
315  Thread* matcher = nullptr;
316  if (match_type_cb_->currentIndex() == 0) {
317  ImagePairsMatchingOptions matcher_options;
318  matcher_options.match_list_path = match_list_path_;
319  matcher = new ImagePairsFeatureMatcher(
320  matcher_options, *options_->sift_matching, *options_->database_path);
321  } else {
322  FeaturePairsMatchingOptions matcher_options;
323  matcher_options.match_list_path = match_list_path_;
324  if (match_type_cb_->currentIndex() == 1) {
325  matcher_options.verify_matches = true;
326  } else if (match_type_cb_->currentIndex() == 2) {
327  matcher_options.verify_matches = false;
328  }
329 
330  matcher = new FeaturePairsFeatureMatcher(
331  matcher_options, *options_->sift_matching, *options_->database_path);
332  }
333 
334  thread_control_widget_->StartThread("Matching...", true, matcher);
335 }
336 
338  OptionManager* options)
339  : parent_(parent) {
340  // Do not change flag, to make sure feature database is not accessed from
341  // multiple threads
342  setWindowFlags(Qt::Window);
343  setWindowTitle("Feature matching");
344 
345  QGridLayout* grid = new QGridLayout(this);
346 
347  tab_widget_ = new QTabWidget(this);
348  tab_widget_->addTab(new ExhaustiveMatchingTab(this, options),
349  tr("Exhaustive"));
350  tab_widget_->addTab(new SequentialMatchingTab(this, options),
351  tr("Sequential"));
352  tab_widget_->addTab(new VocabTreeMatchingTab(this, options), tr("VocabTree"));
353  tab_widget_->addTab(new SpatialMatchingTab(this, options), tr("Spatial"));
354  tab_widget_->addTab(new TransitiveMatchingTab(this, options),
355  tr("Transitive"));
356  tab_widget_->addTab(new CustomMatchingTab(this, options), tr("Custom"));
357 
358  grid->addWidget(tab_widget_, 0, 0);
359 }
360 
361 void FeatureMatchingWidget::showEvent(QShowEvent* event) {
362  parent_->setDisabled(true);
363 }
364 
365 void FeatureMatchingWidget::hideEvent(QHideEvent* event) {
366  parent_->setEnabled(true);
367 }
368 
369 } // namespace colmap
MouseEvent event
CustomMatchingTab(QWidget *parent, OptionManager *options)
ExhaustiveMatchingTab(QWidget *parent, OptionManager *options)
ThreadControlWidget * thread_control_widget_
FeatureMatchingTab(QWidget *parent, OptionManager *options)
FeatureMatchingWidget(QWidget *parent, OptionManager *options)
std::shared_ptr< SequentialMatchingOptions > sequential_matching
std::shared_ptr< TransitiveMatchingOptions > transitive_matching
std::shared_ptr< std::string > database_path
std::shared_ptr< SiftMatchingOptions > sift_matching
std::shared_ptr< VocabTreeMatchingOptions > vocab_tree_matching
std::shared_ptr< ExhaustiveMatchingOptions > exhaustive_matching
std::shared_ptr< SpatialMatchingOptions > spatial_matching
std::shared_ptr< ImagePairsMatchingOptions > image_pairs_matching
QLineEdit * AddOptionText(std::string *option, const std::string &label_text)
QLineEdit * AddOptionFilePath(std::string *option, const std::string &label_text)
QDoubleSpinBox * AddOptionDouble(double *option, const std::string &label_text, const double min=0, const double max=1e7, const double step=0.01, const int decimals=2)
QSpinBox * AddOptionInt(int *option, const std::string &label_text, const int min=0, const int max=static_cast< int >(1e7))
void AddOptionRow(const std::string &label_text, QWidget *widget, void *option)
void AddSection(const std::string &title)
QCheckBox * AddOptionBool(bool *option, const std::string &label_text)
SequentialMatchingTab(QWidget *parent, OptionManager *options)
SpatialMatchingTab(QWidget *parent, OptionManager *options)
void StartThread(const QString &progress_text, const bool stoppable, Thread *thread)
TransitiveMatchingTab(QWidget *parent, OptionManager *options)
VocabTreeMatchingTab(QWidget *parent, OptionManager *options)
bool ExistsFile(const std::string &path)
Definition: misc.cc:100