ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
hierarchical_mapper.cc
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 "base/scene_clustering.h"
11 #include "util/misc.h"
12 
13 namespace colmap {
14 namespace {
15 
16 void MergeClusters(
17  const SceneClustering::Cluster& cluster,
18  std::unordered_map<const SceneClustering::Cluster*, ReconstructionManager>*
19  reconstruction_managers) {
20  // Extract all reconstructions from all child clusters.
21  std::vector<Reconstruction*> reconstructions;
22  for (const auto& child_cluster : cluster.child_clusters) {
23  if (!child_cluster.child_clusters.empty()) {
24  MergeClusters(child_cluster, reconstruction_managers);
25  }
26 
27  auto& reconstruction_manager = reconstruction_managers->at(&child_cluster);
28  for (size_t i = 0; i < reconstruction_manager.Size(); ++i) {
29  reconstructions.push_back(&reconstruction_manager.Get(i));
30  }
31  }
32 
33  // Try to merge all child cluster reconstruction.
34  while (reconstructions.size() > 1) {
35  bool merge_success = false;
36  for (size_t i = 0; i < reconstructions.size(); ++i) {
37  for (size_t j = 0; j < i; ++j) {
38  const double kMaxReprojError = 8.0;
39  if (reconstructions[i]->Merge(*reconstructions[j], kMaxReprojError)) {
40  reconstructions.erase(reconstructions.begin() + j);
41  merge_success = true;
42  break;
43  }
44  }
45 
46  if (merge_success) {
47  break;
48  }
49  }
50 
51  if (!merge_success) {
52  break;
53  }
54  }
55 
56  // Insert a new reconstruction manager for merged cluster.
57  auto& reconstruction_manager = (*reconstruction_managers)[&cluster];
58  for (const auto& reconstruction : reconstructions) {
59  reconstruction_manager.Add();
60  reconstruction_manager.Get(reconstruction_manager.Size() - 1) =
61  *reconstruction;
62  }
63 
64  // Delete all merged child cluster reconstruction managers.
65  for (const auto& child_cluster : cluster.child_clusters) {
66  reconstruction_managers->erase(&child_cluster);
67  }
68 }
69 
70 } // namespace
71 
75  return true;
76 }
77 
79  const Options& options, const SceneClustering::Options& clustering_options,
80  const IncrementalMapperOptions& mapper_options,
81  ReconstructionManager* reconstruction_manager)
82  : options_(options),
83  clustering_options_(clustering_options),
84  mapper_options_(mapper_options),
85  reconstruction_manager_(reconstruction_manager) {
86  CHECK(options_.Check());
87  CHECK(clustering_options_.Check());
88  CHECK(mapper_options_.Check());
89  CHECK_EQ(clustering_options_.branching, 2);
90 }
91 
92 void HierarchicalMapperController::Run() {
93  PrintHeading1("Partitioning the scene");
94 
96  // Cluster scene
98 
99  std::unordered_map<image_t, std::string> image_id_to_name;
100 
101  Database database(options_.database_path);
102 
103  std::cout << "Reading images..." << std::endl;
104  const auto images = database.ReadAllImages();
105  for (const auto& image : images) {
106  image_id_to_name.emplace(image.ImageId(), image.Name());
107  }
108 
109  SceneClustering scene_clustering =
110  SceneClustering::Create(clustering_options_, database);
111 
112  auto leaf_clusters = scene_clustering.GetLeafClusters();
113 
114  size_t total_num_images = 0;
115  for (size_t i = 0; i < leaf_clusters.size(); ++i) {
116  total_num_images += leaf_clusters[i]->image_ids.size();
117  std::cout << StringPrintf(" Cluster %d with %d images", i + 1,
118  leaf_clusters[i]->image_ids.size())
119  << std::endl;
120  }
121 
122  std::cout << StringPrintf("Clusters have %d images", total_num_images)
123  << std::endl;
124 
126  // Reconstruct clusters
128 
129  PrintHeading1("Reconstructing clusters");
130 
131  // Determine the number of workers and threads per worker.
132  const int kMaxNumThreads = -1;
133  const int num_eff_threads = GetEffectiveNumThreads(kMaxNumThreads);
134  const int kDefaultNumWorkers = 8;
135  const int num_eff_workers =
136  options_.num_workers < 1
137  ? std::min(static_cast<int>(leaf_clusters.size()),
138  std::min(kDefaultNumWorkers, num_eff_threads))
139  : options_.num_workers;
140  const int num_threads_per_worker =
141  std::max(1, num_eff_threads / num_eff_workers);
142 
143  // Function to reconstruct one cluster using incremental mapping.
144  auto ReconstructCluster = [&, this](
145  const SceneClustering::Cluster& cluster,
146  ReconstructionManager* reconstruction_manager) {
147  if (cluster.image_ids.empty()) {
148  return;
149  }
150 
151  IncrementalMapperOptions custom_options = mapper_options_;
152  custom_options.max_model_overlap = 3;
153  custom_options.init_num_trials = options_.init_num_trials;
154  if (custom_options.num_threads < 0) {
155  custom_options.num_threads = num_threads_per_worker;
156  }
157 
158  for (const auto image_id : cluster.image_ids) {
159  custom_options.image_names.insert(image_id_to_name.at(image_id));
160  }
161 
162  IncrementalMapperController mapper(&custom_options, options_.image_path,
163  options_.database_path,
164  reconstruction_manager);
165  mapper.Start();
166  mapper.Wait();
167  };
168 
169  // Start reconstructing the bigger clusters first for resource usage.
170  std::sort(leaf_clusters.begin(), leaf_clusters.end(),
171  [](const SceneClustering::Cluster* cluster1,
172  const SceneClustering::Cluster* cluster2) {
173  return cluster1->image_ids.size() > cluster2->image_ids.size();
174  });
175 
176  // Start the reconstruction workers.
177 
178  std::unordered_map<const SceneClustering::Cluster*, ReconstructionManager>
179  reconstruction_managers;
180  reconstruction_managers.reserve(leaf_clusters.size());
181 
182  ThreadPool thread_pool(num_eff_workers);
183  for (const auto& cluster : leaf_clusters) {
184  thread_pool.AddTask(ReconstructCluster, *cluster,
185  &reconstruction_managers[cluster]);
186  }
187  thread_pool.Wait();
188 
190  // Merge clusters
192 
193  PrintHeading1("Merging clusters");
194 
195  MergeClusters(*scene_clustering.GetRootCluster(), &reconstruction_managers);
196 
197  CHECK_EQ(reconstruction_managers.size(), 1);
198  *reconstruction_manager_ = std::move(reconstruction_managers.begin()->second);
199 
200  std::cout << std::endl;
202 }
203 
204 } // namespace colmap
std::shared_ptr< core::Tensor > image
HierarchicalMapperController(const Options &options, const SceneClustering::Options &clustering_options, const IncrementalMapperOptions &mapper_options, ReconstructionManager *reconstruction_manager)
static SceneClustering Create(const Options &options, const Database &database)
const Timer & GetTimer() const
Definition: threading.cc:154
void PrintMinutes() const
Definition: timer.cc:93
#define CHECK_OPTION_GT(val1, val2)
Definition: logging.h:34
#define CHECK_OPTION_GE(val1, val2)
Definition: logging.h:33
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
colmap::IncrementalMapperOptions IncrementalMapperOptions
colmap::IncrementalMapperController IncrementalMapperController
void PrintHeading1(const std::string &heading)
Definition: misc.cc:225
std::string StringPrintf(const char *format,...)
Definition: string.cc:131
int GetEffectiveNumThreads(const int num_threads)
Definition: threading.cc:269