17 IncrementalMapper* mapper) {
18 std::cout <<
" => Continued observations: " <<
image.NumPoints3D()
20 const size_t num_tris =
21 mapper->TriangulateImage(options.Triangulation(),
image.ImageId());
22 std::cout <<
" => Added observations: " << num_tris <<
std::endl;
27 IncrementalMapper* mapper) {
28 BundleAdjustmentOptions custom_ba_options =
29 options.GlobalBundleAdjustment();
31 const size_t num_reg_images = mapper->GetReconstruction().NumRegImages();
34 const size_t kMinNumRegImagesForFastBA = 10;
35 if (num_reg_images < kMinNumRegImagesForFastBA) {
36 custom_ba_options.solver_options.function_tolerance /= 10;
37 custom_ba_options.solver_options.gradient_tolerance /= 10;
38 custom_ba_options.solver_options.parameter_tolerance /= 10;
39 custom_ba_options.solver_options.max_num_iterations *= 2;
40 custom_ba_options.solver_options.max_linear_solver_iterations = 200;
45 if (options.ba_global_use_pba && !options.fix_existing_images &&
46 num_reg_images >= kMinNumRegImagesForFastBA &&
47 ParallelBundleAdjuster::IsSupported(custom_ba_options,
48 mapper->GetReconstruction())) {
49 mapper->AdjustParallelGlobalBundle(
50 custom_ba_options, options.ParallelGlobalBundleAdjustment());
52 mapper->AdjustGlobalBundle(options.Mapper(), custom_ba_options);
55 mapper->AdjustGlobalBundle(options.Mapper(), custom_ba_options);
61 IncrementalMapper* mapper) {
62 auto ba_options = options.LocalBundleAdjustment();
63 for (
int i = 0; i < options.ba_local_max_refinements; ++i) {
64 const auto report = mapper->AdjustLocalBundle(
65 options.Mapper(), ba_options, options.Triangulation(), image_id,
66 mapper->GetModifiedPoints3D());
67 std::cout <<
" => Merged observations: "
68 << report.num_merged_observations <<
std::endl;
69 std::cout <<
" => Completed observations: "
70 << report.num_completed_observations <<
std::endl;
71 std::cout <<
" => Filtered observations: "
72 << report.num_filtered_observations <<
std::endl;
73 const double changed =
74 (report.num_merged_observations +
75 report.num_completed_observations +
76 report.num_filtered_observations) /
77 static_cast<double>(report.num_adjusted_observations);
78 std::cout <<
StringPrintf(
" => Changed observations: %.6f", changed)
80 if (changed < options.ba_local_max_refinement_change) {
84 ba_options.loss_function_type =
87 mapper->ClearModifiedPoints3D();
91 IncrementalMapper* mapper) {
94 std::cout <<
" => Retriangulated observations: "
95 << mapper->Retriangulate(options.Triangulation()) <<
std::endl;
97 for (
int i = 0; i < options.ba_global_max_refinements; ++i) {
98 const size_t num_observations =
99 mapper->GetReconstruction().ComputeNumObservations();
100 size_t num_changed_observations = 0;
101 AdjustGlobalBundle(options, mapper);
103 num_changed_observations +=
FilterPoints(options, mapper);
104 const double changed =
static_cast<double>(num_changed_observations) /
106 std::cout <<
StringPrintf(
" => Changed observations: %.6f", changed)
108 if (changed < options.ba_global_max_refinement_change) {
116 void ExtractColors(
const std::string& image_path,
118 Reconstruction* reconstruction) {
119 if (!reconstruction->ExtractColorsForImage(image_id, image_path)) {
121 "WARNING: Could not read image %s at path %s.",
122 reconstruction->Image(image_id).Name().c_str(),
128 void WriteSnapshot(
const Reconstruction& reconstruction,
129 const std::string& snapshot_path) {
132 const size_t timestamp =
133 std::chrono::duration_cast<std::chrono::milliseconds>(
134 std::chrono::high_resolution_clock::now()
138 const std::string
path =
142 reconstruction.Write(
path);
149 const size_t num_filtered_observations =
151 std::cout <<
" => Filtered observations: " << num_filtered_observations
153 return num_filtered_observations;
159 std::cout <<
" => Filtered images: " << num_filtered_images <<
std::endl;
160 return num_filtered_images;
165 const size_t num_completed_observations =
167 std::cout <<
" => Completed observations: " << num_completed_observations
169 const size_t num_merged_observations =
171 std::cout <<
" => Merged observations: " << num_merged_observations
173 return num_completed_observations + num_merged_observations;
208 #if CERES_VERSION_MAJOR < 2
235 #if CERES_VERSION_MAJOR < 2
252 ParallelBundleAdjuster::Options
253 IncrementalMapperOptions::ParallelGlobalBundleAdjustment()
const {
254 ParallelBundleAdjuster::Options options;
256 options.print_summary =
true;
257 options.gpu_index = ba_global_pba_gpu_index;
259 options.min_num_residuals_for_cpu_multi_threading =
293 const std::string& image_path,
294 const std::string& database_path,
297 image_path_(image_path),
298 database_path_(database_path),
299 reconstruction_manager_(reconstruction_manager) {
300 CHECK(options_->
Check());
306 void IncrementalMapperController::Run() {
307 if (!LoadDatabase()) {
311 IncrementalMapper::Options init_mapper_options = options_->
Mapper();
312 Reconstruct(init_mapper_options);
314 const size_t kNumInitRelaxations = 2;
315 for (
size_t i = 0; i < kNumInitRelaxations; ++i) {
320 std::cout <<
" => Relaxing the initialization constraints."
322 init_mapper_options.init_min_num_inliers /= 2;
323 Reconstruct(init_mapper_options);
329 std::cout <<
" => Relaxing the initialization constraints."
331 init_mapper_options.init_min_tri_angle /= 2;
332 Reconstruct(init_mapper_options);
339 bool IncrementalMapperController::LoadDatabase() {
344 std::unordered_set<std::string> image_names = options_->
image_names;
345 if (reconstruction_manager_->
Size() == 1 &&
347 const Reconstruction& reconstruction = reconstruction_manager_->
Get(0);
348 for (
const image_t image_id : reconstruction.RegImageIds()) {
349 const auto&
image = reconstruction.Image(image_id);
350 image_names.insert(
image.Name());
354 Database database(database_path_);
357 const size_t min_num_matches =
362 timer.PrintMinutes();
367 std::cout <<
"WARNING: No images with matches found in the database."
376 void IncrementalMapperController::Reconstruct(
377 const IncrementalMapper::Options& init_mapper_options) {
378 const bool kDiscardReconstruction =
true;
384 IncrementalMapper mapper(&database_cache_);
388 const bool initial_reconstruction_given =
389 reconstruction_manager_->
Size() > 0;
390 CHECK_LE(reconstruction_manager_->
Size(), 1)
391 <<
"Can only resume from a "
392 "single reconstruction, but "
393 "multiple are given.";
402 size_t reconstruction_idx;
403 if (!initial_reconstruction_given || num_trials > 0) {
404 reconstruction_idx = reconstruction_manager_->
Add();
406 reconstruction_idx = 0;
409 Reconstruction& reconstruction =
410 reconstruction_manager_->
Get(reconstruction_idx);
412 mapper.BeginReconstruction(&reconstruction);
418 if (reconstruction.NumRegImages() == 0) {
426 const bool find_init_success = mapper.FindInitialImagePair(
427 init_mapper_options, &image_id1, &image_id2);
428 if (!find_init_success) {
429 std::cout <<
" => No good initial image pair found."
431 mapper.EndReconstruction(kDiscardReconstruction);
432 reconstruction_manager_->
Delete(reconstruction_idx);
436 if (!reconstruction.ExistsImage(image_id1) ||
437 !reconstruction.ExistsImage(image_id2)) {
439 " => Initial image pair #%d and #%d "
441 image_id1, image_id2)
443 mapper.EndReconstruction(kDiscardReconstruction);
444 reconstruction_manager_->
Delete(reconstruction_idx);
450 StringPrintf(
"Initializing with image pair #%d and #%d",
451 image_id1, image_id2));
452 const bool reg_init_success = mapper.RegisterInitialImagePair(
453 init_mapper_options, image_id1, image_id2);
454 if (!reg_init_success) {
456 <<
" => Initialization failed - possible solutions:"
458 <<
" - try to relax the initialization constraints"
460 <<
" - manually select an initial image pair"
462 mapper.EndReconstruction(kDiscardReconstruction);
463 reconstruction_manager_->
Delete(reconstruction_idx);
467 AdjustGlobalBundle(*options_, &mapper);
472 if (reconstruction.NumRegImages() == 0 ||
473 reconstruction.NumPoints3D() == 0) {
474 mapper.EndReconstruction(kDiscardReconstruction);
475 reconstruction_manager_->
Delete(reconstruction_idx);
487 ExtractColors(image_path_, image_id1, &reconstruction);
497 size_t snapshot_prev_num_reg_images = reconstruction.NumRegImages();
498 size_t ba_prev_num_reg_images = reconstruction.NumRegImages();
499 size_t ba_prev_num_points = reconstruction.NumPoints3D();
501 bool reg_next_success =
true;
502 bool prev_reg_next_success =
true;
503 while (reg_next_success) {
509 reg_next_success =
false;
511 const std::vector<image_t> next_images =
512 mapper.FindNextImages(options_->
Mapper());
514 if (next_images.empty()) {
518 for (
size_t reg_trial = 0; reg_trial < next_images.size();
520 const image_t next_image_id = next_images[reg_trial];
521 const Image& next_image = reconstruction.Image(next_image_id);
525 reconstruction.NumRegImages() + 1));
527 std::cout <<
StringPrintf(
" => Image sees %d / %d points",
528 next_image.NumVisiblePoints3D(),
529 next_image.NumObservations())
532 reg_next_success = mapper.RegisterNextImage(options_->
Mapper(),
535 if (reg_next_success) {
536 TriangulateImage(*options_, next_image, &mapper);
537 IterativeLocalRefinement(*options_, next_image_id, &mapper);
539 if (reconstruction.NumRegImages() >=
541 ba_prev_num_reg_images ||
542 reconstruction.NumRegImages() >=
544 ba_prev_num_reg_images ||
545 reconstruction.NumPoints3D() >=
547 ba_prev_num_points ||
548 reconstruction.NumPoints3D() >=
550 ba_prev_num_points) {
551 IterativeGlobalRefinement(*options_, &mapper);
552 ba_prev_num_points = reconstruction.NumPoints3D();
553 ba_prev_num_reg_images = reconstruction.NumRegImages();
557 ExtractColors(image_path_, next_image_id,
562 reconstruction.NumRegImages() >=
564 snapshot_prev_num_reg_images) {
565 snapshot_prev_num_reg_images =
566 reconstruction.NumRegImages();
575 <<
" => Could not register, trying another image."
580 const size_t kMinNumInitialRegTrials = 30;
581 if (reg_trial >= kMinNumInitialRegTrials &&
582 reconstruction.NumRegImages() <
589 const size_t max_model_overlap =
591 if (mapper.NumSharedRegImages() >= max_model_overlap) {
598 if (!reg_next_success && prev_reg_next_success) {
599 reg_next_success =
true;
600 prev_reg_next_success =
false;
601 IterativeGlobalRefinement(*options_, &mapper);
603 prev_reg_next_success = reg_next_success;
608 const bool kDiscardReconstruction =
false;
609 mapper.EndReconstruction(kDiscardReconstruction);
614 if (reconstruction.NumRegImages() >= 2 &&
615 reconstruction.NumRegImages() != ba_prev_num_reg_images &&
616 reconstruction.NumPoints3D() != ba_prev_num_points) {
617 IterativeGlobalRefinement(*options_, &mapper);
623 const size_t min_model_size =
627 reconstruction.NumRegImages() < min_model_size) ||
628 reconstruction.NumRegImages() == 0) {
629 mapper.EndReconstruction(kDiscardReconstruction);
630 reconstruction_manager_->
Delete(reconstruction_idx);
632 const bool kDiscardReconstruction =
false;
633 mapper.EndReconstruction(kDiscardReconstruction);
638 const size_t max_num_models =
641 reconstruction_manager_->
Size() >= max_num_models ||
642 mapper.NumTotalRegImages() >= database_cache_.
NumImages() - 1) {
std::shared_ptr< core::Tensor > image
void Load(const Database &database, const size_t min_num_matches, const bool ignore_watermarks, const std::unordered_set< std::string > &image_names)
IncrementalMapperController(const IncrementalMapperOptions *options, const std::string &image_path, const std::string &database_path, ReconstructionManager *reconstruction_manager)
@ LAST_IMAGE_REG_CALLBACK
@ INITIAL_IMAGE_PAIR_REG_CALLBACK
@ NEXT_IMAGE_REG_CALLBACK
size_t MergeTracks(const IncrementalTriangulator::Options &tri_options)
size_t FilterImages(const Options &options)
size_t CompleteTracks(const IncrementalTriangulator::Options &tri_options)
size_t FilterPoints(const Options &options)
const Reconstruction & Get(const size_t idx) const
void Delete(const size_t idx)
void Callback(const int id) const
void RegisterCallback(const int id)
const Timer & GetTimer() const
void PrintMinutes() const
#define CHECK_OPTION(expr)
#define CHECK_OPTION_GT(val1, val2)
#define CHECK_OPTION_GE(val1, val2)
QTextStream & endl(QTextStream &stream)
static const std::string path
colmap::IncrementalMapperOptions IncrementalMapperOptions
size_t FilterImages(const IncrementalMapperOptions &options, IncrementalMapper *mapper)
size_t CompleteAndMergeTracks(const IncrementalMapperOptions &options, IncrementalMapper *mapper)
void CreateDirIfNotExists(const std::string &path)
std::string JoinPaths(T const &... paths)
void PrintHeading1(const std::string &heading)
std::string StringPrintf(const char *format,...)
size_t FilterPoints(const IncrementalMapperOptions &options, IncrementalMapper *mapper)
LossFunctionType loss_function_type
bool refine_principal_point
double loss_function_scale
int min_num_residuals_for_cpu_multi_threading
ceres::Solver::Options solver_options
bool ba_refine_focal_length
IncrementalTriangulator::Options triangulation
double ba_global_function_tolerance
IncrementalTriangulator::Options Triangulation() const
int ba_global_max_num_iterations
int ba_local_max_refinements
IncrementalMapper::Options mapper
BundleAdjustmentOptions LocalBundleAdjustment() const
double ba_global_max_refinement_change
std::string snapshot_path
int ba_global_points_freq
bool ba_refine_principal_point
double max_focal_length_ratio
double ba_local_max_refinement_change
int ba_local_max_num_iterations
int ba_global_images_freq
double ba_global_points_ratio
IncrementalMapper::Options Mapper() const
double ba_local_function_tolerance
int ba_min_num_residuals_for_cpu_multi_threading
double min_focal_length_ratio
BundleAdjustmentOptions GlobalBundleAdjustment() const
int ba_global_max_refinements
std::unordered_set< std::string > image_names
double ba_global_images_ratio
bool ba_refine_extra_params
double max_focal_length_ratio
double min_focal_length_ratio
bool abs_pose_refine_focal_length
bool abs_pose_refine_extra_params
double max_focal_length_ratio
double min_focal_length_ratio