Berkeley SfM
naive_matcher_2d3d.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: David Fridovich-Keil ( dfk@eecs.berkeley.edu )
35  * Erik Nelson ( eanelson@eecs.berkeley.edu )
36  */
37 
38 #include "naive_matcher_2d3d.h"
39 
40 namespace bsfm {
41 
43 
45 
47  const FeatureMatcherOptions& options, const ViewIndex& view_index,
48  const std::vector<LandmarkIndex>& landmark_indices) {
49  // Copy options.
50  options_ = options;
51 
52  // Make sure the view is valid.
53  View::Ptr view = View::GetView(view_index);
54  if (view == nullptr) {
55  LOG(WARNING) << "Cannot perform 2D<-->3D matching. View must not be null.";
56  return false;
57  }
58 
59  // Get descriptors from unincorporated observations in the view.
60  std::vector<Descriptor> descriptors_2d;
61  std::vector<size_t> observation_indices;
62  std::vector<Observation::Ptr> observations = view->Observations();
63  for (size_t ii = 0; ii < observations.size(); ++ii) {
64  CHECK_NOTNULL(observations[ii].get());
65  if (!observations[ii]->IsIncorporated()) {
66  descriptors_2d.push_back(observations[ii]->Descriptor());
67  observation_indices.push_back(ii);
68  }
69  }
70 
71  // Get descriptors from landmarks.
72  std::vector<Descriptor> descriptors_3d;
73  descriptors_3d.reserve(landmark_indices.size());
74  for (size_t ii = 0; ii < landmark_indices.size(); ii++) {
75  Landmark::Ptr landmark = Landmark::GetLandmark(landmark_indices[ii]);
76  CHECK_NOTNULL(landmark.get());
77  descriptors_3d.push_back(landmark->Descriptor());
78  }
79 
80  // Normalize descriptors if required by the distance metric.
83 
84  // Compute forward matches.
85  std::vector<LightFeatureMatch> forward_matches;
86  ComputeOneWayMatches(descriptors_2d, descriptors_3d, forward_matches);
87 
88  if (forward_matches.size() < options_.min_num_feature_matches)
89  return false;
90 
91  // Compute reverse matches if needed.
93  std::vector<LightFeatureMatch> reverse_matches;
94  ComputeOneWayMatches(descriptors_3d, descriptors_2d, reverse_matches);
95  ComputeSymmetricMatches(reverse_matches, forward_matches);
96  }
97 
98  // Symmetric matches are now stored in 'forward_matches'.
99  if (forward_matches.size() < options_.min_num_feature_matches)
100  return false;
101 
102  // Check how many features the user wants.
103  size_t num_features_out = forward_matches.size();
105  num_features_out =
106  std::min(num_features_out, static_cast<size_t>(options_.num_best_matches));
107 
108  // Return relevant matches in sorted order.
109  std::partial_sort(forward_matches.begin(),
110  forward_matches.begin() + num_features_out,
111  forward_matches.end(),
113  }
114 
115  // Update Observations in the provided view based on their matches with
116  // landmarks. Also set all observations as matched.
117  for (size_t ii = 0; ii < forward_matches.size(); ii++) {
118  const size_t observation_index =
119  observation_indices[forward_matches[ii].feature_index1_];
120  const LandmarkIndex landmark_index =
121  landmark_indices[forward_matches[ii].feature_index2_];
122 
123  observations[observation_index]->SetMatchedLandmark(landmark_index);
124  }
125 
126  return true;
127 }
128 
129 // Compute one-way matches.
130 // Note: this is essentially the function
131 // NaiveFeatureMatcher::ComputePutativeMatches but it has been adjusted slightly
132 // for this 2d-3d matcher.
134  const std::vector<Descriptor>& descriptors1,
135  const std::vector<Descriptor>& descriptors2,
136  std::vector<LightFeatureMatch>& matches) {
137  matches.clear();
138 
139  // Get the singletone distance metric for descriptor comparison.
141 
142  // Set the maximum tolerable distance between descriptors, if applicable.
145  }
146 
147  // Store all matches and their distances.
148  for (size_t ii = 0; ii < descriptors1.size(); ++ii) {
149  LightFeatureMatchList one_way_matches;
150  for (size_t jj = 0; jj < descriptors2.size(); ++jj) {
151  double dist = distance(descriptors1[ii], descriptors2[jj]);
152 
153  // If max distance was not set above, distance.Max() will be infinity and
154  // this will always be true.
155  if (dist < distance.Max()) {
156  one_way_matches.emplace_back(ii, jj, dist);
157  }
158  }
159 
160  // Store the best match for this element of features2.
162  // Sort by distance. We only care about the distances between the best 2
163  // matches for the Lowes ratio test.
164  std::partial_sort(one_way_matches.begin(),
165  one_way_matches.begin() + 1,
166  one_way_matches.end(),
168 
169  // The second best match must be within the lowes ratio of the best match.
170  double lowes_ratio_squared =
172  if (one_way_matches[0].distance_ <
173  lowes_ratio_squared * one_way_matches[1].distance_) {
174  matches.emplace_back(one_way_matches[0]);
175  }
176  } else {
177  matches.emplace_back(one_way_matches[0]);
178  }
179  }
180 }
181 
182 // Compute symmetric matches.
183 // Note: this is essentially the function FeatureMatcher::SymmetricMatches
184 // but it has been adjusted slightly for this 2d-3d matcher.
186  const std::vector<LightFeatureMatch>& feature_matches_lhs,
187  std::vector<LightFeatureMatch>& feature_matches_rhs) {
188  // Keep track of symmetric matches in a hash table.
189  std::unordered_map<int, int> feature_indices;
190  feature_indices.reserve(feature_matches_lhs.size());
191 
192  // Add all LHS matches to the map.
193  for (const auto& feature_match : feature_matches_lhs) {
194  feature_indices.insert(std::make_pair(feature_match.feature_index1_,
195  feature_match.feature_index2_));
196  }
197 
198  // For each match in the RHS set, search for the same match in the LHS set.
199  // If the match is not symmetric, remove it from the RHS set.
200  auto rhs_iter = feature_matches_rhs.begin();
201  while (rhs_iter != feature_matches_rhs.end()) {
202  const auto& lhs_matched_iter =
203  feature_indices.find(rhs_iter->feature_index2_);
204 
205  // If a symmetric match is found, keep it in the RHS set.
206  if (lhs_matched_iter != feature_indices.end()) {
207  if (lhs_matched_iter->second == rhs_iter->feature_index1_) {
208  ++rhs_iter;
209  continue;
210  }
211  }
212 
213  // Remove the non-symmetric match and continue on.
214  feature_matches_rhs.erase(rhs_iter);
215  }
216 }
217 
218 
219 } //\namespace bsfm
static Landmark::Ptr GetLandmark(LandmarkIndex landmark_index)
Definition: landmark.cpp:59
unsigned int ViewIndex
Definition: types.h:58
unsigned int LandmarkIndex
Definition: types.h:62
bool Match(const FeatureMatcherOptions &options, const ViewIndex &view_index, const std::vector< LandmarkIndex > &landmark_indices)
std::vector< LightFeatureMatch > LightFeatureMatchList
static DistanceMetric & Instance()
static bool SortByDistance(const LightFeatureMatch &lhs, const LightFeatureMatch &rhs)
Definition: feature_match.h:93
void SetMaximumDistance(double maximum_distance)
void ComputeSymmetricMatches(const std::vector< LightFeatureMatch > &feature_matches_lhs, std::vector< LightFeatureMatch > &feature_matches_rhs)
static View::Ptr GetView(ViewIndex view_index)
Definition: view.cpp:60
Definition: camera.cpp:50
std::shared_ptr< Landmark > Ptr
Definition: landmark.h:66
std::shared_ptr< View > Ptr
Definition: view.h:66
void ComputeOneWayMatches(const std::vector< Descriptor > &descriptors1, const std::vector< Descriptor > &descriptors2, std::vector< LightFeatureMatch > &matches)
bool MaybeNormalizeDescriptors(std::vector< Descriptor > &descriptors) const
::Eigen::Matrix< double, Eigen::Dynamic, 1 > Descriptor
Definition: types.h:83
FeatureMatcherOptions options_