Point Cloud Library (PCL)  1.15.1-dev
statistical_multiscale_interest_region_extraction.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2011, Alexandru-Eugen Ichim
6  * Copyright (c) 2012-, Open Perception, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id$
38  */
39 
40 #ifndef PCL_FEATURES_IMPL_STATISTICAL_MULTISCALE_INTEREST_REGION_EXTRACTION_H_
41 #define PCL_FEATURES_IMPL_STATISTICAL_MULTISCALE_INTEREST_REGION_EXTRACTION_H_
42 
43 #include <pcl/features/statistical_multiscale_interest_region_extraction.h>
44 #include <pcl/search/auto.h>
45 #include <pcl/common/distances.h>
46 #include <pcl/console/print.h> // for PCL_INFO, PCL_ERROR
47 #include <boost/graph/adjacency_list.hpp>
48 #include <boost/graph/johnson_all_pairs_shortest.hpp>
49 
50 
51 //////////////////////////////////////////////////////////////////////////////////////////////
52 template <typename PointT> void
54 {
55  // generate a K-NNG (K-nearest neighbors graph)
56  typename pcl::search::Search<PointT>::Ptr kdtree(pcl::search::autoSelectMethod<PointT> (input_, true, pcl::search::Purpose::many_knn_search));
57 
58  using namespace boost;
59  using Weight = property<edge_weight_t, float>;
60  using Graph = adjacency_list<vecS, vecS, undirectedS, no_property, Weight>;
61  Graph cloud_graph;
62 
63  for (std::size_t point_i = 0; point_i < input_->size (); ++point_i)
64  {
65  pcl::Indices k_indices (16);
66  std::vector<float> k_distances (16);
67  kdtree->nearestKSearch (static_cast<int> (point_i), 16, k_indices, k_distances);
68 
69  for (std::size_t k_i = 0; k_i < k_indices.size (); ++k_i)
70  add_edge (point_i, k_indices[k_i], Weight (std::sqrt (k_distances[k_i])), cloud_graph);
71  }
72 
73  const std::size_t E = num_edges (cloud_graph),
74  V = num_vertices (cloud_graph);
75  PCL_INFO ("The graph has %lu vertices and %lu edges.\n", V, E);
76  geodesic_distances_.clear ();
77  for (std::size_t i = 0; i < V; ++i)
78  {
79  std::vector<float> aux (V);
80  geodesic_distances_.push_back (aux);
81  }
82  johnson_all_pairs_shortest_paths (cloud_graph, geodesic_distances_);
83 
84  PCL_INFO ("Done generating the graph\n");
85 }
86 
87 
88 //////////////////////////////////////////////////////////////////////////////////////////////
89 template <typename PointT> bool
91 {
93  {
94  PCL_ERROR ("[pcl::StatisticalMultiscaleInterestRegionExtraction::initCompute] PCLBase::initCompute () failed - no input cloud was given.\n");
95  return (false);
96  }
97  if (scale_values_.empty ())
98  {
99  PCL_ERROR ("[pcl::StatisticalMultiscaleInterestRegionExtraction::initCompute] No scale values were given\n");
100  return (false);
101  }
102 
103  return (true);
104 }
105 
106 
107 //////////////////////////////////////////////////////////////////////////////////////////////
108 template <typename PointT> void
110  float &radius,
111  std::vector<int> &result_indices)
112 {
113  for (std::size_t i = 0; i < geodesic_distances_[query_index].size (); ++i)
114  if (i != query_index && geodesic_distances_[query_index][i] < radius)
115  result_indices.push_back (static_cast<int> (i));
116 }
117 
118 
119 //////////////////////////////////////////////////////////////////////////////////////////////
120 template <typename PointT> void
122 {
123  if (!initCompute ())
124  {
125  PCL_ERROR ("StatisticalMultiscaleInterestRegionExtraction: not completely initialized\n");
126  return;
127  }
128 
129  generateCloudGraph ();
130 
131  computeF ();
132 
133  extractExtrema (rois);
134 }
135 
136 
137 //////////////////////////////////////////////////////////////////////////////////////////////
138 template <typename PointT> void
140 {
141  PCL_INFO ("Calculating statistical information\n");
142 
143  // declare and initialize data structure
144  F_scales_.resize (scale_values_.size ());
145  std::vector<float> point_density (input_->size ()),
146  F (input_->size ());
147  std::vector<std::vector<float> > phi (input_->size ());
148  std::vector<float> phi_row (input_->size ());
149 
150  for (std::size_t scale_i = 0; scale_i < scale_values_.size (); ++scale_i)
151  {
152  float scale_squared = scale_values_[scale_i] * scale_values_[scale_i];
153 
154  // calculate point density for each point x_i
155  for (std::size_t point_i = 0; point_i < input_->size (); ++point_i)
156  {
157  float point_density_i = 0.0;
158  for (std::size_t point_j = 0; point_j < input_->size (); ++point_j)
159  {
160  float d_g = geodesic_distances_[point_i][point_j];
161  float phi_i_j = 1.0f / std::sqrt (2.0f * static_cast<float> (M_PI) * scale_squared) * std::exp ( (-1) * d_g*d_g / (2.0f * scale_squared));
162 
163  point_density_i += phi_i_j;
164  phi_row[point_j] = phi_i_j;
165  }
166  point_density[point_i] = point_density_i;
167  phi[point_i] = phi_row;
168  }
169 
170  // compute weights for each pair (x_i, x_j), evaluate the operator A_hat
171  for (std::size_t point_i = 0; point_i < input_->size (); ++point_i)
172  {
173  float A_hat_normalization = 0.0;
174  PointT A_hat; A_hat.x = A_hat.y = A_hat.z = 0.0;
175  for (std::size_t point_j = 0; point_j < input_->size (); ++point_j)
176  {
177  float phi_hat_i_j = phi[point_i][point_j] / (point_density[point_i] * point_density[point_j]);
178  A_hat_normalization += phi_hat_i_j;
179 
180  PointT aux = (*input_)[point_j];
181  aux.x *= phi_hat_i_j; aux.y *= phi_hat_i_j; aux.z *= phi_hat_i_j;
182 
183  A_hat.x += aux.x; A_hat.y += aux.y; A_hat.z += aux.z;
184  }
185  A_hat.x /= A_hat_normalization; A_hat.y /= A_hat_normalization; A_hat.z /= A_hat_normalization;
186 
187  // compute the invariant F
188  float aux = 2.0f / scale_values_[scale_i] * euclideanDistance<PointT, PointT> (A_hat, (*input_)[point_i]);
189  F[point_i] = aux * std::exp (-aux);
190  }
191 
192  F_scales_[scale_i] = F;
193  }
194 }
195 
196 
197 //////////////////////////////////////////////////////////////////////////////////////////////
198 template <typename PointT> void
200 {
201  std::vector<std::vector<bool> > is_min (scale_values_.size ()),
202  is_max (scale_values_.size ());
203 
204  // for each point, check if it is a local extrema on each scale
205  for (std::size_t scale_i = 0; scale_i < scale_values_.size (); ++scale_i)
206  {
207  std::vector<bool> is_min_scale (input_->size ()),
208  is_max_scale (input_->size ());
209  for (std::size_t point_i = 0; point_i < input_->size (); ++point_i)
210  {
211  std::vector<int> nn_indices;
212  geodesicFixedRadiusSearch (point_i, scale_values_[scale_i], nn_indices);
213  bool is_max_point = true, is_min_point = true;
214  for (const auto &nn_index : nn_indices)
215  if (F_scales_[scale_i][point_i] < F_scales_[scale_i][nn_index])
216  is_max_point = false;
217  else
218  is_min_point = false;
219 
220  is_min_scale[point_i] = is_min_point;
221  is_max_scale[point_i] = is_max_point;
222  }
223 
224  is_min[scale_i] = is_min_scale;
225  is_max[scale_i] = is_max_scale;
226  }
227 
228  // look for points that are min/max over three consecutive scales
229  for (std::size_t scale_i = 1; scale_i < scale_values_.size () - 1; ++scale_i)
230  {
231  for (std::size_t point_i = 0; point_i < input_->size (); ++point_i)
232  if ((is_min[scale_i - 1][point_i] && is_min[scale_i][point_i] && is_min[scale_i + 1][point_i]) ||
233  (is_max[scale_i - 1][point_i] && is_max[scale_i][point_i] && is_max[scale_i + 1][point_i]))
234  {
235  // add the point to the result vector
236  IndicesPtr region (new pcl::Indices);
237  region->push_back (static_cast<int> (point_i));
238 
239  // and also add its scale-sized geodesic neighborhood
240  std::vector<int> nn_indices;
241  geodesicFixedRadiusSearch (point_i, scale_values_[scale_i], nn_indices);
242  region->insert (region->end (), nn_indices.begin (), nn_indices.end ());
243  rois.push_back (region);
244  }
245  }
246 }
247 
248 
249 #define PCL_INSTANTIATE_StatisticalMultiscaleInterestRegionExtraction(T) template class PCL_EXPORTS pcl::StatisticalMultiscaleInterestRegionExtraction<T>;
250 
251 #endif /* PCL_FEATURES_IMPL_STATISTICAL_MULTISCALE_INTEREST_REGION_EXTRACTION_H_ */
252 
PCL base class.
Definition: pcl_base.h:70
Class for extracting interest regions from unstructured point clouds, based on a multi scale statisti...
void computeRegionsOfInterest(std::list< IndicesPtr > &rois)
The method to be called in order to run the algorithm and produce the resulting set of regions of int...
void generateCloudGraph()
Method that generates the underlying nearest neighbor graph based on the input point cloud.
shared_ptr< pcl::search::Search< PointT > > Ptr
Definition: search.h:81
virtual int nearestKSearch(const PointT &point, int k, Indices &k_indices, std::vector< float > &k_sqr_distances) const =0
Search for the k-nearest neighbors for the given query point.
Define standard C methods to do distance calculations.
@ many_knn_search
The search method will mainly be used for nearestKSearch where k is larger than 1.
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition: types.h:133
shared_ptr< Indices > IndicesPtr
Definition: pcl_base.h:58
#define M_PI
Definition: pcl_macros.h:203
A point structure representing Euclidean xyz coordinates, and the RGB color.