ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
feature_extraction_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 "base/camera_models.h"
35 #include "feature/extraction.h"
36 #include "ui/options_widget.h"
37 #include "ui/qt_utils.h"
39 
40 namespace colmap {
41 
43  public:
44  ExtractionWidget(QWidget* parent, OptionManager* options);
45 
46  virtual void Run() = 0;
47 
48  protected:
51 };
52 
54  public:
55  SIFTExtractionWidget(QWidget* parent, OptionManager* options);
56 
57  void Run() override;
58 };
59 
61  public:
62  ImportFeaturesWidget(QWidget* parent, OptionManager* options);
63 
64  void Run() override;
65 
66  private:
67  std::string import_path_;
68 };
69 
71  : OptionsWidget(parent),
72  options_(options),
73  thread_control_widget_(new ThreadControlWidget(this)) {}
74 
76  OptionManager* options)
77  : ExtractionWidget(parent, options) {
78  AddOptionDirPath(&options->image_reader->mask_path, "mask_path");
79  AddOptionFilePath(&options->image_reader->camera_mask_path,
80  "camera_mask_path");
81 
82  AddOptionInt(&options->sift_extraction->max_image_size, "max_image_size");
83  AddOptionInt(&options->sift_extraction->max_num_features, "max_num_features");
84  AddOptionInt(&options->sift_extraction->first_octave, "first_octave", -5);
85  AddOptionInt(&options->sift_extraction->num_octaves, "num_octaves");
86  AddOptionInt(&options->sift_extraction->octave_resolution,
87  "octave_resolution");
88  AddOptionDouble(&options->sift_extraction->peak_threshold, "peak_threshold",
89  0.0, 1e7, 0.00001, 5);
90  AddOptionDouble(&options->sift_extraction->edge_threshold, "edge_threshold");
91  AddOptionBool(&options->sift_extraction->estimate_affine_shape,
92  "estimate_affine_shape");
93  AddOptionInt(&options->sift_extraction->max_num_orientations,
94  "max_num_orientations");
95  AddOptionBool(&options->sift_extraction->upright, "upright");
96  AddOptionBool(&options->sift_extraction->domain_size_pooling,
97  "domain_size_pooling");
98  AddOptionDouble(&options->sift_extraction->dsp_min_scale, "dsp_min_scale",
99  0.0, 1e7, 0.00001, 5);
100  AddOptionDouble(&options->sift_extraction->dsp_max_scale, "dsp_max_scale",
101  0.0, 1e7, 0.00001, 5);
102  AddOptionInt(&options->sift_extraction->dsp_num_scales, "dsp_num_scales", 1);
103 
104  AddOptionInt(&options->sift_extraction->num_threads, "num_threads", -1);
105  AddOptionBool(&options->sift_extraction->use_gpu, "use_gpu");
106  AddOptionText(&options->sift_extraction->gpu_index, "gpu_index");
107 }
108 
110  WriteOptions();
111 
112  ImageReaderOptions reader_options = *options_->image_reader;
113  reader_options.database_path = *options_->database_path;
114  reader_options.image_path = *options_->image_path;
115 
116  Thread* extractor =
117  new SiftFeatureExtractor(reader_options, *options_->sift_extraction);
118  thread_control_widget_->StartThread("Extracting...", true, extractor);
119 }
120 
122  OptionManager* options)
123  : ExtractionWidget(parent, options) {
124  AddOptionDirPath(&import_path_, "import_path");
125 }
126 
128  WriteOptions();
129 
130  if (!ExistsDir(import_path_)) {
131  QMessageBox::critical(this, "", tr("Path is not a directory"));
132  return;
133  }
134 
135  ImageReaderOptions reader_options = *options_->image_reader;
136  reader_options.database_path = *options_->database_path;
137  reader_options.image_path = *options_->image_path;
138 
139  Thread* importer = new FeatureImporter(reader_options, import_path_);
140  thread_control_widget_->StartThread("Importing...", true, importer);
141 }
142 
144  OptionManager* options)
145  : parent_(parent), options_(options) {
146  // Do not change flag, to make sure feature database is not accessed from
147  // multiple threads
148  setWindowFlags(Qt::Window);
149  setWindowTitle("Feature extraction");
150 
151  QGridLayout* grid = new QGridLayout(this);
152 
153  grid->addWidget(CreateCameraModelBox(), 0, 0);
154 
155  tab_widget_ = new QTabWidget(this);
156 
157  QScrollArea* extraction_widget = new QScrollArea(this);
158  extraction_widget->setAlignment(Qt::AlignHCenter);
159  extraction_widget->setWidget(new SIFTExtractionWidget(this, options));
160  tab_widget_->addTab(extraction_widget, tr("Extract"));
161 
162  QScrollArea* import_widget = new QScrollArea(this);
163  import_widget->setAlignment(Qt::AlignHCenter);
164  import_widget->setWidget(new ImportFeaturesWidget(this, options));
165  tab_widget_->addTab(import_widget, tr("Import"));
166 
167  grid->addWidget(tab_widget_);
168 
169  QPushButton* extract_button = new QPushButton(tr("Extract"), this);
170  connect(extract_button, &QPushButton::released, this,
171  &FeatureExtractionWidget::Extract);
172  grid->addWidget(extract_button, grid->rowCount(), 0);
173 }
174 
175 QGroupBox* FeatureExtractionWidget::CreateCameraModelBox() {
176  camera_model_ids_.clear();
177 
178  camera_model_cb_ = new QComboBox(this);
179 
180 #define CAMERA_MODEL_CASE(CameraModel) \
181  camera_model_cb_->addItem( \
182  QString::fromStdString(CameraModelIdToName(CameraModel::model_id))); \
183  camera_model_ids_.push_back(static_cast<int>(CameraModel::model_id));
184 
186 
187 #undef CAMERA_MODEL_CASE
188 
189  camera_params_exif_rb_ = new QRadioButton(tr("Parameters from EXIF"), this);
190  camera_params_exif_rb_->setChecked(true);
191 
192  camera_params_custom_rb_ = new QRadioButton(tr("Custom parameters"), this);
193 
194  camera_params_info_ = new QLabel(tr(""), this);
195  QPalette pal = QPalette(camera_params_info_->palette());
196  pal.setColor(QPalette::WindowText, QColor(130, 130, 130));
197  camera_params_info_->setPalette(pal);
198 
199  camera_params_text_ = new QLineEdit(this);
200  camera_params_text_->setEnabled(false);
201 
202  single_camera_cb_ = new QCheckBox("Shared for all images", this);
203  single_camera_cb_->setChecked(false);
204 
205  single_camera_per_folder_cb_ = new QCheckBox("Shared per sub-folder", this);
206  single_camera_per_folder_cb_->setChecked(false);
207 
208  QGroupBox* box = new QGroupBox(tr("Camera model"), this);
209 
210  QVBoxLayout* vbox = new QVBoxLayout(box);
211  vbox->addWidget(camera_model_cb_);
212  vbox->addWidget(camera_params_info_);
213  vbox->addWidget(single_camera_cb_);
214  vbox->addWidget(single_camera_per_folder_cb_);
215  vbox->addWidget(camera_params_exif_rb_);
216  vbox->addWidget(camera_params_custom_rb_);
217  vbox->addWidget(camera_params_text_);
218  vbox->addStretch(1);
219 
220  box->setLayout(vbox);
221 
222  SelectCameraModel(camera_model_cb_->currentIndex());
223 
224  connect(camera_model_cb_,
225  (void (QComboBox::*)(int)) & QComboBox::currentIndexChanged, this,
226  &FeatureExtractionWidget::SelectCameraModel);
227  connect(camera_params_exif_rb_, &QRadioButton::clicked, camera_params_text_,
228  &QLineEdit::setDisabled);
229  connect(camera_params_custom_rb_, &QRadioButton::clicked, camera_params_text_,
230  &QLineEdit::setEnabled);
231 
232  return box;
233 }
234 
235 void FeatureExtractionWidget::showEvent(QShowEvent* event) {
236  parent_->setDisabled(true);
237  ReadOptions();
238 }
239 
240 void FeatureExtractionWidget::hideEvent(QHideEvent* event) {
241  parent_->setEnabled(true);
242  WriteOptions();
243 }
244 
245 void FeatureExtractionWidget::ReadOptions() {
246  const auto camera_code =
247  CameraModelNameToId(options_->image_reader->camera_model);
248  for (size_t i = 0; i < camera_model_ids_.size(); ++i) {
249  if (camera_model_ids_[i] == camera_code) {
250  SelectCameraModel(i);
251  camera_model_cb_->setCurrentIndex(i);
252  break;
253  }
254  }
255  single_camera_cb_->setChecked(options_->image_reader->single_camera);
256  single_camera_per_folder_cb_->setChecked(
257  options_->image_reader->single_camera_per_folder);
258  camera_params_text_->setText(
259  QString::fromStdString(options_->image_reader->camera_params));
260 }
261 
262 void FeatureExtractionWidget::WriteOptions() {
263  options_->image_reader->camera_model =
264  CameraModelIdToName(camera_model_ids_[camera_model_cb_->currentIndex()]);
265  options_->image_reader->single_camera = single_camera_cb_->isChecked();
266  options_->image_reader->single_camera_per_folder =
267  single_camera_per_folder_cb_->isChecked();
268  options_->image_reader->camera_params =
269  camera_params_text_->text().toUtf8().constData();
270 }
271 
272 void FeatureExtractionWidget::SelectCameraModel(const int idx) {
273  const int code = camera_model_ids_[idx];
274  camera_params_info_->setText(QString::fromStdString(StringPrintf(
275  "<small>Parameters: %s</small>", CameraModelParamsInfo(code).c_str())));
276 }
277 
278 void FeatureExtractionWidget::Extract() {
279  // If the custom parameter radiobuttion is not checked, but the
280  // parameters textbox contains parameters.
281  const auto old_camera_params_text = camera_params_text_->text();
282  if (!camera_params_custom_rb_->isChecked()) {
283  camera_params_text_->setText("");
284  }
285 
286  WriteOptions();
287 
288  if (!ExistsCameraModelWithName(options_->image_reader->camera_model)) {
289  QMessageBox::critical(this, "", tr("Camera model does not exist"));
290  return;
291  }
292 
293  const std::vector<double> camera_params =
294  CSVToVector<double>(options_->image_reader->camera_params);
295  const auto camera_code =
296  CameraModelNameToId(options_->image_reader->camera_model);
297 
298  if (camera_params_custom_rb_->isChecked() &&
299  !CameraModelVerifyParams(camera_code, camera_params)) {
300  QMessageBox::critical(this, "", tr("Invalid camera parameters"));
301  return;
302  }
303 
304  QWidget* widget =
305  static_cast<QScrollArea*>(tab_widget_->currentWidget())->widget();
306  static_cast<ExtractionWidget*>(widget)->Run();
307 
308  camera_params_text_->setText(old_camera_params_text);
309 }
310 
311 } // namespace colmap
MouseEvent event
int Run(int argc, const char *argv[])
#define CAMERA_MODEL_CASES
Definition: camera_models.h:95
ExtractionWidget(QWidget *parent, OptionManager *options)
virtual void Run()=0
ThreadControlWidget * thread_control_widget_
FeatureExtractionWidget(QWidget *parent, OptionManager *options)
ImportFeaturesWidget(QWidget *parent, OptionManager *options)
std::shared_ptr< std::string > database_path
std::shared_ptr< SiftExtractionOptions > sift_extraction
std::shared_ptr< ImageReaderOptions > image_reader
std::shared_ptr< std::string > image_path
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))
QLineEdit * AddOptionDirPath(std::string *option, const std::string &label_text)
QCheckBox * AddOptionBool(bool *option, const std::string &label_text)
SIFTExtractionWidget(QWidget *parent, OptionManager *options)
void StartThread(const QString &progress_text, const bool stoppable, Thread *thread)
bool ExistsCameraModelWithName(const std::string &model_name)
bool CameraModelVerifyParams(const int model_id, const std::vector< double > &params)
std::string CameraModelIdToName(const int model_id)
bool ExistsDir(const std::string &path)
Definition: misc.cc:104
std::string StringPrintf(const char *format,...)
Definition: string.cc:131
std::string CameraModelParamsInfo(const int model_id)
int CameraModelNameToId(const std::string &model_name)