Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
fpfh.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2011, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $Id: fpfh.hpp 4927 2012-03-07 03:35:53Z rusu $
37  *
38  */
39 
40 #ifndef PCL_FEATURES_IMPL_FPFH_H_
41 #define PCL_FEATURES_IMPL_FPFH_H_
42 
43 #include <pcl/features/fpfh.h>
44 #include <pcl/features/pfh.h>
45 
47 template <typename PointInT, typename PointNT, typename PointOutT> bool
49  const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals,
50  int p_idx, int q_idx, float &f1, float &f2, float &f3, float &f4)
51 {
52  pcl::computePairFeatures (cloud.points[p_idx].getVector4fMap (), normals.points[p_idx].getNormalVector4fMap (),
53  cloud.points[q_idx].getVector4fMap (), normals.points[q_idx].getNormalVector4fMap (),
54  f1, f2, f3, f4);
55  return (true);
56 }
57 
59 template <typename PointInT, typename PointNT, typename PointOutT> void
61  const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals,
62  int p_idx, int row, const std::vector<int> &indices,
63  Eigen::MatrixXf &hist_f1, Eigen::MatrixXf &hist_f2, Eigen::MatrixXf &hist_f3)
64 {
65  Eigen::Vector4f pfh_tuple;
66  // Get the number of bins from the histograms size
67  int nr_bins_f1 = static_cast<int> (hist_f1.cols ());
68  int nr_bins_f2 = static_cast<int> (hist_f2.cols ());
69  int nr_bins_f3 = static_cast<int> (hist_f3.cols ());
70 
71  // Factorization constant
72  float hist_incr = 100.0f / static_cast<float>(indices.size () - 1);
73 
74  // Iterate over all the points in the neighborhood
75  for (size_t idx = 0; idx < indices.size (); ++idx)
76  {
77  // Avoid unnecessary returns
78  if (p_idx == indices[idx])
79  continue;
80 
81  // Compute the pair P to NNi
82  if (!computePairFeatures (cloud, normals, p_idx, indices[idx], pfh_tuple[0], pfh_tuple[1], pfh_tuple[2], pfh_tuple[3]))
83  continue;
84 
85  // Normalize the f1, f2, f3 features and push them in the histogram
86  int h_index = static_cast<int> (floor (nr_bins_f1 * ((pfh_tuple[0] + M_PI) * d_pi_)));
87  if (h_index < 0) h_index = 0;
88  if (h_index >= nr_bins_f1) h_index = nr_bins_f1 - 1;
89  hist_f1 (row, h_index) += hist_incr;
90 
91  h_index = static_cast<int> (floor (nr_bins_f2 * ((pfh_tuple[1] + 1.0) * 0.5)));
92  if (h_index < 0) h_index = 0;
93  if (h_index >= nr_bins_f2) h_index = nr_bins_f2 - 1;
94  hist_f2 (row, h_index) += hist_incr;
95 
96  h_index = static_cast<int> (floor (nr_bins_f3 * ((pfh_tuple[2] + 1.0) * 0.5)));
97  if (h_index < 0) h_index = 0;
98  if (h_index >= nr_bins_f3) h_index = nr_bins_f3 - 1;
99  hist_f3 (row, h_index) += hist_incr;
100  }
101 }
102 
104 template <typename PointInT, typename PointNT, typename PointOutT> void
106  const Eigen::MatrixXf &hist_f1, const Eigen::MatrixXf &hist_f2, const Eigen::MatrixXf &hist_f3,
107  const std::vector<int> &indices, const std::vector<float> &dists, Eigen::VectorXf &fpfh_histogram)
108 {
109  assert (indices.size () == dists.size ());
110  double sum_f1 = 0.0, sum_f2 = 0.0, sum_f3 = 0.0;
111  float weight = 0.0, val_f1, val_f2, val_f3;
112 
113  // Get the number of bins from the histograms size
114  int nr_bins_f1 = static_cast<int> (hist_f1.cols ());
115  int nr_bins_f2 = static_cast<int> (hist_f2.cols ());
116  int nr_bins_f3 = static_cast<int> (hist_f3.cols ());
117  int nr_bins_f12 = nr_bins_f1 + nr_bins_f2;
118 
119  // Clear the histogram
120  fpfh_histogram.setZero (nr_bins_f1 + nr_bins_f2 + nr_bins_f3);
121 
122  // Use the entire patch
123  for (size_t idx = 0, data_size = indices.size (); idx < data_size; ++idx)
124  {
125  // Minus the query point itself
126  if (dists[idx] == 0)
127  continue;
128 
129  // Standard weighting function used
130  weight = 1.0f / dists[idx];
131 
132  // Weight the SPFH of the query point with the SPFH of its neighbors
133  for (int f1_i = 0; f1_i < nr_bins_f1; ++f1_i)
134  {
135  val_f1 = hist_f1 (indices[idx], f1_i) * weight;
136  sum_f1 += val_f1;
137  fpfh_histogram[f1_i] += val_f1;
138  }
139 
140  for (int f2_i = 0; f2_i < nr_bins_f2; ++f2_i)
141  {
142  val_f2 = hist_f2 (indices[idx], f2_i) * weight;
143  sum_f2 += val_f2;
144  fpfh_histogram[f2_i + nr_bins_f1] += val_f2;
145  }
146 
147  for (int f3_i = 0; f3_i < nr_bins_f3; ++f3_i)
148  {
149  val_f3 = hist_f3 (indices[idx], f3_i) * weight;
150  sum_f3 += val_f3;
151  fpfh_histogram[f3_i + nr_bins_f12] += val_f3;
152  }
153  }
154 
155  if (sum_f1 != 0)
156  sum_f1 = 100.0 / sum_f1; // histogram values sum up to 100
157  if (sum_f2 != 0)
158  sum_f2 = 100.0 / sum_f2; // histogram values sum up to 100
159  if (sum_f3 != 0)
160  sum_f3 = 100.0 / sum_f3; // histogram values sum up to 100
161 
162  // Adjust final FPFH values
163  for (int f1_i = 0; f1_i < nr_bins_f1; ++f1_i)
164  fpfh_histogram[f1_i] *= static_cast<float> (sum_f1);
165  for (int f2_i = 0; f2_i < nr_bins_f2; ++f2_i)
166  fpfh_histogram[f2_i + nr_bins_f1] *= static_cast<float> (sum_f2);
167  for (int f3_i = 0; f3_i < nr_bins_f3; ++f3_i)
168  fpfh_histogram[f3_i + nr_bins_f12] *= static_cast<float> (sum_f3);
169 }
170 
172 template <typename PointInT, typename PointNT, typename PointOutT> void
174  Eigen::MatrixXf &hist_f1, Eigen::MatrixXf &hist_f2, Eigen::MatrixXf &hist_f3)
175 {
176  // Allocate enough space to hold the NN search results
177  // \note This resize is irrelevant for a radiusSearch ().
178  std::vector<int> nn_indices (k_);
179  std::vector<float> nn_dists (k_);
180 
181  std::set<int> spfh_indices;
182  spfh_hist_lookup.resize (surface_->points.size ());
183 
184  // Build a list of (unique) indices for which we will need to compute SPFH signatures
185  // (We need an SPFH signature for every point that is a neighbor of any point in input_[indices_])
186  if (surface_ != input_ ||
187  indices_->size () != surface_->points.size ())
188  {
189  for (size_t idx = 0; idx < indices_->size (); ++idx)
190  {
191  int p_idx = (*indices_)[idx];
192  if (this->searchForNeighbors (p_idx, search_parameter_, nn_indices, nn_dists) == 0)
193  continue;
194 
195  spfh_indices.insert (nn_indices.begin (), nn_indices.end ());
196  }
197  }
198  else
199  {
200  // Special case: When a feature must be computed at every point, there is no need for a neighborhood search
201  for (size_t idx = 0; idx < indices_->size (); ++idx)
202  spfh_indices.insert (static_cast<int> (idx));
203  }
204 
205  // Initialize the arrays that will store the SPFH signatures
206  size_t data_size = spfh_indices.size ();
207  hist_f1.setZero (data_size, nr_bins_f1_);
208  hist_f2.setZero (data_size, nr_bins_f2_);
209  hist_f3.setZero (data_size, nr_bins_f3_);
210 
211  // Compute SPFH signatures for every point that needs them
212  std::set<int>::iterator spfh_indices_itr = spfh_indices.begin ();
213  for (int i = 0; i < static_cast<int> (spfh_indices.size ()); ++i)
214  {
215  // Get the next point index
216  int p_idx = *spfh_indices_itr;
217  ++spfh_indices_itr;
218 
219  // Find the neighborhood around p_idx
220  if (this->searchForNeighbors (*surface_, p_idx, search_parameter_, nn_indices, nn_dists) == 0)
221  continue;
222 
223  // Estimate the SPFH signature around p_idx
224  computePointSPFHSignature (*surface_, *normals_, p_idx, i, nn_indices, hist_f1, hist_f2, hist_f3);
225 
226  // Populate a lookup table for converting a point index to its corresponding row in the spfh_hist_* matrices
227  spfh_hist_lookup[p_idx] = i;
228  }
229 }
230 
232 template <typename PointInT, typename PointNT, typename PointOutT> void
234 {
235  // Allocate enough space to hold the NN search results
236  // \note This resize is irrelevant for a radiusSearch ().
237  std::vector<int> nn_indices (k_);
238  std::vector<float> nn_dists (k_);
239 
240  std::vector<int> spfh_hist_lookup;
241  computeSPFHSignatures (spfh_hist_lookup, hist_f1_, hist_f2_, hist_f3_);
242 
243  output.is_dense = true;
244  // Save a few cycles by not checking every point for NaN/Inf values if the cloud is set to dense
245  if (input_->is_dense)
246  {
247  // Iterate over the entire index vector
248  for (size_t idx = 0; idx < indices_->size (); ++idx)
249  {
250  if (this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0)
251  {
252  for (int d = 0; d < fpfh_histogram_.size (); ++d)
253  output.points[idx].histogram[d] = std::numeric_limits<float>::quiet_NaN ();
254 
255  output.is_dense = false;
256  continue;
257  }
258 
259  // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices
260  // instead of indices into surface_->points
261  for (size_t i = 0; i < nn_indices.size (); ++i)
262  nn_indices[i] = spfh_hist_lookup[nn_indices[i]];
263 
264  // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ...
265  weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_);
266 
267  // ...and copy it into the output cloud
268  for (int d = 0; d < fpfh_histogram_.size (); ++d)
269  output.points[idx].histogram[d] = fpfh_histogram_[d];
270  }
271  }
272  else
273  {
274  // Iterate over the entire index vector
275  for (size_t idx = 0; idx < indices_->size (); ++idx)
276  {
277  if (!isFinite ((*input_)[(*indices_)[idx]]) ||
278  this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0)
279  {
280  for (int d = 0; d < fpfh_histogram_.size (); ++d)
281  output.points[idx].histogram[d] = std::numeric_limits<float>::quiet_NaN ();
282 
283  output.is_dense = false;
284  continue;
285  }
286 
287  // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices
288  // instead of indices into surface_->points
289  for (size_t i = 0; i < nn_indices.size (); ++i)
290  nn_indices[i] = spfh_hist_lookup[nn_indices[i]];
291 
292  // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ...
293  weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_);
294 
295  // ...and copy it into the output cloud
296  for (int d = 0; d < fpfh_histogram_.size (); ++d)
297  output.points[idx].histogram[d] = fpfh_histogram_[d];
298  }
299  }
300 }
301 
303 template <typename PointInT, typename PointNT> void
305 {
306  // Set up the output channels
307  output.channels["fpfh"].name = "fpfh";
308  output.channels["fpfh"].offset = 0;
309  output.channels["fpfh"].size = 4;
310  output.channels["fpfh"].count = 33;
311  output.channels["fpfh"].datatype = sensor_msgs::PointField::FLOAT32;
312 
313  // Allocate enough space to hold the NN search results
314  // \note This resize is irrelevant for a radiusSearch ().
315  std::vector<int> nn_indices (k_);
316  std::vector<float> nn_dists (k_);
317 
318  std::vector<int> spfh_hist_lookup;
319  this->computeSPFHSignatures (spfh_hist_lookup, hist_f1_, hist_f2_, hist_f3_);
320 
321  // Intialize the array that will store the FPFH signature
322  output.points.resize (indices_->size (), nr_bins_f1_ + nr_bins_f2_ + nr_bins_f3_);
323  output.is_dense = true;
324  // Save a few cycles by not checking every point for NaN/Inf values if the cloud is set to dense
325  if (input_->is_dense)
326  {
327  // Iterate over the entire index vector
328  for (size_t idx = 0; idx < indices_->size (); ++idx)
329  {
330  if (!isFinite ((*input_)[(*indices_)[idx]]) ||
331  this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0)
332  {
333  output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ());
334  output.is_dense = false;
335  continue;
336  }
337 
338  // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices
339  // instead of indices into surface_->points
340  for (size_t i = 0; i < nn_indices.size (); ++i)
341  nn_indices[i] = spfh_hist_lookup[nn_indices[i]];
342 
343  // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ...
344  this->weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_);
345  output.points.row (idx) = fpfh_histogram_;
346  }
347  }
348  else
349  {
350  // Iterate over the entire index vector
351  for (size_t idx = 0; idx < indices_->size (); ++idx)
352  {
353  if (this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0)
354  {
355  output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ());
356  output.is_dense = false;
357  continue;
358  }
359 
360  // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices
361  // instead of indices into surface_->points
362  for (size_t i = 0; i < nn_indices.size (); ++i)
363  nn_indices[i] = spfh_hist_lookup[nn_indices[i]];
364 
365  // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ...
366  this->weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_);
367  output.points.row (idx) = fpfh_histogram_;
368  }
369  }
370 }
371 
372 
373 #define PCL_INSTANTIATE_FPFHEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::FPFHEstimation<T,NT,OutT>;
374 
375 #endif // PCL_FEATURES_IMPL_FPFH_H_
376