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 "util/option_manager.h"
33 
34 #include <boost/filesystem/operations.hpp>
35 #include <boost/property_tree/ini_parser.hpp>
36 
37 #include "base/image_reader.h"
38 #include "controllers/incremental_mapper.h"
39 #include "feature/extraction.h"
40 #include "feature/matching.h"
41 #include "feature/sift.h"
42 #include "mvs/fusion.h"
43 #include "mvs/meshing.h"
44 #include "mvs/patch_match.h"
45 #include "optim/bundle_adjustment.h"
46 #include "ui/render_options.h"
47 #include "util/misc.h"
48 #include "util/random.h"
49 #include "util/version.h"
50 
51 namespace config = boost::program_options;
52 
53 namespace colmap {
54 
OptionManager(bool add_project_options)55 OptionManager::OptionManager(bool add_project_options) {
56   project_path.reset(new std::string());
57   database_path.reset(new std::string());
58   image_path.reset(new std::string());
59 
60   image_reader.reset(new ImageReaderOptions());
61   sift_extraction.reset(new SiftExtractionOptions());
62   sift_matching.reset(new SiftMatchingOptions());
63   exhaustive_matching.reset(new ExhaustiveMatchingOptions());
64   sequential_matching.reset(new SequentialMatchingOptions());
65   vocab_tree_matching.reset(new VocabTreeMatchingOptions());
66   spatial_matching.reset(new SpatialMatchingOptions());
67   transitive_matching.reset(new TransitiveMatchingOptions());
68   image_pairs_matching.reset(new ImagePairsMatchingOptions());
69   bundle_adjustment.reset(new BundleAdjustmentOptions());
70   mapper.reset(new IncrementalMapperOptions());
71   patch_match_stereo.reset(new mvs::PatchMatchOptions());
72   stereo_fusion.reset(new mvs::StereoFusionOptions());
73   poisson_meshing.reset(new mvs::PoissonMeshingOptions());
74   delaunay_meshing.reset(new mvs::DelaunayMeshingOptions());
75   render.reset(new RenderOptions());
76 
77   Reset();
78 
79   desc_->add_options()("help,h", "");
80 
81   AddRandomOptions();
82   AddLogOptions();
83 
84   if (add_project_options) {
85     desc_->add_options()("project_path", config::value<std::string>());
86   }
87 }
88 
ModifyForIndividualData()89 void OptionManager::ModifyForIndividualData() {
90   mapper->min_focal_length_ratio = 0.1;
91   mapper->max_focal_length_ratio = 10;
92   mapper->max_extra_param = std::numeric_limits<double>::max();
93 }
94 
ModifyForVideoData()95 void OptionManager::ModifyForVideoData() {
96   const bool kResetPaths = false;
97   ResetOptions(kResetPaths);
98   mapper->mapper.init_min_tri_angle /= 2;
99   mapper->ba_global_images_ratio = 1.4;
100   mapper->ba_global_points_ratio = 1.4;
101   mapper->min_focal_length_ratio = 0.1;
102   mapper->max_focal_length_ratio = 10;
103   mapper->max_extra_param = std::numeric_limits<double>::max();
104   stereo_fusion->min_num_pixels = 15;
105 }
106 
ModifyForInternetData()107 void OptionManager::ModifyForInternetData() {
108   stereo_fusion->min_num_pixels = 10;
109 }
110 
ModifyForLowQuality()111 void OptionManager::ModifyForLowQuality() {
112   sift_extraction->max_image_size = 1000;
113   sequential_matching->loop_detection_num_images /= 2;
114   vocab_tree_matching->num_images /= 2;
115   mapper->ba_local_max_num_iterations /= 2;
116   mapper->ba_global_max_num_iterations /= 2;
117   mapper->ba_global_images_ratio *= 1.2;
118   mapper->ba_global_points_ratio *= 1.2;
119   mapper->ba_global_max_refinements = 2;
120   patch_match_stereo->max_image_size = 1000;
121   patch_match_stereo->window_radius = 4;
122   patch_match_stereo->window_step = 2;
123   patch_match_stereo->num_samples /= 2;
124   patch_match_stereo->num_iterations = 3;
125   patch_match_stereo->geom_consistency = false;
126   stereo_fusion->check_num_images /= 2;
127   stereo_fusion->max_image_size = 1000;
128 }
129 
ModifyForMediumQuality()130 void OptionManager::ModifyForMediumQuality() {
131   sift_extraction->max_image_size = 1600;
132   sequential_matching->loop_detection_num_images /= 1.5;
133   vocab_tree_matching->num_images /= 1.5;
134   mapper->ba_local_max_num_iterations /= 1.5;
135   mapper->ba_global_max_num_iterations /= 1.5;
136   mapper->ba_global_images_ratio *= 1.1;
137   mapper->ba_global_points_ratio *= 1.1;
138   mapper->ba_global_max_refinements = 2;
139   patch_match_stereo->max_image_size = 1600;
140   patch_match_stereo->window_radius = 4;
141   patch_match_stereo->window_step = 2;
142   patch_match_stereo->num_samples /= 1.5;
143   patch_match_stereo->num_iterations = 5;
144   patch_match_stereo->geom_consistency = false;
145   stereo_fusion->check_num_images /= 1.5;
146   stereo_fusion->max_image_size = 1600;
147 }
148 
ModifyForHighQuality()149 void OptionManager::ModifyForHighQuality() {
150   sift_extraction->estimate_affine_shape = true;
151   sift_extraction->max_image_size = 2400;
152   sift_matching->guided_matching = true;
153   mapper->ba_local_max_num_iterations = 30;
154   mapper->ba_local_max_refinements = 3;
155   mapper->ba_global_max_num_iterations = 75;
156   patch_match_stereo->max_image_size = 2400;
157   stereo_fusion->max_image_size = 2400;
158 }
159 
ModifyForExtremeQuality()160 void OptionManager::ModifyForExtremeQuality() {
161   // Most of the options are set to extreme quality by default.
162   sift_extraction->estimate_affine_shape = true;
163   sift_extraction->domain_size_pooling = true;
164   sift_matching->guided_matching = true;
165   mapper->ba_local_max_num_iterations = 40;
166   mapper->ba_local_max_refinements = 3;
167   mapper->ba_global_max_num_iterations = 100;
168 }
169 
AddAllOptions()170 void OptionManager::AddAllOptions() {
171   AddLogOptions();
172   AddRandomOptions();
173   AddDatabaseOptions();
174   AddImageOptions();
175   AddExtractionOptions();
176   AddMatchingOptions();
177   AddExhaustiveMatchingOptions();
178   AddSequentialMatchingOptions();
179   AddVocabTreeMatchingOptions();
180   AddSpatialMatchingOptions();
181   AddTransitiveMatchingOptions();
182   AddImagePairsMatchingOptions();
183   AddBundleAdjustmentOptions();
184   AddMapperOptions();
185   AddPatchMatchStereoOptions();
186   AddStereoFusionOptions();
187   AddPoissonMeshingOptions();
188   AddDelaunayMeshingOptions();
189   AddRenderOptions();
190 }
191 
AddLogOptions()192 void OptionManager::AddLogOptions() {
193   if (added_log_options_) {
194     return;
195   }
196   added_log_options_ = true;
197 
198   AddAndRegisterDefaultOption("log_to_stderr", &FLAGS_logtostderr);
199   AddAndRegisterDefaultOption("log_level", &FLAGS_v);
200 }
201 
AddRandomOptions()202 void OptionManager::AddRandomOptions() {
203   if (added_random_options_) {
204     return;
205   }
206   added_random_options_ = true;
207 
208   AddAndRegisterDefaultOption("random_seed", &kDefaultPRNGSeed);
209 }
210 
AddDatabaseOptions()211 void OptionManager::AddDatabaseOptions() {
212   if (added_database_options_) {
213     return;
214   }
215   added_database_options_ = true;
216 
217   AddAndRegisterRequiredOption("database_path", database_path.get());
218 }
219 
AddImageOptions()220 void OptionManager::AddImageOptions() {
221   if (added_image_options_) {
222     return;
223   }
224   added_image_options_ = true;
225 
226   AddAndRegisterRequiredOption("image_path", image_path.get());
227 }
228 
AddExtractionOptions()229 void OptionManager::AddExtractionOptions() {
230   if (added_extraction_options_) {
231     return;
232   }
233   added_extraction_options_ = true;
234 
235   AddAndRegisterDefaultOption("ImageReader.mask_path",
236                               &image_reader->mask_path);
237   AddAndRegisterDefaultOption("ImageReader.camera_model",
238                               &image_reader->camera_model);
239   AddAndRegisterDefaultOption("ImageReader.single_camera",
240                               &image_reader->single_camera);
241   AddAndRegisterDefaultOption("ImageReader.single_camera_per_folder",
242                               &image_reader->single_camera_per_folder);
243   AddAndRegisterDefaultOption("ImageReader.existing_camera_id",
244                               &image_reader->existing_camera_id);
245   AddAndRegisterDefaultOption("ImageReader.camera_params",
246                               &image_reader->camera_params);
247   AddAndRegisterDefaultOption("ImageReader.default_focal_length_factor",
248                               &image_reader->default_focal_length_factor);
249   AddAndRegisterDefaultOption("ImageReader.camera_mask_path",
250                               &image_reader->camera_mask_path);
251 
252   AddAndRegisterDefaultOption("SiftExtraction.num_threads",
253                               &sift_extraction->num_threads);
254   AddAndRegisterDefaultOption("SiftExtraction.use_gpu",
255                               &sift_extraction->use_gpu);
256   AddAndRegisterDefaultOption("SiftExtraction.gpu_index",
257                               &sift_extraction->gpu_index);
258   AddAndRegisterDefaultOption("SiftExtraction.max_image_size",
259                               &sift_extraction->max_image_size);
260   AddAndRegisterDefaultOption("SiftExtraction.max_num_features",
261                               &sift_extraction->max_num_features);
262   AddAndRegisterDefaultOption("SiftExtraction.first_octave",
263                               &sift_extraction->first_octave);
264   AddAndRegisterDefaultOption("SiftExtraction.num_octaves",
265                               &sift_extraction->num_octaves);
266   AddAndRegisterDefaultOption("SiftExtraction.octave_resolution",
267                               &sift_extraction->octave_resolution);
268   AddAndRegisterDefaultOption("SiftExtraction.peak_threshold",
269                               &sift_extraction->peak_threshold);
270   AddAndRegisterDefaultOption("SiftExtraction.edge_threshold",
271                               &sift_extraction->edge_threshold);
272   AddAndRegisterDefaultOption("SiftExtraction.estimate_affine_shape",
273                               &sift_extraction->estimate_affine_shape);
274   AddAndRegisterDefaultOption("SiftExtraction.max_num_orientations",
275                               &sift_extraction->max_num_orientations);
276   AddAndRegisterDefaultOption("SiftExtraction.upright",
277                               &sift_extraction->upright);
278   AddAndRegisterDefaultOption("SiftExtraction.domain_size_pooling",
279                               &sift_extraction->domain_size_pooling);
280   AddAndRegisterDefaultOption("SiftExtraction.dsp_min_scale",
281                               &sift_extraction->dsp_min_scale);
282   AddAndRegisterDefaultOption("SiftExtraction.dsp_max_scale",
283                               &sift_extraction->dsp_max_scale);
284   AddAndRegisterDefaultOption("SiftExtraction.dsp_num_scales",
285                               &sift_extraction->dsp_num_scales);
286 }
287 
AddMatchingOptions()288 void OptionManager::AddMatchingOptions() {
289   if (added_match_options_) {
290     return;
291   }
292   added_match_options_ = true;
293 
294   AddAndRegisterDefaultOption("SiftMatching.num_threads",
295                               &sift_matching->num_threads);
296   AddAndRegisterDefaultOption("SiftMatching.use_gpu", &sift_matching->use_gpu);
297   AddAndRegisterDefaultOption("SiftMatching.gpu_index",
298                               &sift_matching->gpu_index);
299   AddAndRegisterDefaultOption("SiftMatching.max_ratio",
300                               &sift_matching->max_ratio);
301   AddAndRegisterDefaultOption("SiftMatching.max_distance",
302                               &sift_matching->max_distance);
303   AddAndRegisterDefaultOption("SiftMatching.cross_check",
304                               &sift_matching->cross_check);
305   AddAndRegisterDefaultOption("SiftMatching.max_error",
306                               &sift_matching->max_error);
307   AddAndRegisterDefaultOption("SiftMatching.max_num_matches",
308                               &sift_matching->max_num_matches);
309   AddAndRegisterDefaultOption("SiftMatching.confidence",
310                               &sift_matching->confidence);
311   AddAndRegisterDefaultOption("SiftMatching.max_num_trials",
312                               &sift_matching->max_num_trials);
313   AddAndRegisterDefaultOption("SiftMatching.min_inlier_ratio",
314                               &sift_matching->min_inlier_ratio);
315   AddAndRegisterDefaultOption("SiftMatching.min_num_inliers",
316                               &sift_matching->min_num_inliers);
317   AddAndRegisterDefaultOption("SiftMatching.multiple_models",
318                               &sift_matching->multiple_models);
319   AddAndRegisterDefaultOption("SiftMatching.guided_matching",
320                               &sift_matching->guided_matching);
321 }
322 
AddExhaustiveMatchingOptions()323 void OptionManager::AddExhaustiveMatchingOptions() {
324   if (added_exhaustive_match_options_) {
325     return;
326   }
327   added_exhaustive_match_options_ = true;
328 
329   AddMatchingOptions();
330 
331   AddAndRegisterDefaultOption("ExhaustiveMatching.block_size",
332                               &exhaustive_matching->block_size);
333 }
334 
AddSequentialMatchingOptions()335 void OptionManager::AddSequentialMatchingOptions() {
336   if (added_sequential_match_options_) {
337     return;
338   }
339   added_sequential_match_options_ = true;
340 
341   AddMatchingOptions();
342 
343   AddAndRegisterDefaultOption("SequentialMatching.overlap",
344                               &sequential_matching->overlap);
345   AddAndRegisterDefaultOption("SequentialMatching.quadratic_overlap",
346                               &sequential_matching->quadratic_overlap);
347   AddAndRegisterDefaultOption("SequentialMatching.loop_detection",
348                               &sequential_matching->loop_detection);
349   AddAndRegisterDefaultOption("SequentialMatching.loop_detection_period",
350                               &sequential_matching->loop_detection_period);
351   AddAndRegisterDefaultOption("SequentialMatching.loop_detection_num_images",
352                               &sequential_matching->loop_detection_num_images);
353   AddAndRegisterDefaultOption(
354       "SequentialMatching.loop_detection_num_nearest_neighbors",
355       &sequential_matching->loop_detection_num_nearest_neighbors);
356   AddAndRegisterDefaultOption("SequentialMatching.loop_detection_num_checks",
357                               &sequential_matching->loop_detection_num_checks);
358   AddAndRegisterDefaultOption(
359       "SequentialMatching.loop_detection_num_images_after_verification",
360       &sequential_matching->loop_detection_num_images_after_verification);
361   AddAndRegisterDefaultOption(
362       "SequentialMatching.loop_detection_max_num_features",
363       &sequential_matching->loop_detection_max_num_features);
364   AddAndRegisterDefaultOption("SequentialMatching.vocab_tree_path",
365                               &sequential_matching->vocab_tree_path);
366 }
367 
AddVocabTreeMatchingOptions()368 void OptionManager::AddVocabTreeMatchingOptions() {
369   if (added_vocab_tree_match_options_) {
370     return;
371   }
372   added_vocab_tree_match_options_ = true;
373 
374   AddMatchingOptions();
375 
376   AddAndRegisterDefaultOption("VocabTreeMatching.num_images",
377                               &vocab_tree_matching->num_images);
378   AddAndRegisterDefaultOption("VocabTreeMatching.num_nearest_neighbors",
379                               &vocab_tree_matching->num_nearest_neighbors);
380   AddAndRegisterDefaultOption("VocabTreeMatching.num_checks",
381                               &vocab_tree_matching->num_checks);
382   AddAndRegisterDefaultOption(
383       "VocabTreeMatching.num_images_after_verification",
384       &vocab_tree_matching->num_images_after_verification);
385   AddAndRegisterDefaultOption("VocabTreeMatching.max_num_features",
386                               &vocab_tree_matching->max_num_features);
387   AddAndRegisterDefaultOption("VocabTreeMatching.vocab_tree_path",
388                               &vocab_tree_matching->vocab_tree_path);
389   AddAndRegisterDefaultOption("VocabTreeMatching.match_list_path",
390                               &vocab_tree_matching->match_list_path);
391 }
392 
AddSpatialMatchingOptions()393 void OptionManager::AddSpatialMatchingOptions() {
394   if (added_spatial_match_options_) {
395     return;
396   }
397   added_spatial_match_options_ = true;
398 
399   AddMatchingOptions();
400 
401   AddAndRegisterDefaultOption("SpatialMatching.is_gps",
402                               &spatial_matching->is_gps);
403   AddAndRegisterDefaultOption("SpatialMatching.ignore_z",
404                               &spatial_matching->ignore_z);
405   AddAndRegisterDefaultOption("SpatialMatching.max_num_neighbors",
406                               &spatial_matching->max_num_neighbors);
407   AddAndRegisterDefaultOption("SpatialMatching.max_distance",
408                               &spatial_matching->max_distance);
409 }
410 
AddTransitiveMatchingOptions()411 void OptionManager::AddTransitiveMatchingOptions() {
412   if (added_transitive_match_options_) {
413     return;
414   }
415   added_transitive_match_options_ = true;
416 
417   AddMatchingOptions();
418 
419   AddAndRegisterDefaultOption("TransitiveMatching.batch_size",
420                               &transitive_matching->batch_size);
421   AddAndRegisterDefaultOption("TransitiveMatching.num_iterations",
422                               &transitive_matching->num_iterations);
423 }
424 
AddImagePairsMatchingOptions()425 void OptionManager::AddImagePairsMatchingOptions() {
426   if (added_image_pairs_match_options_) {
427     return;
428   }
429   added_image_pairs_match_options_ = true;
430 
431   AddMatchingOptions();
432 
433   AddAndRegisterDefaultOption("ImagePairsMatching.block_size",
434                               &image_pairs_matching->block_size);
435 }
436 
AddBundleAdjustmentOptions()437 void OptionManager::AddBundleAdjustmentOptions() {
438   if (added_ba_options_) {
439     return;
440   }
441   added_ba_options_ = true;
442 
443   AddAndRegisterDefaultOption(
444       "BundleAdjustment.max_num_iterations",
445       &bundle_adjustment->solver_options.max_num_iterations);
446   AddAndRegisterDefaultOption(
447       "BundleAdjustment.max_linear_solver_iterations",
448       &bundle_adjustment->solver_options.max_linear_solver_iterations);
449   AddAndRegisterDefaultOption(
450       "BundleAdjustment.function_tolerance",
451       &bundle_adjustment->solver_options.function_tolerance);
452   AddAndRegisterDefaultOption(
453       "BundleAdjustment.gradient_tolerance",
454       &bundle_adjustment->solver_options.gradient_tolerance);
455   AddAndRegisterDefaultOption(
456       "BundleAdjustment.parameter_tolerance",
457       &bundle_adjustment->solver_options.parameter_tolerance);
458   AddAndRegisterDefaultOption("BundleAdjustment.refine_focal_length",
459                               &bundle_adjustment->refine_focal_length);
460   AddAndRegisterDefaultOption("BundleAdjustment.refine_principal_point",
461                               &bundle_adjustment->refine_principal_point);
462   AddAndRegisterDefaultOption("BundleAdjustment.refine_extra_params",
463                               &bundle_adjustment->refine_extra_params);
464   AddAndRegisterDefaultOption("BundleAdjustment.refine_extrinsics",
465                               &bundle_adjustment->refine_extrinsics);
466 }
467 
AddMapperOptions()468 void OptionManager::AddMapperOptions() {
469   if (added_mapper_options_) {
470     return;
471   }
472   added_mapper_options_ = true;
473 
474   AddAndRegisterDefaultOption("Mapper.min_num_matches",
475                               &mapper->min_num_matches);
476   AddAndRegisterDefaultOption("Mapper.ignore_watermarks",
477                               &mapper->ignore_watermarks);
478   AddAndRegisterDefaultOption("Mapper.multiple_models",
479                               &mapper->multiple_models);
480   AddAndRegisterDefaultOption("Mapper.max_num_models", &mapper->max_num_models);
481   AddAndRegisterDefaultOption("Mapper.max_model_overlap",
482                               &mapper->max_model_overlap);
483   AddAndRegisterDefaultOption("Mapper.min_model_size", &mapper->min_model_size);
484   AddAndRegisterDefaultOption("Mapper.init_image_id1", &mapper->init_image_id1);
485   AddAndRegisterDefaultOption("Mapper.init_image_id2", &mapper->init_image_id2);
486   AddAndRegisterDefaultOption("Mapper.init_num_trials",
487                               &mapper->init_num_trials);
488   AddAndRegisterDefaultOption("Mapper.extract_colors", &mapper->extract_colors);
489   AddAndRegisterDefaultOption("Mapper.num_threads", &mapper->num_threads);
490   AddAndRegisterDefaultOption("Mapper.min_focal_length_ratio",
491                               &mapper->min_focal_length_ratio);
492   AddAndRegisterDefaultOption("Mapper.max_focal_length_ratio",
493                               &mapper->max_focal_length_ratio);
494   AddAndRegisterDefaultOption("Mapper.max_extra_param",
495                               &mapper->max_extra_param);
496   AddAndRegisterDefaultOption("Mapper.ba_refine_focal_length",
497                               &mapper->ba_refine_focal_length);
498   AddAndRegisterDefaultOption("Mapper.ba_refine_principal_point",
499                               &mapper->ba_refine_principal_point);
500   AddAndRegisterDefaultOption("Mapper.ba_refine_extra_params",
501                               &mapper->ba_refine_extra_params);
502   AddAndRegisterDefaultOption(
503       "Mapper.ba_min_num_residuals_for_multi_threading",
504       &mapper->ba_min_num_residuals_for_multi_threading);
505   AddAndRegisterDefaultOption("Mapper.ba_local_num_images",
506                               &mapper->ba_local_num_images);
507   AddAndRegisterDefaultOption("Mapper.ba_local_max_num_iterations",
508                               &mapper->ba_local_max_num_iterations);
509   AddAndRegisterDefaultOption("Mapper.ba_global_use_pba",
510                               &mapper->ba_global_use_pba);
511   AddAndRegisterDefaultOption("Mapper.ba_global_pba_gpu_index",
512                               &mapper->ba_global_pba_gpu_index);
513   AddAndRegisterDefaultOption("Mapper.ba_global_images_ratio",
514                               &mapper->ba_global_images_ratio);
515   AddAndRegisterDefaultOption("Mapper.ba_global_points_ratio",
516                               &mapper->ba_global_points_ratio);
517   AddAndRegisterDefaultOption("Mapper.ba_global_images_freq",
518                               &mapper->ba_global_images_freq);
519   AddAndRegisterDefaultOption("Mapper.ba_global_points_freq",
520                               &mapper->ba_global_points_freq);
521   AddAndRegisterDefaultOption("Mapper.ba_global_max_num_iterations",
522                               &mapper->ba_global_max_num_iterations);
523   AddAndRegisterDefaultOption("Mapper.ba_global_max_refinements",
524                               &mapper->ba_global_max_refinements);
525   AddAndRegisterDefaultOption("Mapper.ba_global_max_refinement_change",
526                               &mapper->ba_global_max_refinement_change);
527   AddAndRegisterDefaultOption("Mapper.ba_local_max_refinements",
528                               &mapper->ba_local_max_refinements);
529   AddAndRegisterDefaultOption("Mapper.ba_local_max_refinement_change",
530                               &mapper->ba_local_max_refinement_change);
531   AddAndRegisterDefaultOption("Mapper.snapshot_path", &mapper->snapshot_path);
532   AddAndRegisterDefaultOption("Mapper.snapshot_images_freq",
533                               &mapper->snapshot_images_freq);
534   AddAndRegisterDefaultOption("Mapper.fix_existing_images",
535                               &mapper->fix_existing_images);
536 
537   // IncrementalMapper.
538   AddAndRegisterDefaultOption("Mapper.init_min_num_inliers",
539                               &mapper->mapper.init_min_num_inliers);
540   AddAndRegisterDefaultOption("Mapper.init_max_error",
541                               &mapper->mapper.init_max_error);
542   AddAndRegisterDefaultOption("Mapper.init_max_forward_motion",
543                               &mapper->mapper.init_max_forward_motion);
544   AddAndRegisterDefaultOption("Mapper.init_min_tri_angle",
545                               &mapper->mapper.init_min_tri_angle);
546   AddAndRegisterDefaultOption("Mapper.init_max_reg_trials",
547                               &mapper->mapper.init_max_reg_trials);
548   AddAndRegisterDefaultOption("Mapper.abs_pose_max_error",
549                               &mapper->mapper.abs_pose_max_error);
550   AddAndRegisterDefaultOption("Mapper.abs_pose_min_num_inliers",
551                               &mapper->mapper.abs_pose_min_num_inliers);
552   AddAndRegisterDefaultOption("Mapper.abs_pose_min_inlier_ratio",
553                               &mapper->mapper.abs_pose_min_inlier_ratio);
554   AddAndRegisterDefaultOption("Mapper.filter_max_reproj_error",
555                               &mapper->mapper.filter_max_reproj_error);
556   AddAndRegisterDefaultOption("Mapper.filter_min_tri_angle",
557                               &mapper->mapper.filter_min_tri_angle);
558   AddAndRegisterDefaultOption("Mapper.max_reg_trials",
559                               &mapper->mapper.max_reg_trials);
560   AddAndRegisterDefaultOption("Mapper.local_ba_min_tri_angle",
561                               &mapper->mapper.local_ba_min_tri_angle);
562 
563   // IncrementalTriangulator.
564   AddAndRegisterDefaultOption("Mapper.tri_max_transitivity",
565                               &mapper->triangulation.max_transitivity);
566   AddAndRegisterDefaultOption("Mapper.tri_create_max_angle_error",
567                               &mapper->triangulation.create_max_angle_error);
568   AddAndRegisterDefaultOption("Mapper.tri_continue_max_angle_error",
569                               &mapper->triangulation.continue_max_angle_error);
570   AddAndRegisterDefaultOption("Mapper.tri_merge_max_reproj_error",
571                               &mapper->triangulation.merge_max_reproj_error);
572   AddAndRegisterDefaultOption("Mapper.tri_complete_max_reproj_error",
573                               &mapper->triangulation.complete_max_reproj_error);
574   AddAndRegisterDefaultOption("Mapper.tri_complete_max_transitivity",
575                               &mapper->triangulation.complete_max_transitivity);
576   AddAndRegisterDefaultOption("Mapper.tri_re_max_angle_error",
577                               &mapper->triangulation.re_max_angle_error);
578   AddAndRegisterDefaultOption("Mapper.tri_re_min_ratio",
579                               &mapper->triangulation.re_min_ratio);
580   AddAndRegisterDefaultOption("Mapper.tri_re_max_trials",
581                               &mapper->triangulation.re_max_trials);
582   AddAndRegisterDefaultOption("Mapper.tri_min_angle",
583                               &mapper->triangulation.min_angle);
584   AddAndRegisterDefaultOption("Mapper.tri_ignore_two_view_tracks",
585                               &mapper->triangulation.ignore_two_view_tracks);
586 }
587 
AddPatchMatchStereoOptions()588 void OptionManager::AddPatchMatchStereoOptions() {
589   if (added_patch_match_stereo_options_) {
590     return;
591   }
592   added_patch_match_stereo_options_ = true;
593 
594   AddAndRegisterDefaultOption("PatchMatchStereo.max_image_size",
595                               &patch_match_stereo->max_image_size);
596   AddAndRegisterDefaultOption("PatchMatchStereo.gpu_index",
597                               &patch_match_stereo->gpu_index);
598   AddAndRegisterDefaultOption("PatchMatchStereo.depth_min",
599                               &patch_match_stereo->depth_min);
600   AddAndRegisterDefaultOption("PatchMatchStereo.depth_max",
601                               &patch_match_stereo->depth_max);
602   AddAndRegisterDefaultOption("PatchMatchStereo.window_radius",
603                               &patch_match_stereo->window_radius);
604   AddAndRegisterDefaultOption("PatchMatchStereo.window_step",
605                               &patch_match_stereo->window_step);
606   AddAndRegisterDefaultOption("PatchMatchStereo.sigma_spatial",
607                               &patch_match_stereo->sigma_spatial);
608   AddAndRegisterDefaultOption("PatchMatchStereo.sigma_color",
609                               &patch_match_stereo->sigma_color);
610   AddAndRegisterDefaultOption("PatchMatchStereo.num_samples",
611                               &patch_match_stereo->num_samples);
612   AddAndRegisterDefaultOption("PatchMatchStereo.ncc_sigma",
613                               &patch_match_stereo->ncc_sigma);
614   AddAndRegisterDefaultOption("PatchMatchStereo.min_triangulation_angle",
615                               &patch_match_stereo->min_triangulation_angle);
616   AddAndRegisterDefaultOption("PatchMatchStereo.incident_angle_sigma",
617                               &patch_match_stereo->incident_angle_sigma);
618   AddAndRegisterDefaultOption("PatchMatchStereo.num_iterations",
619                               &patch_match_stereo->num_iterations);
620   AddAndRegisterDefaultOption("PatchMatchStereo.geom_consistency",
621                               &patch_match_stereo->geom_consistency);
622   AddAndRegisterDefaultOption(
623       "PatchMatchStereo.geom_consistency_regularizer",
624       &patch_match_stereo->geom_consistency_regularizer);
625   AddAndRegisterDefaultOption("PatchMatchStereo.geom_consistency_max_cost",
626                               &patch_match_stereo->geom_consistency_max_cost);
627   AddAndRegisterDefaultOption("PatchMatchStereo.filter",
628                               &patch_match_stereo->filter);
629   AddAndRegisterDefaultOption("PatchMatchStereo.filter_min_ncc",
630                               &patch_match_stereo->filter_min_ncc);
631   AddAndRegisterDefaultOption(
632       "PatchMatchStereo.filter_min_triangulation_angle",
633       &patch_match_stereo->filter_min_triangulation_angle);
634   AddAndRegisterDefaultOption("PatchMatchStereo.filter_min_num_consistent",
635                               &patch_match_stereo->filter_min_num_consistent);
636   AddAndRegisterDefaultOption(
637       "PatchMatchStereo.filter_geom_consistency_max_cost",
638       &patch_match_stereo->filter_geom_consistency_max_cost);
639   AddAndRegisterDefaultOption("PatchMatchStereo.cache_size",
640                               &patch_match_stereo->cache_size);
641   AddAndRegisterDefaultOption("PatchMatchStereo.write_consistency_graph",
642                               &patch_match_stereo->write_consistency_graph);
643 }
644 
AddStereoFusionOptions()645 void OptionManager::AddStereoFusionOptions() {
646   if (added_stereo_fusion_options_) {
647     return;
648   }
649   added_stereo_fusion_options_ = true;
650 
651   AddAndRegisterDefaultOption("StereoFusion.max_image_size",
652                               &stereo_fusion->max_image_size);
653   AddAndRegisterDefaultOption("StereoFusion.min_num_pixels",
654                               &stereo_fusion->min_num_pixels);
655   AddAndRegisterDefaultOption("StereoFusion.max_num_pixels",
656                               &stereo_fusion->max_num_pixels);
657   AddAndRegisterDefaultOption("StereoFusion.max_traversal_depth",
658                               &stereo_fusion->max_traversal_depth);
659   AddAndRegisterDefaultOption("StereoFusion.max_reproj_error",
660                               &stereo_fusion->max_reproj_error);
661   AddAndRegisterDefaultOption("StereoFusion.max_depth_error",
662                               &stereo_fusion->max_depth_error);
663   AddAndRegisterDefaultOption("StereoFusion.max_normal_error",
664                               &stereo_fusion->max_normal_error);
665   AddAndRegisterDefaultOption("StereoFusion.check_num_images",
666                               &stereo_fusion->check_num_images);
667   AddAndRegisterDefaultOption("StereoFusion.cache_size",
668                               &stereo_fusion->cache_size);
669 }
670 
AddPoissonMeshingOptions()671 void OptionManager::AddPoissonMeshingOptions() {
672   if (added_poisson_meshing_options_) {
673     return;
674   }
675   added_poisson_meshing_options_ = true;
676 
677   AddAndRegisterDefaultOption("PoissonMeshing.point_weight",
678                               &poisson_meshing->point_weight);
679   AddAndRegisterDefaultOption("PoissonMeshing.depth", &poisson_meshing->depth);
680   AddAndRegisterDefaultOption("PoissonMeshing.color", &poisson_meshing->color);
681   AddAndRegisterDefaultOption("PoissonMeshing.trim", &poisson_meshing->trim);
682   AddAndRegisterDefaultOption("PoissonMeshing.num_threads",
683                               &poisson_meshing->num_threads);
684 }
685 
AddDelaunayMeshingOptions()686 void OptionManager::AddDelaunayMeshingOptions() {
687   if (added_delaunay_meshing_options_) {
688     return;
689   }
690   added_delaunay_meshing_options_ = true;
691 
692   AddAndRegisterDefaultOption("DelaunayMeshing.max_proj_dist",
693                               &delaunay_meshing->max_proj_dist);
694   AddAndRegisterDefaultOption("DelaunayMeshing.max_depth_dist",
695                               &delaunay_meshing->max_depth_dist);
696   AddAndRegisterDefaultOption("DelaunayMeshing.distance_sigma_factor",
697                               &delaunay_meshing->distance_sigma_factor);
698   AddAndRegisterDefaultOption("DelaunayMeshing.quality_regularization",
699                               &delaunay_meshing->quality_regularization);
700   AddAndRegisterDefaultOption("DelaunayMeshing.max_side_length_factor",
701                               &delaunay_meshing->max_side_length_factor);
702   AddAndRegisterDefaultOption("DelaunayMeshing.max_side_length_percentile",
703                               &delaunay_meshing->max_side_length_percentile);
704   AddAndRegisterDefaultOption("DelaunayMeshing.num_threads",
705                               &delaunay_meshing->num_threads);
706 }
707 
AddRenderOptions()708 void OptionManager::AddRenderOptions() {
709   if (added_render_options_) {
710     return;
711   }
712   added_render_options_ = true;
713 
714   AddAndRegisterDefaultOption("Render.min_track_len", &render->min_track_len);
715   AddAndRegisterDefaultOption("Render.max_error", &render->max_error);
716   AddAndRegisterDefaultOption("Render.refresh_rate", &render->refresh_rate);
717   AddAndRegisterDefaultOption("Render.adapt_refresh_rate",
718                               &render->adapt_refresh_rate);
719   AddAndRegisterDefaultOption("Render.image_connections",
720                               &render->image_connections);
721   AddAndRegisterDefaultOption("Render.projection_type",
722                               &render->projection_type);
723 }
724 
Reset()725 void OptionManager::Reset() {
726   FLAGS_logtostderr = false;
727   FLAGS_v = 2;
728 
729   const bool kResetPaths = true;
730   ResetOptions(kResetPaths);
731 
732   desc_.reset(new boost::program_options::options_description());
733 
734   options_bool_.clear();
735   options_int_.clear();
736   options_double_.clear();
737   options_string_.clear();
738 
739   added_log_options_ = false;
740   added_random_options_ = false;
741   added_database_options_ = false;
742   added_image_options_ = false;
743   added_extraction_options_ = false;
744   added_match_options_ = false;
745   added_exhaustive_match_options_ = false;
746   added_sequential_match_options_ = false;
747   added_vocab_tree_match_options_ = false;
748   added_spatial_match_options_ = false;
749   added_transitive_match_options_ = false;
750   added_image_pairs_match_options_ = false;
751   added_ba_options_ = false;
752   added_mapper_options_ = false;
753   added_patch_match_stereo_options_ = false;
754   added_stereo_fusion_options_ = false;
755   added_poisson_meshing_options_ = false;
756   added_delaunay_meshing_options_ = false;
757   added_render_options_ = false;
758 }
759 
ResetOptions(const bool reset_paths)760 void OptionManager::ResetOptions(const bool reset_paths) {
761   if (reset_paths) {
762     *project_path = "";
763     *database_path = "";
764     *image_path = "";
765   }
766   *image_reader = ImageReaderOptions();
767   *sift_extraction = SiftExtractionOptions();
768   *sift_matching = SiftMatchingOptions();
769   *exhaustive_matching = ExhaustiveMatchingOptions();
770   *sequential_matching = SequentialMatchingOptions();
771   *vocab_tree_matching = VocabTreeMatchingOptions();
772   *spatial_matching = SpatialMatchingOptions();
773   *transitive_matching = TransitiveMatchingOptions();
774   *image_pairs_matching = ImagePairsMatchingOptions();
775   *bundle_adjustment = BundleAdjustmentOptions();
776   *mapper = IncrementalMapperOptions();
777   *patch_match_stereo = mvs::PatchMatchOptions();
778   *stereo_fusion = mvs::StereoFusionOptions();
779   *poisson_meshing = mvs::PoissonMeshingOptions();
780   *delaunay_meshing = mvs::DelaunayMeshingOptions();
781   *render = RenderOptions();
782 }
783 
Check()784 bool OptionManager::Check() {
785   bool success = true;
786 
787   if (added_database_options_) {
788     const auto database_parent_path = GetParentDir(*database_path);
789     success = success && CHECK_OPTION_IMPL(!ExistsDir(*database_path)) &&
790               CHECK_OPTION_IMPL(database_parent_path == "" ||
791                                 ExistsDir(database_parent_path));
792   }
793 
794   if (added_image_options_)
795     success = success && CHECK_OPTION_IMPL(ExistsDir(*image_path));
796 
797   if (image_reader) success = success && image_reader->Check();
798   if (sift_extraction) success = success && sift_extraction->Check();
799 
800   if (sift_matching) success = success && sift_matching->Check();
801   if (exhaustive_matching) success = success && exhaustive_matching->Check();
802   if (sequential_matching) success = success && sequential_matching->Check();
803   if (vocab_tree_matching) success = success && vocab_tree_matching->Check();
804   if (spatial_matching) success = success && spatial_matching->Check();
805   if (transitive_matching) success = success && transitive_matching->Check();
806   if (image_pairs_matching) success = success && image_pairs_matching->Check();
807 
808   if (bundle_adjustment) success = success && bundle_adjustment->Check();
809   if (mapper) success = success && mapper->Check();
810 
811   if (patch_match_stereo) success = success && patch_match_stereo->Check();
812   if (stereo_fusion) success = success && stereo_fusion->Check();
813   if (poisson_meshing) success = success && poisson_meshing->Check();
814   if (delaunay_meshing) success = success && delaunay_meshing->Check();
815 
816   if (render) success = success && render->Check();
817 
818   return success;
819 }
820 
Parse(const int argc,char ** argv)821 void OptionManager::Parse(const int argc, char** argv) {
822   config::variables_map vmap;
823 
824   try {
825     config::store(config::parse_command_line(argc, argv, *desc_), vmap);
826 
827     if (vmap.count("help")) {
828       std::cout << StringPrintf("%s (%s)", GetVersionInfo().c_str(),
829                                 GetBuildInfo().c_str())
830                 << std::endl
831                 << std::endl;
832       std::cout
833           << "Options can either be specified via command-line or by defining"
834           << std::endl
835           << "them in a .ini project file passed to `--project_path`."
836           << std::endl
837           << std::endl;
838       std::cout << *desc_ << std::endl;
839       exit(EXIT_SUCCESS);
840     }
841 
842     if (vmap.count("project_path")) {
843       *project_path = vmap["project_path"].as<std::string>();
844       if (!Read(*project_path)) {
845         exit(EXIT_FAILURE);
846       }
847     } else {
848       vmap.notify();
849     }
850   } catch (std::exception& exc) {
851     std::cerr << "ERROR: Failed to parse options - " << exc.what() << "."
852               << std::endl;
853     exit(EXIT_FAILURE);
854   } catch (...) {
855     std::cerr << "ERROR: Failed to parse options for unknown reason."
856               << std::endl;
857     exit(EXIT_FAILURE);
858   }
859 
860   if (!Check()) {
861     std::cerr << "ERROR: Invalid options provided." << std::endl;
862     exit(EXIT_FAILURE);
863   }
864 }
865 
Read(const std::string & path)866 bool OptionManager::Read(const std::string& path) {
867   config::variables_map vmap;
868 
869   if (!ExistsFile(path)) {
870     std::cout << "ERROR: Configuration file does not exist." << std::endl;
871     return false;
872   }
873 
874   try {
875     std::ifstream file(path);
876     CHECK(file.is_open()) << path;
877     config::store(config::parse_config_file(file, *desc_), vmap);
878     vmap.notify();
879   } catch (std::exception& e) {
880     std::cout << "ERROR: Failed to parse options " << e.what() << "."
881               << std::endl;
882     return false;
883   } catch (...) {
884     std::cout << "ERROR: Failed to parse options for unknown reason."
885               << std::endl;
886     return false;
887   }
888 
889   return Check();
890 }
891 
ReRead(const std::string & path)892 bool OptionManager::ReRead(const std::string& path) {
893   Reset();
894   AddAllOptions();
895   return Read(path);
896 }
897 
Write(const std::string & path) const898 void OptionManager::Write(const std::string& path) const {
899   boost::property_tree::ptree pt;
900 
901   // First, put all options without a section and then those with a section.
902   // This is necessary as otherwise older Boost versions will write the
903   // options without a section in between other sections and therefore
904   // the errors will be assigned to the wrong section if read later.
905 
906   for (const auto& option : options_bool_) {
907     if (!StringContains(option.first, ".")) {
908       pt.put(option.first, *option.second);
909     }
910   }
911 
912   for (const auto& option : options_int_) {
913     if (!StringContains(option.first, ".")) {
914       pt.put(option.first, *option.second);
915     }
916   }
917 
918   for (const auto& option : options_double_) {
919     if (!StringContains(option.first, ".")) {
920       pt.put(option.first, *option.second);
921     }
922   }
923 
924   for (const auto& option : options_string_) {
925     if (!StringContains(option.first, ".")) {
926       pt.put(option.first, *option.second);
927     }
928   }
929 
930   for (const auto& option : options_bool_) {
931     if (StringContains(option.first, ".")) {
932       pt.put(option.first, *option.second);
933     }
934   }
935 
936   for (const auto& option : options_int_) {
937     if (StringContains(option.first, ".")) {
938       pt.put(option.first, *option.second);
939     }
940   }
941 
942   for (const auto& option : options_double_) {
943     if (StringContains(option.first, ".")) {
944       pt.put(option.first, *option.second);
945     }
946   }
947 
948   for (const auto& option : options_string_) {
949     if (StringContains(option.first, ".")) {
950       pt.put(option.first, *option.second);
951     }
952   }
953 
954   boost::property_tree::write_ini(path, pt);
955 }
956 
957 }  // namespace colmap
958