ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
database_cache.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 
32 #include "base/database_cache.h"
33 
34 #include <unordered_set>
35 
36 #include "feature/utils.h"
37 #include "util/string.h"
38 #include "util/timer.h"
39 
40 namespace colmap {
41 
43 
44 void DatabaseCache::AddCamera(const class Camera& camera) {
45  CHECK(!ExistsCamera(camera.CameraId()));
46  cameras_.emplace(camera.CameraId(), camera);
47 }
48 
49 void DatabaseCache::AddImage(const class Image& image) {
50  CHECK(!ExistsImage(image.ImageId()));
51  images_.emplace(image.ImageId(), image);
52  correspondence_graph_.AddImage(image.ImageId(), image.NumPoints2D());
53 }
54 
55 void DatabaseCache::Load(const Database& database, const size_t min_num_matches,
56  const bool ignore_watermarks,
57  const std::unordered_set<std::string>& image_names) {
59  // Load cameras
61 
62  Timer timer;
63 
64  timer.Start();
65  std::cout << "Loading cameras..." << std::flush;
66 
67  {
68  const std::vector<class Camera> cameras = database.ReadAllCameras();
69  cameras_.reserve(cameras.size());
70  for (const auto& camera : cameras) {
71  cameras_.emplace(camera.CameraId(), camera);
72  }
73  }
74 
75  std::cout << StringPrintf(" %d in %.3fs", cameras_.size(),
76  timer.ElapsedSeconds())
77  << std::endl;
78 
80  // Load matches
82 
83  timer.Restart();
84  std::cout << "Loading matches..." << std::flush;
85 
86  std::vector<image_pair_t> image_pair_ids;
87  std::vector<TwoViewGeometry> two_view_geometries;
88  database.ReadTwoViewGeometries(&image_pair_ids, &two_view_geometries);
89 
90  std::cout << StringPrintf(" %d in %.3fs", image_pair_ids.size(),
91  timer.ElapsedSeconds())
92  << std::endl;
93 
94  auto UseInlierMatchesCheck = [min_num_matches, ignore_watermarks](
95  const TwoViewGeometry& two_view_geometry) {
96  return static_cast<size_t>(two_view_geometry.inlier_matches.size()) >=
97  min_num_matches &&
98  (!ignore_watermarks ||
99  two_view_geometry.config != TwoViewGeometry::WATERMARK);
100  };
101 
103  // Load images
105 
106  timer.Restart();
107  std::cout << "Loading images..." << std::flush;
108 
109  std::unordered_set<image_t> image_ids;
110 
111  {
112  const std::vector<class Image> images = database.ReadAllImages();
113 
114  // Determines for which images data should be loaded.
115  if (image_names.empty()) {
116  for (const auto& image : images) {
117  image_ids.insert(image.ImageId());
118  }
119  } else {
120  for (const auto& image : images) {
121  if (image_names.count(image.Name()) > 0) {
122  image_ids.insert(image.ImageId());
123  }
124  }
125  }
126 
127  // Collect all images that are connected in the correspondence graph.
128  std::unordered_set<image_t> connected_image_ids;
129  connected_image_ids.reserve(image_ids.size());
130  for (size_t i = 0; i < image_pair_ids.size(); ++i) {
131  if (UseInlierMatchesCheck(two_view_geometries[i])) {
132  image_t image_id1;
133  image_t image_id2;
134  Database::PairIdToImagePair(image_pair_ids[i], &image_id1, &image_id2);
135  if (image_ids.count(image_id1) > 0 && image_ids.count(image_id2) > 0) {
136  connected_image_ids.insert(image_id1);
137  connected_image_ids.insert(image_id2);
138  }
139  }
140  }
141 
142  // Load images with correspondences and discard images without
143  // correspondences, as those images are useless for SfM.
144  images_.reserve(connected_image_ids.size());
145  for (const auto& image : images) {
146  if (image_ids.count(image.ImageId()) > 0 &&
147  connected_image_ids.count(image.ImageId()) > 0) {
148  images_.emplace(image.ImageId(), image);
149  const FeatureKeypoints keypoints =
150  database.ReadKeypoints(image.ImageId());
151  const std::vector<Eigen::Vector2d> points =
153  images_[image.ImageId()].SetPoints2D(points);
154  }
155  }
156 
157  std::cout << StringPrintf(" %d in %.3fs (connected %d)", images.size(),
158  timer.ElapsedSeconds(),
159  connected_image_ids.size())
160  << std::endl;
161  }
162 
164  // Build correspondence graph
166 
167  timer.Restart();
168  std::cout << "Building correspondence graph..." << std::flush;
169 
170  for (const auto& image : images_) {
171  correspondence_graph_.AddImage(image.first, image.second.NumPoints2D());
172  }
173 
174  size_t num_ignored_image_pairs = 0;
175  for (size_t i = 0; i < image_pair_ids.size(); ++i) {
176  if (UseInlierMatchesCheck(two_view_geometries[i])) {
177  image_t image_id1;
178  image_t image_id2;
179  Database::PairIdToImagePair(image_pair_ids[i], &image_id1, &image_id2);
180  if (image_ids.count(image_id1) > 0 && image_ids.count(image_id2) > 0) {
181  correspondence_graph_.AddCorrespondences(
182  image_id1, image_id2, two_view_geometries[i].inlier_matches);
183  } else {
184  num_ignored_image_pairs += 1;
185  }
186  } else {
187  num_ignored_image_pairs += 1;
188  }
189  }
190 
191  correspondence_graph_.Finalize();
192 
193  // Set number of observations and correspondences per image.
194  for (auto& image : images_) {
195  image.second.SetNumObservations(
196  correspondence_graph_.NumObservationsForImage(image.first));
197  image.second.SetNumCorrespondences(
198  correspondence_graph_.NumCorrespondencesForImage(image.first));
199  }
200 
201  std::cout << StringPrintf(" in %.3fs (ignored %d)", timer.ElapsedSeconds(),
202  num_ignored_image_pairs)
203  << std::endl;
204 }
205 
207  const std::string& name) const {
208  for (const auto& image : images_) {
209  if (image.second.Name() == name) {
210  return &image.second;
211  }
212  }
213  return nullptr;
214 }
215 
216 } // namespace colmap
std::shared_ptr< core::Tensor > image
std::string name
int points
camera_t CameraId() const
Definition: camera.h:154
void AddImage(const image_t image_id, const size_t num_points2D)
point2D_t NumCorrespondencesForImage(const image_t image_id) const
void AddCorrespondences(const image_t image_id1, const image_t image_id2, const FeatureMatches &matches)
point2D_t NumObservationsForImage(const image_t image_id) const
bool ExistsCamera(const camera_t camera_id) const
void AddImage(const class Image &image)
void Load(const Database &database, const size_t min_num_matches, const bool ignore_watermarks, const std::unordered_set< std::string > &image_names)
const class Image * FindImageWithName(const std::string &name) const
void AddCamera(const class Camera &camera)
bool ExistsImage(const image_t image_id) const
FeatureKeypoints ReadKeypoints(const image_t image_id) const
Definition: database.cc:436
std::vector< Camera > ReadAllCameras() const
Definition: database.cc:380
void ReadTwoViewGeometries(std::vector< image_pair_t > *image_pair_ids, std::vector< TwoViewGeometry > *two_view_geometries) const
Definition: database.cc:539
static void PairIdToImagePair(const image_pair_t pair_id, image_t *image_id1, image_t *image_id2)
Definition: database.h:352
std::vector< Image > ReadAllImages() const
Definition: database.cc:423
void Start()
Definition: timer.cc:43
void Restart()
Definition: timer.cc:49
double ElapsedSeconds() const
Definition: timer.cc:82
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
uint32_t image_t
Definition: types.h:61
std::vector< Eigen::Vector2d > FeatureKeypointsToPointsVector(const FeatureKeypoints &keypoints)
Definition: utils.cc:38
std::vector< FeatureKeypoint > FeatureKeypoints
Definition: types.h:77
std::string StringPrintf(const char *format,...)
Definition: string.cc:131