Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pyramid_feature_matching.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011, Alexandru-Eugen Ichim
5  * Willow Garage, Inc
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of Willow Garage, Inc. nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * $Id: pyramid_feature_matching.hpp 5026 2012-03-12 02:51:44Z rusu $
36  */
37 
38 #ifndef PCL_REGISTRATION_IMPL_PYRAMID_FEATURE_MATCHING_H_
39 #define PCL_REGISTRATION_IMPL_PYRAMID_FEATURE_MATCHING_H_
40 
41 #include <pcl/pcl_macros.h>
42 
44 
49 __inline double
50 Log2 (double n_arg)
51 {
52  return log (n_arg) / M_LN2;
53 }
54 
55 
57 template <typename PointFeature> float
59  const PyramidFeatureHistogramPtr &pyramid_b)
60 {
61  // do a few consistency checks before and during the computation
62  if (pyramid_a->nr_dimensions != pyramid_b->nr_dimensions)
63  {
64  PCL_ERROR ("[pcl::PyramidFeatureMatching::comparePyramidFeatureHistograms] The two given pyramids have different numbers of dimensions: %u vs %u\n", pyramid_a->nr_dimensions, pyramid_b->nr_dimensions);
65  return -1;
66  }
67  if (pyramid_a->nr_levels != pyramid_b->nr_levels)
68  {
69  PCL_ERROR ("[pcl::PyramidFeatureMatching::comparePyramidFeatureHistograms] The two given pyramids have different numbers of levels: %u vs %u\n", pyramid_a->nr_levels, pyramid_b->nr_levels);
70  return -1;
71  }
72 
73 
74  // calculate for level 0 first
75  if (pyramid_a->hist_levels[0].hist.size () != pyramid_b->hist_levels[0].hist.size ())
76  {
77  PCL_ERROR ("[pcl::PyramidFeatureMatching::comparePyramidFeatureHistograms] The two given pyramids have different numbers of bins on level 0: %u vs %u\n", pyramid_a->hist_levels[0].hist.size (), pyramid_b->hist_levels[0].hist.size ());
78  return -1;
79  }
80  float match_count_level = 0.0f, match_count_prev_level = 0.0f;
81  for (size_t bin_i = 0; bin_i < pyramid_a->hist_levels[0].hist.size (); ++bin_i)
82  {
83  if (pyramid_a->hist_levels[0].hist[bin_i] < pyramid_b->hist_levels[0].hist[bin_i])
84  match_count_level += static_cast<float> (pyramid_a->hist_levels[0].hist[bin_i]);
85  else
86  match_count_level += static_cast<float> (pyramid_b->hist_levels[0].hist[bin_i]);
87  }
88 
89 
90  float match_count = match_count_level;
91  for (size_t level_i = 1; level_i < pyramid_a->nr_levels; ++level_i)
92  {
93  if (pyramid_a->hist_levels[level_i].hist.size () != pyramid_b->hist_levels[level_i].hist.size ())
94  {
95  PCL_ERROR ("[pcl::PyramidFeatureMatching::comparePyramidFeatureHistograms] The two given pyramids have different numbers of bins on level %u: %u vs %u\n", level_i, pyramid_a->hist_levels[level_i].hist.size (), pyramid_b->hist_levels[level_i].hist.size ());
96  return -1;
97  }
98 
99  match_count_prev_level = match_count_level;
100  match_count_level = 0.0f;
101  for (size_t bin_i = 0; bin_i < pyramid_a->hist_levels[level_i].hist.size (); ++bin_i)
102  {
103  if (pyramid_a->hist_levels[level_i].hist[bin_i] < pyramid_b->hist_levels[level_i].hist[bin_i])
104  match_count_level += static_cast<float> (pyramid_a->hist_levels[level_i].hist[bin_i]);
105  else
106  match_count_level += static_cast<float> (pyramid_b->hist_levels[level_i].hist[bin_i]);
107  }
108 
109  float level_normalization_factor = powf (2.0f, static_cast<float> (level_i));
110  match_count += (match_count_level - match_count_prev_level) / level_normalization_factor;
111  }
112 
113 
114  // include self-similarity factors
115  float self_similarity_a = static_cast<float> (pyramid_a->nr_features),
116  self_similarity_b = static_cast<float> (pyramid_b->nr_features);
117  PCL_DEBUG ("[pcl::PyramidFeatureMatching::comparePyramidFeatureHistograms] Self similarity measures: %f, %f\n", self_similarity_a, self_similarity_b);
118  match_count /= sqrtf (self_similarity_a * self_similarity_b);
119 
120  return match_count;
121 }
122 
123 
125 template <typename PointFeature>
127  nr_dimensions (0), nr_levels (0), nr_features (0),
128  dimension_range_input_ (), dimension_range_target_ (),
129  feature_representation_ (new DefaultPointRepresentation<PointFeature>),
130  is_computed_ (false),
131  hist_levels ()
132 {
133 }
134 
136 template <typename PointFeature> void
138 {
139  size_t total_vector_size = 1;
140  for (std::vector<size_t>::iterator dim_it = bins_per_dimension.begin (); dim_it != bins_per_dimension.end (); ++dim_it)
141  total_vector_size *= *dim_it;
142 
143  hist.resize (total_vector_size, 0);
144 }
145 
146 
148 template <typename PointFeature> bool
150 {
151  // a few consistency checks before starting the computations
152  if (!PCLBase<PointFeature>::initCompute ())
153  {
154  PCL_ERROR ("[pcl::PyramidFeatureHistogram::initializeHistogram] PCLBase initCompute failed\n");
155  return false;
156  }
157 
158  if (dimension_range_input_.size () == 0)
159  {
160  PCL_ERROR ("[pcl::PyramidFeatureHistogram::initializeHistogram] Input dimension range was not set\n");
161  return false;
162  }
163 
164  if (dimension_range_target_.size () == 0)
165  {
166  PCL_ERROR ("[pcl::PyramidFeatureHistogram::initializeHistogram] Target dimension range was not set\n");
167  return false;
168  }
169 
170  if (dimension_range_input_.size () != dimension_range_target_.size ())
171  {
172  PCL_ERROR ("[pcl::PyramidFeatureHistogram::initializeHistogram] Input and target dimension ranges do not agree in size: %u vs %u\n",
173  dimension_range_input_.size (), dimension_range_target_.size ());
174  return false;
175  }
176 
177 
178  nr_dimensions = dimension_range_target_.size ();
179  nr_features = input_->points.size ();
180  float D = 0.0f;
181  for (std::vector<std::pair<float, float> >::iterator range_it = dimension_range_target_.begin (); range_it != dimension_range_target_.end (); ++range_it)
182  {
183  float aux = range_it->first - range_it->second;
184  D += aux * aux;
185  }
186  D = sqrtf (D);
187  nr_levels = static_cast<size_t> (ceilf (log2f (D)));
188  PCL_DEBUG ("[pcl::PyramidFeatureHistogram::initializeHistogram] Pyramid will have %u levels with a hyper-parallelepiped diagonal size of %f\n", nr_levels, D);
189 
190 
191  hist_levels.resize (nr_levels);
192  for (size_t level_i = 0; level_i < nr_levels; ++level_i)
193  {
194  std::vector<size_t> bins_per_dimension (nr_dimensions);
195  std::vector<float> bin_step (nr_dimensions);
196  for (size_t dim_i = 0; dim_i < nr_dimensions; ++dim_i)
197  {
198  bins_per_dimension[dim_i] =
199  static_cast<size_t> (ceilf ((dimension_range_target_[dim_i].second - dimension_range_target_[dim_i].first) / (powf (2.0f, static_cast<float> (level_i)) * sqrtf (static_cast<float> (nr_dimensions)))));
200  bin_step[dim_i] = powf (2.0f, static_cast<float> (level_i)) * sqrtf (static_cast<float> (nr_dimensions));
201  }
202  hist_levels[level_i] = PyramidFeatureHistogramLevel (bins_per_dimension, bin_step);
203 
204  PCL_DEBUG ("[pcl::PyramidFeatureHistogram::initializeHistogram] Created vector of size %u at level %u\nwith #bins per dimension:", hist_levels.back ().hist.size (), level_i);
205  for (size_t dim_i = 0; dim_i < nr_dimensions; ++dim_i)
206  PCL_DEBUG ("%u ", bins_per_dimension[dim_i]);
207  PCL_DEBUG ("\n");
208  }
209 
210  return true;
211 }
212 
213 
215 template <typename PointFeature> unsigned int&
216 pcl::PyramidFeatureHistogram<PointFeature>::at (std::vector<size_t> &access,
217  size_t &level)
218 {
219  if (access.size () != nr_dimensions)
220  {
221  PCL_ERROR ("[pcl::PyramidFeatureHistogram::at] Cannot access histogram position because the access point does not have the right number of dimensions\n");
222  return hist_levels.front ().hist.front ();
223  }
224  if (level >= hist_levels.size ())
225  {
226  PCL_ERROR ("[pcl::PyramidFeatureHistogram::at] Trying to access a too large level\n");
227  return hist_levels.front ().hist.front ();
228  }
229 
230  size_t vector_position = 0;
231  size_t dim_accumulator = 1;
232 
233  for (int i = static_cast<int> (access.size ()) - 1; i >= 0; --i)
234  {
235  vector_position += access[i] * dim_accumulator;
236  dim_accumulator *= hist_levels[level].bins_per_dimension[i];
237  }
238 
239  return hist_levels[level].hist[vector_position];
240 }
241 
242 
244 template <typename PointFeature> unsigned int&
245 pcl::PyramidFeatureHistogram<PointFeature>::at (std::vector<float> &feature,
246  size_t &level)
247 {
248  if (feature.size () != nr_dimensions)
249  {
250  PCL_ERROR ("[pcl::PyramidFeatureHistogram::at] The given feature vector does not match the feature dimensions of the pyramid histogram: %u vs %u\n", feature.size (), nr_dimensions);
251  return hist_levels.front ().hist.front ();
252  }
253  if (level >= hist_levels.size ())
254  {
255  PCL_ERROR ("[pcl::PyramidFeatureHistogram::at] Trying to access a too large level\n");
256  return hist_levels.front ().hist.front ();
257  }
258 
259  std::vector<size_t> access;
260  for (size_t dim_i = 0; dim_i < nr_dimensions; ++dim_i)
261  access.push_back (static_cast<size_t> (floor ((feature[dim_i] - dimension_range_target_[dim_i].first) / hist_levels[level].bin_step[dim_i])));
262 
263  return at (access, level);
264 }
265 
266 
268 template <typename PointFeature> void
270  std::vector<float> &feature_vector)
271 {
272  // convert feature to vector representation
273  feature_vector.resize (feature_representation_->getNumberOfDimensions ());
274  feature_representation_->vectorize (feature, feature_vector);
275 
276  // adapt the values from the input range to the target range
277  for (size_t i = 0; i < feature_vector.size (); ++i)
278  feature_vector[i] = (feature_vector[i] - dimension_range_input_[i].first) / (dimension_range_input_[i].second - dimension_range_input_[i].first) *
279  (dimension_range_target_[i].second - dimension_range_target_[i].first) + dimension_range_target_[i].first;
280 }
281 
282 
284 template <typename PointFeature> void
286 {
287  if (!initializeHistogram ())
288  return;
289 
290  for (size_t feature_i = 0; feature_i < input_->points.size (); ++feature_i)
291  {
292  std::vector<float> feature_vector;
293  convertFeatureToVector (input_->points[feature_i], feature_vector);
294  addFeature (feature_vector);
295  }
296 
297  is_computed_ = true;
298 }
299 
300 
302 template <typename PointFeature> void
303 pcl::PyramidFeatureHistogram<PointFeature>::addFeature (std::vector<float> &feature)
304 {
305  for (size_t level_i = 0; level_i < nr_levels; ++level_i)
306  at (feature, level_i) ++;
307 }
308 
309 #define PCL_INSTANTIATE_PyramidFeatureHistogram(PointFeature) template class PCL_EXPORTS pcl::PyramidFeatureHistogram<PointFeature>;
310 
311 #endif /* PCL_REGISTRATION_IMPL_PYRAMID_FEATURE_MATCHING_H_ */