Skip to content

Commit

Permalink
Make global descriptor flags available to CLI. Small improvments to s…
Browse files Browse the repository at this point in the history
…tability of FV computation.
  • Loading branch information
Chris Sweeney authored and Chris Sweeney committed Sep 29, 2018
1 parent 287c009 commit 8d5bb9b
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 75 deletions.
186 changes: 120 additions & 66 deletions applications/build_reconstruction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney ([email protected])

#include <glog/logging.h>
#include <gflags/gflags.h>
#include <time.h>
#include <theia/theia.h>
#include <chrono> // NOLINT
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <string>
#include <theia/theia.h>
#include <time.h>
#include <vector>

#include "applications/command_line_helpers.h"
Expand All @@ -46,72 +46,102 @@
DEFINE_string(images, "", "Wildcard of images to reconstruct.");
DEFINE_string(image_masks, "", "Wildcard of image masks to reconstruct.");
DEFINE_string(matches_file, "", "Filename of the matches file.");
DEFINE_string(calibration_file, "",
DEFINE_string(calibration_file,
"",
"Calibration file containing image calibration data.");
DEFINE_string(
output_matches_file, "",
output_matches_file,
"",
"File to write the two-view matches to. This file can be used in "
"future iterations as input to the reconstruction builder. Leave empty if "
"you do not want to output matches.");
DEFINE_string(
output_reconstruction, "",
output_reconstruction,
"",
"Filename to write reconstruction to. The filename will be appended with "
"the reconstruction number if multiple reconstructions are created.");

// Multithreading.
DEFINE_int32(num_threads, 1,
DEFINE_int32(num_threads,
1,
"Number of threads to use for feature extraction and matching.");

// Feature and matching options.
DEFINE_string(
descriptor, "SIFT",
descriptor,
"SIFT",
"Type of feature descriptor to use. Must be one of the following: "
"SIFT");
DEFINE_string(feature_density, "NORMAL",
DEFINE_string(feature_density,
"NORMAL",
"Set to SPARSE, NORMAL, or DENSE to extract fewer or more "
"features from each image.");
DEFINE_string(matching_strategy, "CASCADE_HASHING",
DEFINE_string(matching_strategy,
"CASCADE_HASHING",
"Strategy used to match features. Must be BRUTE_FORCE "
" or CASCADE_HASHING");
DEFINE_bool(match_out_of_core, true,
DEFINE_bool(match_out_of_core,
true,
"Perform matching out of core by saving features to disk and "
"reading them as needed. Set to false to perform matching all in "
"memory.");
DEFINE_string(matching_working_directory, "",
DEFINE_string(matching_working_directory,
"",
"Directory used during matching to store features for "
"out-of-core matching.");
DEFINE_int32(matching_max_num_images_in_cache, 128,
DEFINE_int32(matching_max_num_images_in_cache,
128,
"Maximum number of images to store in the LRU cache during "
"feature matching. The higher this number is the more memory is "
"consumed during matching.");
DEFINE_double(lowes_ratio, 0.8, "Lowes ratio used for feature matching.");
DEFINE_double(max_sampson_error_for_verified_match, 4.0,
DEFINE_double(max_sampson_error_for_verified_match,
4.0,
"Maximum sampson error for a match to be considered "
"geometrically valid. This threshold is relative to an image "
"with a width of 1024 pixels and will be appropriately scaled "
"for images with different resolutions.");
DEFINE_int32(min_num_inliers_for_valid_match, 30,
DEFINE_int32(min_num_inliers_for_valid_match,
30,
"Minimum number of geometrically verified inliers that a pair on "
"images must have in order to be considered a valid two-view "
"match.");
DEFINE_bool(bundle_adjust_two_view_geometry, true,
DEFINE_bool(bundle_adjust_two_view_geometry,
true,
"Set to false to turn off 2-view BA.");
DEFINE_bool(keep_only_symmetric_matches, true,
DEFINE_bool(keep_only_symmetric_matches,
true,
"Performs two-way matching and keeps symmetric matches.");
DEFINE_int32(
num_nearest_neighbors_for_global_descriptor_matching,
100,
"Number of nearest neighbor images to use for full descriptor matching.");
DEFINE_int32(num_gmm_clusters_for_fisher_vector,
16,
"Number of clusters to use for the GMM with Fisher Vectors for "
"global image descriptors.");
DEFINE_int32(max_num_features_for_fisher_vector_training,
1000000,
"Number of features to use to train the Fisher Vector kernel for "
"global image descriptor extraction.");

// Reconstruction building options.
DEFINE_string(reconstruction_estimator, "GLOBAL",
DEFINE_string(reconstruction_estimator,
"GLOBAL",
"Type of SfM reconstruction estimation to use.");
DEFINE_bool(reconstruct_largest_connected_component, false,
DEFINE_bool(reconstruct_largest_connected_component,
false,
"If set to true, only the single largest connected component is "
"reconstructed. Otherwise, as many models as possible are "
"estimated.");
DEFINE_bool(shared_calibration, false,
DEFINE_bool(shared_calibration,
false,
"Set to true if all camera intrinsic parameters should be shared "
"as a single set of intrinsics. This is useful, for instance, if "
"all images in the reconstruction were taken with the same "
"camera.");
DEFINE_bool(only_calibrated_views, false,
DEFINE_bool(only_calibrated_views,
false,
"Set to true to only reconstruct the views where calibration is "
"provided or can be extracted from EXIF");
DEFINE_int32(min_track_length, 2, "Minimum length of a track.");
Expand All @@ -120,99 +150,123 @@ DEFINE_string(intrinsics_to_optimize,
"NONE",
"Set to control which intrinsics parameters are optimized during "
"bundle adjustment.");
DEFINE_double(max_reprojection_error_pixels, 4.0,
DEFINE_double(max_reprojection_error_pixels,
4.0,
"Maximum reprojection error for a correspondence to be "
"considered an inlier after bundle adjustment.");

// Global SfM options.
DEFINE_string(global_rotation_estimator, "ROBUST_L1L2",
DEFINE_string(global_rotation_estimator,
"ROBUST_L1L2",
"Type of global rotation estimation to use for global SfM.");
DEFINE_string(global_position_estimator, "NONLINEAR",
DEFINE_string(global_position_estimator,
"NONLINEAR",
"Type of global position estimation to use for global SfM.");
DEFINE_bool(refine_relative_translations_after_rotation_estimation, true,
DEFINE_bool(refine_relative_translations_after_rotation_estimation,
true,
"Refine the relative translation estimation after computing the "
"absolute rotations. This can help improve the accuracy of the "
"position estimation.");
DEFINE_double(post_rotation_filtering_degrees, 5.0,
DEFINE_double(post_rotation_filtering_degrees,
5.0,
"Max degrees difference in relative rotation and rotation "
"estimates for rotation filtering.");
DEFINE_bool(extract_maximal_rigid_subgraph, false,
DEFINE_bool(extract_maximal_rigid_subgraph,
false,
"If true, only cameras that are well-conditioned for position "
"estimation will be used for global position estimation.");
DEFINE_bool(filter_relative_translations_with_1dsfm, true,
DEFINE_bool(filter_relative_translations_with_1dsfm,
true,
"Filter relative translation estimations with the 1DSfM algorithm "
"to potentially remove outlier relativep oses for position "
"estimation.");
DEFINE_bool(refine_camera_positions_and_points_after_position_estimation, true,
DEFINE_bool(refine_camera_positions_and_points_after_position_estimation,
true,
"After estimating positions in Global SfM we can refine only "
"camera positions and 3D point locations, holding camera "
"intrinsics and rotations constant. This often improves the "
"stability of bundle adjustment when the camera intrinsics are "
"inaccurate.");
DEFINE_int32(num_retriangulation_iterations, 1,
DEFINE_int32(num_retriangulation_iterations,
1,
"Number of times to retriangulate any unestimated tracks. Bundle "
"adjustment is performed after retriangulation.");

// Nonlinear position estimation options.
DEFINE_int32(
position_estimation_min_num_tracks_per_view, 0,
position_estimation_min_num_tracks_per_view,
0,
"Minimum number of point to camera constraints for position estimation.");
DEFINE_double(position_estimation_robust_loss_width, 0.1,
DEFINE_double(position_estimation_robust_loss_width,
0.1,
"Robust loss width to use for position estimation.");

// Incremental SfM options.
DEFINE_double(absolute_pose_reprojection_error_threshold, 4.0,
DEFINE_double(absolute_pose_reprojection_error_threshold,
4.0,
"The inlier threshold for absolute pose estimation. This "
"threshold is relative to an image with a width of 1024 pixels "
"and will be appropriately scaled based on the input image "
"resolutions.");
DEFINE_int32(min_num_absolute_pose_inliers, 30,
DEFINE_int32(min_num_absolute_pose_inliers,
30,
"Minimum number of inliers in order for absolute pose estimation "
"to be considered successful.");
DEFINE_double(full_bundle_adjustment_growth_percent, 5.0,
DEFINE_double(full_bundle_adjustment_growth_percent,
5.0,
"Full BA is only triggered for incremental SfM when the "
"reconstruction has growth by this percent since the last time "
"full BA was used.");
DEFINE_int32(partial_bundle_adjustment_num_views, 20,
DEFINE_int32(partial_bundle_adjustment_num_views,
20,
"When full BA is not being run, partial BA is executed on a "
"constant number of views specified by this parameter.");

// Triangulation options.
DEFINE_double(min_triangulation_angle_degrees, 4.0,
DEFINE_double(min_triangulation_angle_degrees,
4.0,
"Minimum angle between views for triangulation.");
DEFINE_double(
triangulation_reprojection_error_pixels, 15.0,
triangulation_reprojection_error_pixels,
15.0,
"Max allowable reprojection error on initial triangulation of points.");
DEFINE_bool(bundle_adjust_tracks, true,
DEFINE_bool(bundle_adjust_tracks,
true,
"Set to true to optimize tracks immediately upon estimation.");

// Bundle adjustment parameters.
DEFINE_string(bundle_adjustment_robust_loss_function, "NONE",
DEFINE_string(bundle_adjustment_robust_loss_function,
"NONE",
"By setting this to an option other than NONE, a robust loss "
"function will be used during bundle adjustment which can "
"improve robustness to outliers. Options are NONE, HUBER, "
"SOFTLONE, CAUCHY, ARCTAN, and TUKEY.");
DEFINE_double(bundle_adjustment_robust_loss_width, 10.0,
DEFINE_double(bundle_adjustment_robust_loss_width,
10.0,
"If the BA loss function is not NONE, then this value controls "
"where the robust loss begins with respect to reprojection error "
"in pixels.");

// Track Subsampling parameters.
DEFINE_bool(subsample_tracks_for_bundle_adjustment, false,
DEFINE_bool(subsample_tracks_for_bundle_adjustment,
false,
"Set to true to subsample tracks used for bundle adjustment. This "
"can help improve efficiency of bundle adjustment dramatically "
"when used properly.");
DEFINE_int32(track_subset_selection_long_track_length_threshold, 10,
DEFINE_int32(track_subset_selection_long_track_length_threshold,
10,
"When track subsampling is enabled, longer tracks are chosen with "
"a higher probability with the track length capped to this value "
"for selection.");
DEFINE_int32(track_selection_image_grid_cell_size_pixels, 100,
DEFINE_int32(track_selection_image_grid_cell_size_pixels,
100,
"When track subsampling is enabled, tracks are chosen such that "
"each view has a good spatial coverage. This is achieved by "
"binning tracks into an image grid in each view and choosing the "
"best tracks in each grid cell to guarantee spatial coverage. The "
"image grid cells are defined to be this width in pixels.");
DEFINE_int32(min_num_optimized_tracks_per_view, 100,
DEFINE_int32(min_num_optimized_tracks_per_view,
100,
"When track subsampling is enabled, tracks are selected such that "
"each view observes a minimum number of optimized tracks.");

Expand Down Expand Up @@ -254,6 +308,13 @@ ReconstructionBuilderOptions SetReconstructionBuilderOptions() {
.min_triangulation_angle_degrees = FLAGS_min_triangulation_angle_degrees;
options.matching_options.geometric_verification_options
.final_max_reprojection_error = FLAGS_max_reprojection_error_pixels;
options.matching_options
.num_nearest_neighbors_for_global_descriptor_matching =
FLAGS_num_nearest_neighbors_for_global_descriptor_matching;
options.matching_options.num_gmm_clusters_for_fisher_vector =
FLAGS_num_gmm_clusters_for_fisher_vector;
options.matching_options.max_num_features_for_fisher_vector_training =
FLAGS_max_num_features_for_fisher_vector_training;

options.min_track_length = FLAGS_min_track_length;
options.max_track_length = FLAGS_max_track_length;
Expand All @@ -265,7 +326,7 @@ ReconstructionBuilderOptions SetReconstructionBuilderOptions() {
FLAGS_min_num_inliers_for_valid_match;
reconstruction_estimator_options.num_threads = FLAGS_num_threads;
reconstruction_estimator_options.intrinsics_to_optimize =
StringToOptimizeIntrinsicsType(FLAGS_intrinsics_to_optimize);
StringToOptimizeIntrinsicsType(FLAGS_intrinsics_to_optimize);
options.reconstruct_largest_connected_component =
FLAGS_reconstruct_largest_connected_component;
options.only_calibrated_views = FLAGS_only_calibrated_views;
Expand All @@ -290,8 +351,7 @@ ReconstructionBuilderOptions SetReconstructionBuilderOptions() {
FLAGS_extract_maximal_rigid_subgraph;
reconstruction_estimator_options.filter_relative_translations_with_1dsfm =
FLAGS_filter_relative_translations_with_1dsfm;
reconstruction_estimator_options
.rotation_filtering_max_difference_degrees =
reconstruction_estimator_options.rotation_filtering_max_difference_degrees =
FLAGS_post_rotation_filtering_degrees;
reconstruction_estimator_options.nonlinear_position_estimator_options
.min_num_points_per_view =
Expand All @@ -301,13 +361,11 @@ ReconstructionBuilderOptions SetReconstructionBuilderOptions() {
FLAGS_refine_camera_positions_and_points_after_position_estimation;

// Incremental SfM Options.
reconstruction_estimator_options
.absolute_pose_reprojection_error_threshold =
reconstruction_estimator_options.absolute_pose_reprojection_error_threshold =
FLAGS_absolute_pose_reprojection_error_threshold;
reconstruction_estimator_options.min_num_absolute_pose_inliers =
FLAGS_min_num_absolute_pose_inliers;
reconstruction_estimator_options
.full_bundle_adjustment_growth_percent =
reconstruction_estimator_options.full_bundle_adjustment_growth_percent =
FLAGS_full_bundle_adjustment_growth_percent;
reconstruction_estimator_options.partial_bundle_adjustment_num_views =
FLAGS_partial_bundle_adjustment_num_views;
Expand Down Expand Up @@ -369,9 +427,8 @@ void AddMatchesToReconstructionBuilder(

// Add the matches.
for (const auto& match : image_matches) {
CHECK(reconstruction_builder->AddTwoViewMatch(match.image1,
match.image2,
match));
CHECK(reconstruction_builder->AddTwoViewMatch(
match.image1, match.image2, match));
}
}

Expand Down Expand Up @@ -407,7 +464,7 @@ void AddImagesToReconstructionBuilder(
CHECK(theia::GetFilenameFromFilepath(image_file, true, &image_filename));

const theia::CameraIntrinsicsPrior* image_camera_intrinsics_prior =
FindOrNull(camera_intrinsics_prior, image_filename);
FindOrNull(camera_intrinsics_prior, image_filename);
if (image_camera_intrinsics_prior != nullptr) {
CHECK(reconstruction_builder->AddImageWithCameraIntrinsicsPrior(
image_file, *image_camera_intrinsics_prior, intrinsics_group_id));
Expand All @@ -424,21 +481,18 @@ void AddImagesToReconstructionBuilder(
std::vector<std::string> mask_files;
if (FLAGS_image_masks.size() != 0) {
CHECK(theia::GetFilepathsFromWildcard(FLAGS_image_masks, &mask_files))
<< "Could not find image masks that matched the filepath: "
<< FLAGS_image_masks
<< ". NOTE that the ~ filepath is not supported.";
<< "Could not find image masks that matched the filepath: "
<< FLAGS_image_masks << ". NOTE that the ~ filepath is not supported.";
if (mask_files.size() > 0) {
for (const std::string& image_file : image_files) {
std::string image_filename;
CHECK(theia::GetFilenameFromFilepath(image_file,
false,
&image_filename));
CHECK(
theia::GetFilenameFromFilepath(image_file, false, &image_filename));
// Find and add the associated mask
for (const std::string& mask_file : mask_files) {
if (mask_file.find(image_filename) != std::string::npos) {
CHECK(reconstruction_builder->AddMaskForFeaturesExtraction(
image_file,
mask_file));
image_file, mask_file));
break;
}
}
Expand All @@ -452,7 +506,7 @@ void AddImagesToReconstructionBuilder(
CHECK(reconstruction_builder->ExtractAndMatchFeatures());
}

int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
THEIA_GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);

Expand Down
Loading

0 comments on commit 8d5bb9b

Please sign in to comment.