ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FeatureMatchingWidget.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 
9 
10 #include "ThreadControlWidget.h"
11 #include "feature/matching.h"
12 #include "ui/options_widget.h"
13 #include "util/misc.h"
14 #include "util/option_manager.h"
15 
16 namespace cloudViewer {
17 
18 using namespace colmap;
19 
20 class FeatureMatchingTab : public QWidget {
21 public:
22  FeatureMatchingTab(QWidget* parent, OptionManager* options);
23 
24  virtual void Run() = 0;
25 
26 protected:
27  void CreateGeneralOptions();
28 
30  OptionsWidget* options_widget_;
31  QGridLayout* grid_layout_;
33 };
34 
36 public:
37  ExhaustiveMatchingTab(QWidget* parent, OptionManager* options);
38  void Run() override;
39 };
40 
42 public:
43  SequentialMatchingTab(QWidget* parent, OptionManager* options);
44  void Run() override;
45 };
46 
48 public:
49  VocabTreeMatchingTab(QWidget* parent, OptionManager* options);
50  void Run() override;
51 };
52 
54 public:
55  SpatialMatchingTab(QWidget* parent, OptionManager* options);
56  void Run() override;
57 };
58 
60 public:
61  TransitiveMatchingTab(QWidget* parent, OptionManager* options);
62  void Run() override;
63 };
64 
66 public:
67  CustomMatchingTab(QWidget* parent, OptionManager* options);
68  void Run() override;
69 
70 private:
71  std::string match_list_path_;
72  QComboBox* match_type_cb_;
73 };
74 
76  : QWidget(parent),
77  options_(options),
78  options_widget_(new OptionsWidget(this)),
79  grid_layout_(new QGridLayout(this)),
80  thread_control_widget_(new ThreadControlWidget(this)) {}
81 
83  options_widget_->AddSpacer();
84  options_widget_->AddSpacer();
85  options_widget_->AddSection("General Options");
86  options_widget_->AddSpacer();
87 
88  options_widget_->AddOptionInt(&options_->sift_matching->num_threads,
89  "num_threads", -1);
90  options_widget_->AddOptionBool(&options_->sift_matching->use_gpu,
91  "use_gpu");
92  options_widget_->AddOptionText(&options_->sift_matching->gpu_index,
93  "gpu_index");
94  options_widget_->AddOptionDouble(&options_->sift_matching->max_ratio,
95  "max_ratio");
96  options_widget_->AddOptionDouble(&options_->sift_matching->max_distance,
97  "max_distance");
98  options_widget_->AddOptionBool(&options_->sift_matching->cross_check,
99  "cross_check");
100  options_widget_->AddOptionInt(&options_->sift_matching->max_num_matches,
101  "max_num_matches");
102  options_widget_->AddOptionDouble(&options_->sift_matching->max_error,
103  "max_error");
104  options_widget_->AddOptionDouble(&options_->sift_matching->confidence,
105  "confidence", 0, 1, 0.00001, 5);
106  options_widget_->AddOptionInt(&options_->sift_matching->max_num_trials,
107  "max_num_trials");
108  options_widget_->AddOptionDouble(&options_->sift_matching->min_inlier_ratio,
109  "min_inlier_ratio", 0, 1, 0.001, 3);
110  options_widget_->AddOptionInt(&options_->sift_matching->min_num_inliers,
111  "min_num_inliers");
112  options_widget_->AddOptionBool(&options_->sift_matching->multiple_models,
113  "multiple_models");
114  options_widget_->AddOptionBool(&options_->sift_matching->guided_matching,
115  "guided_matching");
116 
117  options_widget_->AddSpacer();
118 
119  QScrollArea* options_scroll_area = new QScrollArea(this);
120  options_scroll_area->setAlignment(Qt::AlignHCenter);
121  options_scroll_area->setWidget(options_widget_);
122  grid_layout_->addWidget(options_scroll_area, grid_layout_->rowCount(), 0);
123 
124  QPushButton* run_button = new QPushButton(tr("Run"), this);
125  grid_layout_->addWidget(run_button, grid_layout_->rowCount(), 0);
126  connect(run_button, &QPushButton::released, this, &FeatureMatchingTab::Run);
127 }
128 
130  OptionManager* options)
131  : FeatureMatchingTab(parent, options) {
132  options_widget_->AddOptionInt(&options_->exhaustive_matching->block_size,
133  "block_size", 2);
134 
136 }
137 
139  options_widget_->WriteOptions();
140 
141  Thread* matcher = new ExhaustiveFeatureMatcher(
142  *options_->exhaustive_matching, *options_->sift_matching,
143  *options_->database_path);
144  thread_control_widget_->StartThread("Matching...", true, matcher);
145 }
146 
148  OptionManager* options)
149  : FeatureMatchingTab(parent, options) {
150  options_widget_->AddOptionInt(&options_->sequential_matching->overlap,
151  "overlap");
152  options_widget_->AddOptionBool(
153  &options_->sequential_matching->quadratic_overlap,
154  "quadratic_overlap");
155  options_widget_->AddOptionBool(
156  &options_->sequential_matching->loop_detection, "loop_detection");
157  options_widget_->AddOptionInt(
158  &options_->sequential_matching->loop_detection_period,
159  "loop_detection_period");
160  options_widget_->AddOptionInt(
161  &options_->sequential_matching->loop_detection_num_images,
162  "loop_detection_num_images");
163  options_widget_->AddOptionInt(
164  &options_->sequential_matching
165  ->loop_detection_num_nearest_neighbors,
166  "loop_detection_num_nearest_neighbors");
167  options_widget_->AddOptionInt(
168  &options_->sequential_matching->loop_detection_num_checks,
169  "loop_detection_num_checks", 1);
170  options_widget_->AddOptionInt(
171  &options_->sequential_matching
172  ->loop_detection_num_images_after_verification,
173  "loop_detection_num_images_after_verification", 0);
174  options_widget_->AddOptionInt(
175  &options_->sequential_matching->loop_detection_max_num_features,
176  "loop_detection_max_num_features", -1);
177  options_widget_->AddOptionFilePath(
178  &options_->sequential_matching->vocab_tree_path, "vocab_tree_path");
179 
181 }
182 
184  options_widget_->WriteOptions();
185 
186  if (options_->sequential_matching->loop_detection &&
187  !ExistsFile(options_->sequential_matching->vocab_tree_path)) {
188  QMessageBox::critical(this, "", tr("Invalid vocabulary tree path."));
189  return;
190  }
191 
192  Thread* matcher = new SequentialFeatureMatcher(
193  *options_->sequential_matching, *options_->sift_matching,
194  *options_->database_path);
195  thread_control_widget_->StartThread("Matching...", true, matcher);
196 }
197 
199  OptionManager* options)
200  : FeatureMatchingTab(parent, options) {
201  options_widget_->AddOptionInt(&options_->vocab_tree_matching->num_images,
202  "num_images");
203  options_widget_->AddOptionInt(
204  &options_->vocab_tree_matching->num_nearest_neighbors,
205  "num_nearest_neighbors");
206  options_widget_->AddOptionInt(&options_->vocab_tree_matching->num_checks,
207  "num_checks", 1);
208  options_widget_->AddOptionInt(
209  &options_->vocab_tree_matching->num_images_after_verification,
210  "num_images_after_verification", 0);
211  options_widget_->AddOptionInt(
212  &options_->vocab_tree_matching->max_num_features,
213  "max_num_features", -1);
214  options_widget_->AddOptionFilePath(
215  &options_->vocab_tree_matching->vocab_tree_path, "vocab_tree_path");
216 
218 }
219 
221  options_widget_->WriteOptions();
222 
223  if (!ExistsFile(options_->vocab_tree_matching->vocab_tree_path)) {
224  QMessageBox::critical(this, "", tr("Invalid vocabulary tree path."));
225  return;
226  }
227 
228  Thread* matcher = new VocabTreeFeatureMatcher(
229  *options_->vocab_tree_matching, *options_->sift_matching,
230  *options_->database_path);
231  thread_control_widget_->StartThread("Matching...", true, matcher);
232 }
233 
235  : FeatureMatchingTab(parent, options) {
236  options_widget_->AddOptionBool(&options_->spatial_matching->is_gps,
237  "is_gps");
238  options_widget_->AddOptionBool(&options_->spatial_matching->ignore_z,
239  "ignore_z");
240  options_widget_->AddOptionInt(
241  &options_->spatial_matching->max_num_neighbors,
242  "max_num_neighbors");
243  options_widget_->AddOptionDouble(&options_->spatial_matching->max_distance,
244  "max_distance");
245 
247 }
248 
250  options_widget_->WriteOptions();
251 
252  Thread* matcher = new SpatialFeatureMatcher(*options_->spatial_matching,
253  *options_->sift_matching,
254  *options_->database_path);
255  thread_control_widget_->StartThread("Matching...", true, matcher);
256 }
257 
259  OptionManager* options)
260  : FeatureMatchingTab(parent, options) {
261  options_widget_->AddOptionInt(&options->transitive_matching->batch_size,
262  "batch_size");
263  options_widget_->AddOptionInt(&options->transitive_matching->num_iterations,
264  "num_iterations");
265 
267 }
268 
270  options_widget_->WriteOptions();
271 
272  Thread* matcher = new TransitiveFeatureMatcher(
273  *options_->transitive_matching, *options_->sift_matching,
274  *options_->database_path);
275  thread_control_widget_->StartThread("Matching...", true, matcher);
276 }
277 
279  : FeatureMatchingTab(parent, options) {
280  match_type_cb_ = new QComboBox(this);
281  match_type_cb_->addItem(QString("Image pairs"));
282  match_type_cb_->addItem(QString("Raw feature matches"));
283  match_type_cb_->addItem(QString("Inlier feature matches"));
284  options_widget_->AddOptionRow("type", match_type_cb_, nullptr);
285 
286  options_widget_->AddOptionFilePath(&match_list_path_, "match_list_path");
287  options_widget_->AddOptionInt(&options_->image_pairs_matching->block_size,
288  "block_size", 2);
289 
291 }
292 
294  options_widget_->WriteOptions();
295 
296  if (!ExistsFile(match_list_path_)) {
297  QMessageBox::critical(this, "", tr("Path does not exist!"));
298  return;
299  }
300 
301  Thread* matcher = nullptr;
302  if (match_type_cb_->currentIndex() == 0) {
303  ImagePairsMatchingOptions matcher_options;
304  matcher_options.match_list_path = match_list_path_;
305  matcher = new ImagePairsFeatureMatcher(matcher_options,
306  *options_->sift_matching,
307  *options_->database_path);
308  } else {
309  FeaturePairsMatchingOptions matcher_options;
310  matcher_options.match_list_path = match_list_path_;
311  if (match_type_cb_->currentIndex() == 1) {
312  matcher_options.verify_matches = true;
313  } else if (match_type_cb_->currentIndex() == 2) {
314  matcher_options.verify_matches = false;
315  }
316 
317  matcher = new FeaturePairsFeatureMatcher(matcher_options,
318  *options_->sift_matching,
319  *options_->database_path);
320  }
321 
322  thread_control_widget_->StartThread("Matching...", true, matcher);
323 }
324 
326  OptionManager* options)
327  : parent_(parent) {
328  // Do not change flag, to make sure feature database is not accessed from
329  // multiple threads
330  setWindowFlags(Qt::Window);
331  setWindowTitle("Feature matching");
332 
333  QGridLayout* grid = new QGridLayout(this);
334 
335  tab_widget_ = new QTabWidget(this);
336  tab_widget_->addTab(new ExhaustiveMatchingTab(this, options),
337  tr("Exhaustive"));
338  tab_widget_->addTab(new SequentialMatchingTab(this, options),
339  tr("Sequential"));
340  tab_widget_->addTab(new VocabTreeMatchingTab(this, options),
341  tr("VocabTree"));
342  tab_widget_->addTab(new SpatialMatchingTab(this, options), tr("Spatial"));
343  tab_widget_->addTab(new TransitiveMatchingTab(this, options),
344  tr("Transitive"));
345  tab_widget_->addTab(new CustomMatchingTab(this, options), tr("Custom"));
346 
347  grid->addWidget(tab_widget_, 0, 0);
348 }
349 
350 void FeatureMatchingWidget::showEvent(QShowEvent* event) {
351  parent_->setDisabled(true);
352 }
353 
354 void FeatureMatchingWidget::hideEvent(QHideEvent* event) {
355  parent_->setEnabled(true);
356 }
357 
358 } // namespace cloudViewer
MouseEvent event
int Run(int argc, const char *argv[])
CustomMatchingTab(QWidget *parent, OptionManager *options)
ExhaustiveMatchingTab(QWidget *parent, OptionManager *options)
FeatureMatchingTab(QWidget *parent, OptionManager *options)
ThreadControlWidget * thread_control_widget_
FeatureMatchingWidget(QWidget *parent, OptionManager *options)
SequentialMatchingTab(QWidget *parent, OptionManager *options)
SpatialMatchingTab(QWidget *parent, OptionManager *options)
void StartThread(const QString &progress_text, const bool stoppable, colmap::Thread *thread)
TransitiveMatchingTab(QWidget *parent, OptionManager *options)
VocabTreeMatchingTab(QWidget *parent, OptionManager *options)
Generic file read and write utility for python interface.
colmap::OptionManager OptionManager
struct Window Window
Definition: sqlite3.c:14678