Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
statistical_multiscale_interest_region_extraction.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: statistical_multiscale_interest_region_extraction.hpp 5026 2012-03-12 02:51:44Z rusu $
36  */
37 
38 #ifndef PCL_FEATURES_IMPL_STATISTICAL_MULTISCALE_INTEREST_REGION_EXTRACTION_H_
39 #define PCL_FEATURES_IMPL_STATISTICAL_MULTISCALE_INTEREST_REGION_EXTRACTION_H_
40 
43 #include <boost/graph/adjacency_list.hpp>
44 #include <boost/property_map/property_map.hpp>
45 #include <boost/graph/johnson_all_pairs_shortest.hpp>
46 #include <pcl/common/distances.h>
47 
49 template <typename PointT> void
51 {
52  // generate a K-NNG (K-nearest neighbors graph)
54  kdtree.setInputCloud (input_);
55 
56  using namespace boost;
57  typedef property<edge_weight_t, float> Weight;
58  typedef adjacency_list<vecS, vecS, undirectedS, no_property, Weight> Graph;
59  Graph cloud_graph;
60 
61  for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
62  {
63  std::vector<int> k_indices (16);
64  std::vector<float> k_distances (16);
65  kdtree.nearestKSearch (static_cast<int> (point_i), 16, k_indices, k_distances);
66 
67  for (int k_i = 0; k_i < static_cast<int> (k_indices.size ()); ++k_i)
68  add_edge (point_i, k_indices[k_i], Weight (sqrtf (k_distances[k_i])), cloud_graph);
69  }
70 
71  const size_t E = num_edges (cloud_graph),
72  V = num_vertices (cloud_graph);
73  PCL_INFO ("The graph has %lu vertices and %lu edges.\n", V, E);
74  geodesic_distances_.clear ();
75  for (size_t i = 0; i < V; ++i)
76  {
77  std::vector<float> aux (V);
78  geodesic_distances_.push_back (aux);
79  }
80  johnson_all_pairs_shortest_paths (cloud_graph, geodesic_distances_);
81 
82  PCL_INFO ("Done generating the graph\n");
83 }
84 
85 
87 template <typename PointT> bool
89 {
91  {
92  PCL_ERROR ("[pcl::StatisticalMultiscaleInterestRegionExtraction::initCompute] PCLBase::initCompute () failed - no input cloud was given.\n");
93  return (false);
94  }
95  if (scale_values_.empty ())
96  {
97  PCL_ERROR ("[pcl::StatisticalMultiscaleInterestRegionExtraction::initCompute] No scale values were given\n");
98  return (false);
99  }
100 
101  return (true);
102 }
103 
104 
106 template <typename PointT> void
108  float &radius,
109  std::vector<int> &result_indices)
110 {
111  for (size_t i = 0; i < geodesic_distances_[query_index].size (); ++i)
112  if (i != query_index && geodesic_distances_[query_index][i] < radius)
113  result_indices.push_back (static_cast<int> (i));
114 }
115 
116 
118 template <typename PointT> void
120 {
121  if (!initCompute ())
122  {
123  PCL_ERROR ("StatisticalMultiscaleInterestRegionExtraction: not completely initialized\n");
124  return;
125  }
126 
127  generateCloudGraph ();
128 
129  computeF ();
130 
131  extractExtrema (rois);
132 }
133 
134 
136 template <typename PointT> void
138 {
139  PCL_INFO ("Calculating statistical information\n");
140 
141  // declare and initialize data structure
142  F_scales_.resize (scale_values_.size ());
143  std::vector<float> point_density (input_->points.size ()),
144  F (input_->points.size ());
145  std::vector<std::vector<float> > phi (input_->points.size ());
146  std::vector<float> phi_row (input_->points.size ());
147 
148  for (size_t scale_i = 0; scale_i < scale_values_.size (); ++scale_i)
149  {
150  float scale_squared = scale_values_[scale_i] * scale_values_[scale_i];
151 
152  // calculate point density for each point x_i
153  for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
154  {
155  float point_density_i = 0.0;
156  for (size_t point_j = 0; point_j < input_->points.size (); ++point_j)
157  {
158  float d_g = geodesic_distances_[point_i][point_j];
159  float phi_i_j = 1.0f / sqrtf (2.0f * static_cast<float> (M_PI) * scale_squared) * expf ( (-1) * d_g*d_g / (2.0f * scale_squared));
160 
161  point_density_i += phi_i_j;
162  phi_row[point_j] = phi_i_j;
163  }
164  point_density[point_i] = point_density_i;
165  phi[point_i] = phi_row;
166  }
167 
168  // compute weights for each pair (x_i, x_j), evaluate the operator A_hat
169  for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
170  {
171  float A_hat_normalization = 0.0;
172  PointT A_hat; A_hat.x = A_hat.y = A_hat.z = 0.0;
173  for (size_t point_j = 0; point_j < input_->points.size (); ++point_j)
174  {
175  float phi_hat_i_j = phi[point_i][point_j] / (point_density[point_i] * point_density[point_j]);
176  A_hat_normalization += phi_hat_i_j;
177 
178  PointT aux = input_->points[point_j];
179  aux.x *= phi_hat_i_j; aux.y *= phi_hat_i_j; aux.z *= phi_hat_i_j;
180 
181  A_hat.x += aux.x; A_hat.y += aux.y; A_hat.z += aux.z;
182  }
183  A_hat.x /= A_hat_normalization; A_hat.y /= A_hat_normalization; A_hat.z /= A_hat_normalization;
184 
185  // compute the invariant F
186  float aux = 2.0f / scale_values_[scale_i] * euclideanDistance<PointT, PointT> (A_hat, input_->points[point_i]);
187  F[point_i] = aux * expf (-aux);
188  }
189 
190  F_scales_[scale_i] = F;
191  }
192 }
193 
194 
196 template <typename PointT> void
198 {
199  std::vector<std::vector<bool> > is_min (scale_values_.size ()),
200  is_max (scale_values_.size ());
201 
202  // for each point, check if it is a local extrema on each scale
203  for (size_t scale_i = 0; scale_i < scale_values_.size (); ++scale_i)
204  {
205  std::vector<bool> is_min_scale (input_->points.size ()),
206  is_max_scale (input_->points.size ());
207  for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
208  {
209  std::vector<int> nn_indices;
210  geodesicFixedRadiusSearch (point_i, scale_values_[scale_i], nn_indices);
211  bool is_max_point = true, is_min_point = true;
212  for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
213  if (F_scales_[scale_i][point_i] < F_scales_[scale_i][*nn_it])
214  is_max_point = false;
215  else
216  is_min_point = false;
217 
218  is_min_scale[point_i] = is_min_point;
219  is_max_scale[point_i] = is_max_point;
220  }
221 
222  is_min[scale_i] = is_min_scale;
223  is_max[scale_i] = is_max_scale;
224  }
225 
226  // look for points that are min/max over three consecutive scales
227  for (size_t scale_i = 1; scale_i < scale_values_.size () - 1; ++scale_i)
228  {
229  for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
230  if ((is_min[scale_i - 1][point_i] && is_min[scale_i][point_i] && is_min[scale_i + 1][point_i]) ||
231  (is_max[scale_i - 1][point_i] && is_max[scale_i][point_i] && is_max[scale_i + 1][point_i]))
232  {
233  // add the point to the result vector
234  IndicesPtr region (new std::vector<int>);
235  region->push_back (static_cast<int> (point_i));
236 
237  // and also add its scale-sized geodesic neighborhood
238  std::vector<int> nn_indices;
239  geodesicFixedRadiusSearch (point_i, scale_values_[scale_i], nn_indices);
240  region->insert (region->end (), nn_indices.begin (), nn_indices.end ());
241  rois.push_back (region);
242  }
243  }
244 }
245 
246 
247 #define PCL_INSTANTIATE_StatisticalMultiscaleInterestRegionExtraction(T) template class PCL_EXPORTS pcl::StatisticalMultiscaleInterestRegionExtraction<T>;
248 
249 #endif /* PCL_FEATURES_IMPL_STATISTICAL_MULTISCALE_INTEREST_REGION_EXTRACTION_H_ */
250