ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
correspondence_graph.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 
33 
34 #include <unordered_set>
35 
36 #include "base/pose.h"
37 #include "util/string.h"
38 
39 namespace colmap {
40 
42 
43 std::unordered_map<image_pair_t, point2D_t>
45  std::unordered_map<image_pair_t, point2D_t> num_corrs_between_images;
46  num_corrs_between_images.reserve(image_pairs_.size());
47  for (const auto& image_pair : image_pairs_) {
48  num_corrs_between_images.emplace(image_pair.first,
49  image_pair.second.num_correspondences);
50  }
51  return num_corrs_between_images;
52 }
53 
55  for (auto it = images_.begin(); it != images_.end();) {
56  it->second.num_observations = 0;
57  for (auto& corr : it->second.corrs) {
58  corr.shrink_to_fit();
59  if (corr.size() > 0) {
60  it->second.num_observations += 1;
61  }
62  }
63  if (it->second.num_observations == 0) {
64  images_.erase(it++);
65  } else {
66  ++it;
67  }
68  }
69 }
70 
72  const size_t num_points) {
73  CHECK(!ExistsImage(image_id));
74  images_[image_id].corrs.resize(num_points);
75 }
76 
78  const image_t image_id2,
79  const FeatureMatches& matches) {
80  // Avoid self-matches - should only happen, if user provides custom matches.
81  if (image_id1 == image_id2) {
82  std::cout << "WARNING: Cannot use self-matches for image_id=" << image_id1
83  << std::endl;
84  return;
85  }
86 
87  // Corresponding images.
88  struct Image& image1 = images_.at(image_id1);
89  struct Image& image2 = images_.at(image_id2);
90 
91  // Store number of correspondences for each image to find good initial pair.
92  image1.num_correspondences += matches.size();
93  image2.num_correspondences += matches.size();
94 
95  // Set the number of all correspondences for this image pair. Further below,
96  // we will make sure that only unique correspondences are counted.
97  const image_pair_t pair_id =
98  Database::ImagePairToPairId(image_id1, image_id2);
99  auto& image_pair = image_pairs_[pair_id];
100  image_pair.num_correspondences += static_cast<point2D_t>(matches.size());
101 
102  // Store all matches in correspondence graph data structure. This data-
103  // structure uses more memory than storing the raw match matrices, but is
104  // significantly more efficient when updating the correspondences in case an
105  // observation is triangulated.
106 
107  for (const auto& match : matches) {
108  const bool valid_idx1 = match.point2D_idx1 < image1.corrs.size();
109  const bool valid_idx2 = match.point2D_idx2 < image2.corrs.size();
110 
111  if (valid_idx1 && valid_idx2) {
112  auto& corrs1 = image1.corrs[match.point2D_idx1];
113  auto& corrs2 = image2.corrs[match.point2D_idx2];
114 
115  const bool duplicate1 =
116  std::find_if(corrs1.begin(), corrs1.end(),
117  [image_id2](const Correspondence& corr) {
118  return corr.image_id == image_id2;
119  }) != corrs1.end();
120  const bool duplicate2 =
121  std::find_if(corrs2.begin(), corrs2.end(),
122  [image_id1](const Correspondence& corr) {
123  return corr.image_id == image_id1;
124  }) != corrs2.end();
125 
126  if (duplicate1 || duplicate2) {
127  image1.num_correspondences -= 1;
128  image2.num_correspondences -= 1;
129  image_pair.num_correspondences -= 1;
130  std::cout << StringPrintf(
131  "WARNING: Duplicate correspondence between "
132  "point2D_idx=%d in image_id=%d and point2D_idx=%d in "
133  "image_id=%d",
134  match.point2D_idx1, image_id1, match.point2D_idx2,
135  image_id2)
136  << std::endl;
137  } else {
138  corrs1.emplace_back(image_id2, match.point2D_idx2);
139  corrs2.emplace_back(image_id1, match.point2D_idx1);
140  }
141  } else {
142  image1.num_correspondences -= 1;
143  image2.num_correspondences -= 1;
144  image_pair.num_correspondences -= 1;
145  if (!valid_idx1) {
146  std::cout
147  << StringPrintf(
148  "WARNING: point2D_idx=%d in image_id=%d does not exist",
149  match.point2D_idx1, image_id1)
150  << std::endl;
151  }
152  if (!valid_idx2) {
153  std::cout
154  << StringPrintf(
155  "WARNING: point2D_idx=%d in image_id=%d does not exist",
156  match.point2D_idx2, image_id2)
157  << std::endl;
158  }
159  }
160  }
161 }
162 
163 std::vector<CorrespondenceGraph::Correspondence>
165  const image_t image_id, const point2D_t point2D_idx,
166  const size_t transitivity) const {
167  if (transitivity == 1) {
168  return FindCorrespondences(image_id, point2D_idx);
169  }
170 
171  std::vector<Correspondence> found_corrs;
172  if (!HasCorrespondences(image_id, point2D_idx)) {
173  return found_corrs;
174  }
175 
176  found_corrs.emplace_back(image_id, point2D_idx);
177 
178  std::unordered_map<image_t, std::unordered_set<point2D_t>> image_corrs;
179  image_corrs[image_id].insert(point2D_idx);
180 
181  size_t corr_queue_begin = 0;
182  size_t corr_queue_end = found_corrs.size();
183 
184  for (size_t t = 0; t < transitivity; ++t) {
185  // Collect correspondences at transitive level t to all
186  // correspondences that were collected at transitive level t - 1.
187  for (size_t i = corr_queue_begin; i < corr_queue_end; ++i) {
188  const Correspondence ref_corr = found_corrs[i];
189 
190  const Image& image = images_.at(ref_corr.image_id);
191  const std::vector<Correspondence>& ref_corrs =
192  image.corrs[ref_corr.point2D_idx];
193 
194  for (const Correspondence& corr : ref_corrs) {
195  // Check if correspondence already collected, otherwise collect.
196  auto& corr_image_corrs = image_corrs[corr.image_id];
197  if (corr_image_corrs.count(corr.point2D_idx) == 0) {
198  corr_image_corrs.insert(corr.point2D_idx);
199  found_corrs.emplace_back(corr.image_id, corr.point2D_idx);
200  }
201  }
202  }
203 
204  // Move on to the next block of correspondences at next transitive level.
205  corr_queue_begin = corr_queue_end;
206  corr_queue_end = found_corrs.size();
207 
208  // No new correspondences collected in last transitivity level.
209  if (corr_queue_begin == corr_queue_end) {
210  break;
211  }
212  }
213 
214  // Remove first element, which is the given observation by swapping it
215  // with the last collected correspondence.
216  if (found_corrs.size() > 1) {
217  found_corrs.front() = found_corrs.back();
218  }
219  found_corrs.pop_back();
220 
221  return found_corrs;
222 }
223 
225  const image_t image_id1, const image_t image_id2) const {
226  const auto num_correspondences =
227  NumCorrespondencesBetweenImages(image_id1, image_id2);
228 
229  if (num_correspondences == 0) {
230  return {};
231  }
232 
233  FeatureMatches found_corrs;
234  found_corrs.reserve(num_correspondences);
235 
236  const struct Image& image1 = images_.at(image_id1);
237 
238  for (point2D_t point2D_idx1 = 0; point2D_idx1 < image1.corrs.size();
239  ++point2D_idx1) {
240  for (const Correspondence& corr1 : image1.corrs[point2D_idx1]) {
241  if (corr1.image_id == image_id2) {
242  found_corrs.emplace_back(point2D_idx1, corr1.point2D_idx);
243  }
244  }
245  }
246 
247  return found_corrs;
248 }
249 
251  const image_t image_id, const point2D_t point2D_idx) const {
252  const struct Image& image = images_.at(image_id);
253  const std::vector<Correspondence>& corrs = image.corrs.at(point2D_idx);
254  if (corrs.size() != 1) {
255  return false;
256  }
257  const struct Image& other_image = images_.at(corrs[0].image_id);
258  const std::vector<Correspondence>& other_corrs =
259  other_image.corrs.at(corrs[0].point2D_idx);
260  return other_corrs.size() == 1;
261 }
262 
263 } // namespace colmap
std::shared_ptr< core::Tensor > image
bool HasCorrespondences(const image_t image_id, const point2D_t point2D_idx) const
bool ExistsImage(const image_t image_id) const
const std::vector< Correspondence > & FindCorrespondences(const image_t image_id, const point2D_t point2D_idx) const
void AddImage(const image_t image_id, const size_t num_points2D)
FeatureMatches FindCorrespondencesBetweenImages(const image_t image_id1, const image_t image_id2) const
std::vector< Correspondence > FindTransitiveCorrespondences(const image_t image_id, const point2D_t point2D_idx, const size_t transitivity) const
bool IsTwoViewObservation(const image_t image_id, const point2D_t point2D_idx) const
void AddCorrespondences(const image_t image_id1, const image_t image_id2, const FeatureMatches &matches)
std::unordered_map< image_pair_t, point2D_t > NumCorrespondencesBetweenImages() const
static image_pair_t ImagePairToPairId(const image_t image_id1, const image_t image_id2)
Definition: database.h:339
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
uint64_t image_pair_t
Definition: types.h:64
uint32_t point2D_t
Definition: types.h:67
uint32_t image_t
Definition: types.h:61
std::string StringPrintf(const char *format,...)
Definition: string.cc:131
std::vector< FeatureMatch > FeatureMatches
Definition: types.h:80