Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
usc.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: usc.hpp 6144 2012-07-04 22:06:28Z rusu $
37  *
38  */
39 
40 #ifndef PCL_FEATURES_IMPL_USC_HPP_
41 #define PCL_FEATURES_IMPL_USC_HPP_
42 
43 #include <pcl/features/usc.h>
44 #include <pcl/features/shot_lrf.h>
45 #include <pcl/common/geometry.h>
46 #include <pcl/common/angles.h>
47 #include <pcl/common/utils.h>
48 
50 template <typename PointInT, typename PointOutT, typename PointRFT> bool
52 {
53  if (!Feature<PointInT, PointOutT>::initCompute ())
54  {
55  PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ());
56  return (false);
57  }
58 
59  // Default LRF estimation alg: SHOTLocalReferenceFrameEstimation
60  typename SHOTLocalReferenceFrameEstimation<PointInT, PointRFT>::Ptr lrf_estimator(new SHOTLocalReferenceFrameEstimation<PointInT, PointRFT>());
61  lrf_estimator->setRadiusSearch (local_radius_);
62  lrf_estimator->setInputCloud (input_);
63  lrf_estimator->setIndices (indices_);
64  if (!fake_surface_)
65  lrf_estimator->setSearchSurface(surface_);
66 
67  if (!FeatureWithLocalReferenceFrames<PointInT, PointRFT>::initLocalReferenceFrames (indices_->size (), lrf_estimator))
68  {
69  PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ());
70  return (false);
71  }
72 
73  if (search_radius_< min_radius_)
74  {
75  PCL_ERROR ("[pcl::%s::initCompute] search_radius_ must be GREATER than min_radius_.\n", getClassName ().c_str ());
76  return (false);
77  }
78 
79  // Update descriptor length
80  descriptor_length_ = elevation_bins_ * azimuth_bins_ * radius_bins_;
81 
82  // Compute radial, elevation and azimuth divisions
83  float azimuth_interval = 360.0f / static_cast<float> (azimuth_bins_);
84  float elevation_interval = 180.0f / static_cast<float> (elevation_bins_);
85 
86  // Reallocate divisions and volume lut
87  radii_interval_.clear ();
88  phi_divisions_.clear ();
89  theta_divisions_.clear ();
90  volume_lut_.clear ();
91 
92  // Fills radii interval based on formula (1) in section 2.1 of Frome's paper
93  radii_interval_.resize (radius_bins_ + 1);
94  for (size_t j = 0; j < radius_bins_ + 1; j++)
95  radii_interval_[j] = static_cast<float> (exp (log (min_radius_) + ((static_cast<float> (j) / static_cast<float> (radius_bins_)) * log (search_radius_/min_radius_))));
96 
97  // Fill theta didvisions of elevation
98  theta_divisions_.resize (elevation_bins_+1);
99  for (size_t k = 0; k < elevation_bins_+1; k++)
100  theta_divisions_[k] = static_cast<float> (k) * elevation_interval;
101 
102  // Fill phi didvisions of elevation
103  phi_divisions_.resize (azimuth_bins_+1);
104  for (size_t l = 0; l < azimuth_bins_+1; l++)
105  phi_divisions_[l] = static_cast<float> (l) * azimuth_interval;
106 
107  // LookUp Table that contains the volume of all the bins
108  // "phi" term of the volume integral
109  // "integr_phi" has always the same value so we compute it only one time
110  float integr_phi = pcl::deg2rad (phi_divisions_[1]) - pcl::deg2rad (phi_divisions_[0]);
111  // exponential to compute the cube root using pow
112  float e = 1.0f / 3.0f;
113  // Resize volume look up table
114  volume_lut_.resize (radius_bins_ * elevation_bins_ * azimuth_bins_);
115  // Fill volumes look up table
116  for (size_t j = 0; j < radius_bins_; j++)
117  {
118  // "r" term of the volume integral
119  float integr_r = (radii_interval_[j+1]*radii_interval_[j+1]*radii_interval_[j+1] / 3) - (radii_interval_[j]*radii_interval_[j]*radii_interval_[j]/ 3);
120 
121  for (size_t k = 0; k < elevation_bins_; k++)
122  {
123  // "theta" term of the volume integral
124  float integr_theta = cosf (deg2rad (theta_divisions_[k])) - cosf (deg2rad (theta_divisions_[k+1]));
125  // Volume
126  float V = integr_phi * integr_theta * integr_r;
127  // Compute cube root of the computed volume commented for performance but left
128  // here for clarity
129  // float cbrt = pow(V, e);
130  // cbrt = 1 / cbrt;
131 
132  for (size_t l = 0; l < azimuth_bins_; l++)
133  // Store in lut 1/cbrt
134  //volume_lut_[ (l*elevation_bins_*radius_bins_) + k*radius_bins_ + j ] = cbrt;
135  volume_lut_[(l*elevation_bins_*radius_bins_) + k*radius_bins_ + j] = 1.0f / powf (V, e);
136  }
137  }
138  return (true);
139 }
140 
142 template <typename PointInT, typename PointOutT, typename PointRFT> void
143 pcl::UniqueShapeContext<PointInT, PointOutT, PointRFT>::computePointDescriptor (size_t index, /*float rf[9],*/ std::vector<float> &desc)
144 {
145  pcl::Vector3fMapConst origin = input_->points[(*indices_)[index]].getVector3fMap ();
146 
147  const Eigen::Vector3f& x_axis = frames_->points[index].x_axis.getNormalVector3fMap ();
148  //const Eigen::Vector3f& y_axis = frames_->points[index].y_axis.getNormalVector3fMap ();
149  const Eigen::Vector3f& normal = frames_->points[index].z_axis.getNormalVector3fMap ();
150 
151  // Find every point within specified search_radius_
152  std::vector<int> nn_indices;
153  std::vector<float> nn_dists;
154  const size_t neighb_cnt = searchForNeighbors ((*indices_)[index], search_radius_, nn_indices, nn_dists);
155  // For each point within radius
156  for (size_t ne = 0; ne < neighb_cnt; ne++)
157  {
158  if (pcl::utils::equal(nn_dists[ne], 0.0f))
159  continue;
160  // Get neighbours coordinates
161  Eigen::Vector3f neighbour = surface_->points[nn_indices[ne]].getVector3fMap ();
162 
163  // ----- Compute current neighbour polar coordinates -----
164 
165  // Get distance between the neighbour and the origin
166  float r = sqrt (nn_dists[ne]);
167 
168  // Project point into the tangent plane
169  Eigen::Vector3f proj;
170  pcl::geometry::project (neighbour, origin, normal, proj);
171  proj -= origin;
172 
173  // Normalize to compute the dot product
174  proj.normalize ();
175 
176  // Compute the angle between the projection and the x axis in the interval [0,360]
177  Eigen::Vector3f cross = x_axis.cross (proj);
178  float phi = rad2deg (std::atan2 (cross.norm (), x_axis.dot (proj)));
179  phi = cross.dot (normal) < 0.f ? (360.0f - phi) : phi;
181  Eigen::Vector3f no = neighbour - origin;
182  no.normalize ();
183  float theta = normal.dot (no);
184  theta = pcl::rad2deg (acosf (std::min (1.0f, std::max (-1.0f, theta))));
185 
187  size_t j = 0;
188  size_t k = 0;
189  size_t l = 0;
190 
192  for (size_t rad = 1; rad < radius_bins_ + 1; rad++)
193  {
194  if (r <= radii_interval_[rad])
195  {
196  j = rad - 1;
197  break;
198  }
199  }
200 
201  for (size_t ang = 1; ang < elevation_bins_ + 1; ang++)
202  {
203  if (theta <= theta_divisions_[ang])
204  {
205  k = ang - 1;
206  break;
207  }
208  }
209 
210  for (size_t ang = 1; ang < azimuth_bins_ + 1; ang++)
211  {
212  if (phi <= phi_divisions_[ang])
213  {
214  l = ang - 1;
215  break;
216  }
217  }
218 
220  std::vector<int> neighbour_indices;
221  std::vector<float> neighbour_didtances;
222  float point_density = static_cast<float> (searchForNeighbors (*surface_, nn_indices[ne], point_density_radius_, neighbour_indices, neighbour_didtances));
224  float w = (1.0f / point_density) * volume_lut_[(l*elevation_bins_*radius_bins_) +
225  (k*radius_bins_) +
226  j];
227 
228  assert (w >= 0.0);
229  if (w == std::numeric_limits<float>::infinity ())
230  PCL_ERROR ("Shape Context Error INF!\n");
231  if (w != w)
232  PCL_ERROR ("Shape Context Error IND!\n");
234  desc[(l*elevation_bins_*radius_bins_) + (k*radius_bins_) + j] += w;
235 
236  assert (desc[(l*elevation_bins_*radius_bins_) + (k*radius_bins_) + j] >= 0);
237  } // end for each neighbour
238 }
239 
241 template <typename PointInT, typename PointOutT, typename PointRFT> void
243 {
244  for (size_t point_index = 0; point_index < indices_->size (); point_index++)
245  {
246  output[point_index].descriptor.resize (descriptor_length_);
247  for (int d = 0; d < 9; ++d)
248  output.points[point_index].rf[d] = frames_->points[point_index].rf[ (4*(d/3) + (d%3)) ];
249 
250  computePointDescriptor (point_index, output[point_index].descriptor);
251  }
252 }
253 
255 template <typename PointInT, typename PointRFT> void
257 {
258  output.points.resize (indices_->size (), descriptor_length_ + 9);
259 
260  for (size_t point_index = 0; point_index < indices_->size (); point_index++)
261  {
262  for (int d = 0; d < 9; ++d)
263  output.points (point_index, d) = frames_->points[point_index].rf[ (4*(d/3) + (d%3)) ];
264 
265  std::vector<float> descriptor (descriptor_length_);
266  computePointDescriptor (point_index, descriptor);
267  for (size_t j = 0; j < descriptor_length_; ++j)
268  output.points (point_index, 9 + j) = descriptor[j];
269  }
270 }
271 
272 #define PCL_INSTANTIATE_UniqueShapeContext(T,OutT,RFT) template class PCL_EXPORTS pcl::UniqueShapeContext<T,OutT,RFT>;
273 
274 #endif