Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rsd.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2009, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. 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
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id: rsd.hpp 5026 2012-03-12 02:51:44Z rusu $
35  *
36  */
37 
38 #ifndef PCL_FEATURES_IMPL_RSD_H_
39 #define PCL_FEATURES_IMPL_RSD_H_
40 
41 #include <cfloat>
42 #include <pcl/features/rsd.h>
43 
45 template <typename PointInT, typename PointNT, typename PointOutT> Eigen::MatrixXf
46 pcl::computeRSD (boost::shared_ptr<const pcl::PointCloud<PointInT> > &surface, boost::shared_ptr<const pcl::PointCloud<PointNT> > &normals,
47  const std::vector<int> &indices, double max_dist,
48  int nr_subdiv, double plane_radius, PointOutT &radii, bool compute_histogram)
49 {
50  // Check if the full histogram has to be saved or not
51  Eigen::MatrixXf histogram;
52  if (compute_histogram)
53  histogram = Eigen::MatrixXf::Zero (nr_subdiv, nr_subdiv);
54 
55  // Check if enough points are provided or not
56  if (indices.size () < 2)
57  {
58  radii.r_max = 0;
59  radii.r_min = 0;
60  return histogram;
61  }
62 
63  // Initialize minimum and maximum angle values in each distance bin
64  std::vector<std::vector<double> > min_max_angle_by_dist (nr_subdiv);
65  min_max_angle_by_dist[0].resize (2);
66  min_max_angle_by_dist[0][0] = min_max_angle_by_dist[0][1] = 0.0;
67  for (int di=1; di<nr_subdiv; di++)
68  {
69  min_max_angle_by_dist[di].resize (2);
70  min_max_angle_by_dist[di][0] = +DBL_MAX;
71  min_max_angle_by_dist[di][1] = -DBL_MAX;
72  }
73 
74  // Compute distance by normal angle distribution for points
75  std::vector<int>::const_iterator i, begin (indices.begin()), end (indices.end());
76  for(i = begin+1; i != end; ++i)
77  {
78  // compute angle between the two lines going through normals (disregard orientation!)
79  double cosine = normals->points[*i].normal[0] * normals->points[*begin].normal[0] +
80  normals->points[*i].normal[1] * normals->points[*begin].normal[1] +
81  normals->points[*i].normal[2] * normals->points[*begin].normal[2];
82  if (cosine > 1) cosine = 1;
83  if (cosine < -1) cosine = -1;
84  double angle = acos (cosine);
85  if (angle > M_PI/2) angle = M_PI - angle;
86 
87  // Compute point to point distance
88  double dist = sqrt ((surface->points[*i].x - surface->points[*begin].x) * (surface->points[*i].x - surface->points[*begin].x) +
89  (surface->points[*i].y - surface->points[*begin].y) * (surface->points[*i].y - surface->points[*begin].y) +
90  (surface->points[*i].z - surface->points[*begin].z) * (surface->points[*i].z - surface->points[*begin].z));
91 
92  if (dist > max_dist)
93  continue;
94 
95  // compute bins and increase
96  int bin_d = (int) floor (nr_subdiv * dist / max_dist);
97  if (compute_histogram)
98  {
99  int bin_a = std::min (nr_subdiv-1, (int) floor (nr_subdiv * angle / (M_PI/2)));
100  histogram(bin_a, bin_d)++;
101  }
102 
103  // update min-max values for distance bins
104  if (min_max_angle_by_dist[bin_d][0] > angle) min_max_angle_by_dist[bin_d][0] = angle;
105  if (min_max_angle_by_dist[bin_d][1] < angle) min_max_angle_by_dist[bin_d][1] = angle;
106  }
107 
108  // Estimate radius from min and max lines
109  double Amint_Amin = 0, Amint_d = 0;
110  double Amaxt_Amax = 0, Amaxt_d = 0;
111  for (int di=0; di<nr_subdiv; di++)
112  {
113  // combute the members of A'*A*r = A'*D
114  if (min_max_angle_by_dist[di][1] >= 0)
115  {
116  double p_min = min_max_angle_by_dist[di][0];
117  double p_max = min_max_angle_by_dist[di][1];
118  double f = (di+0.5)*max_dist/nr_subdiv;
119  Amint_Amin += p_min * p_min;
120  Amint_d += p_min * f;
121  Amaxt_Amax += p_max * p_max;
122  Amaxt_d += p_max * f;
123  }
124  }
125  float min_radius = Amint_Amin == 0 ? plane_radius : std::min (Amint_d/Amint_Amin, plane_radius);
126  float max_radius = Amaxt_Amax == 0 ? plane_radius : std::min (Amaxt_d/Amaxt_Amax, plane_radius);
127 
128  // Small correction of the systematic error of the estimation (based on analysis with nr_subdiv_ = 5)
129  min_radius *= 1.1;
130  max_radius *= 0.9;
131  if (min_radius < max_radius)
132  {
133  radii.r_min = min_radius;
134  radii.r_max = max_radius;
135  }
136  else
137  {
138  radii.r_max = min_radius;
139  radii.r_min = max_radius;
140  }
141 
142  return histogram;
143 }
144 
146 template <typename PointNT, typename PointOutT> Eigen::MatrixXf
147 pcl::computeRSD (boost::shared_ptr<const pcl::PointCloud<PointNT> > &normals,
148  const std::vector<int> &indices, const std::vector<float> &sqr_dists, double max_dist,
149  int nr_subdiv, double plane_radius, PointOutT &radii, bool compute_histogram)
150 {
151  // Check if the full histogram has to be saved or not
152  Eigen::MatrixXf histogram;
153  if (compute_histogram)
154  histogram = Eigen::MatrixXf::Zero (nr_subdiv, nr_subdiv);
155 
156  // Check if enough points are provided or not
157  if (indices.size () < 2)
158  {
159  radii.r_max = 0;
160  radii.r_min = 0;
161  return histogram;
162  }
163 
164  // Initialize minimum and maximum angle values in each distance bin
165  std::vector<std::vector<double> > min_max_angle_by_dist (nr_subdiv);
166  min_max_angle_by_dist[0].resize (2);
167  min_max_angle_by_dist[0][0] = min_max_angle_by_dist[0][1] = 0.0;
168  for (int di=1; di<nr_subdiv; di++)
169  {
170  min_max_angle_by_dist[di].resize (2);
171  min_max_angle_by_dist[di][0] = +DBL_MAX;
172  min_max_angle_by_dist[di][1] = -DBL_MAX;
173  }
174 
175  // Compute distance by normal angle distribution for points
176  std::vector<int>::const_iterator i, begin (indices.begin()), end (indices.end());
177  for(i = begin+1; i != end; ++i)
178  {
179  // compute angle between the two lines going through normals (disregard orientation!)
180  double cosine = normals->points[*i].normal[0] * normals->points[*begin].normal[0] +
181  normals->points[*i].normal[1] * normals->points[*begin].normal[1] +
182  normals->points[*i].normal[2] * normals->points[*begin].normal[2];
183  if (cosine > 1) cosine = 1;
184  if (cosine < -1) cosine = -1;
185  double angle = acos (cosine);
186  if (angle > M_PI/2) angle = M_PI - angle;
187 
188  // Compute point to point distance
189  double dist = sqrt (sqr_dists[i-begin]);
190 
191  if (dist > max_dist)
192  continue;
193 
194  // compute bins and increase
195  int bin_d = (int) floor (nr_subdiv * dist / max_dist);
196  if (compute_histogram)
197  {
198  int bin_a = std::min (nr_subdiv-1, (int) floor (nr_subdiv * angle / (M_PI/2)));
199  histogram(bin_a, bin_d)++;
200  }
201 
202  // update min-max values for distance bins
203  if (min_max_angle_by_dist[bin_d][0] > angle) min_max_angle_by_dist[bin_d][0] = angle;
204  if (min_max_angle_by_dist[bin_d][1] < angle) min_max_angle_by_dist[bin_d][1] = angle;
205  }
206 
207  // Estimate radius from min and max lines
208  double Amint_Amin = 0, Amint_d = 0;
209  double Amaxt_Amax = 0, Amaxt_d = 0;
210  for (int di=0; di<nr_subdiv; di++)
211  {
212  // combute the members of A'*A*r = A'*D
213  if (min_max_angle_by_dist[di][1] >= 0)
214  {
215  double p_min = min_max_angle_by_dist[di][0];
216  double p_max = min_max_angle_by_dist[di][1];
217  double f = (di+0.5)*max_dist/nr_subdiv;
218  Amint_Amin += p_min * p_min;
219  Amint_d += p_min * f;
220  Amaxt_Amax += p_max * p_max;
221  Amaxt_d += p_max * f;
222  }
223  }
224  float min_radius = Amint_Amin == 0 ? plane_radius : std::min (Amint_d/Amint_Amin, plane_radius);
225  float max_radius = Amaxt_Amax == 0 ? plane_radius : std::min (Amaxt_d/Amaxt_Amax, plane_radius);
226 
227  // Small correction of the systematic error of the estimation (based on analysis with nr_subdiv_ = 5)
228  min_radius *= 1.1;
229  max_radius *= 0.9;
230  if (min_radius < max_radius)
231  {
232  radii.r_min = min_radius;
233  radii.r_max = max_radius;
234  }
235  else
236  {
237  radii.r_max = min_radius;
238  radii.r_min = max_radius;
239  }
240 
241  return histogram;
242 }
243 
245 template <typename PointInT, typename PointNT, typename PointOutT> void
247 {
248  // Check if search_radius_ was set
249  if (search_radius_ < 0)
250  {
251  PCL_ERROR ("[pcl::%s::computeFeature] A search radius needs to be set!\n", getClassName ().c_str ());
252  output.width = output.height = 0;
253  output.points.clear ();
254  return;
255  }
256 
257  // List of indices and corresponding squared distances for a neighborhood
258  // \note resize is irrelevant for a radiusSearch ().
259  std::vector<int> nn_indices;
260  std::vector<float> nn_sqr_dists;
261 
262  // Check if the full histogram has to be saved or not
263  if (save_histograms_)
264  {
265  // Reserve space for the output histogram dataset
266  histograms_.reset (new std::vector<Eigen::MatrixXf, Eigen::aligned_allocator<Eigen::MatrixXf> >);
267  histograms_->reserve (output.points.size ());
268 
269  // Iterating over the entire index vector
270  for (size_t idx = 0; idx < indices_->size (); ++idx)
271  {
272  // Compute and store r_min and r_max in the output cloud
273  this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_sqr_dists);
274  //histograms_->push_back (computeRSD (surface_, normals_, nn_indices, search_radius_, nr_subdiv_, plane_radius_, output.points[idx], true));
275  histograms_->push_back (computeRSD (normals_, nn_indices, nn_sqr_dists, search_radius_, nr_subdiv_, plane_radius_, output.points[idx], true));
276  }
277  }
278  else
279  {
280  // Iterating over the entire index vector
281  for (size_t idx = 0; idx < indices_->size (); ++idx)
282  {
283  // Compute and store r_min and r_max in the output cloud
284  this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_sqr_dists);
285  //computeRSD (surface_, normals_, nn_indices, search_radius_, nr_subdiv_, plane_radius_, output.points[idx], false);
286  computeRSD (normals_, nn_indices, nn_sqr_dists, search_radius_, nr_subdiv_, plane_radius_, output.points[idx], false);
287  }
288  }
289 }
290 
291 #define PCL_INSTANTIATE_RSDEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::RSDEstimation<T,NT,OutT>;
292 
293 #endif // PCL_FEATURES_IMPL_VFH_H_