Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
intensity_spin.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: intensity_spin.hpp 5026 2012-03-12 02:51:44Z rusu $
37  *
38  */
39 
40 #ifndef PCL_FEATURES_IMPL_INTENSITY_SPIN_H_
41 #define PCL_FEATURES_IMPL_INTENSITY_SPIN_H_
42 
44 
46 template <typename PointInT, typename PointOutT> void
48  const PointCloudIn &cloud, float radius, float sigma,
49  int k,
50  const std::vector<int> &indices,
51  const std::vector<float> &squared_distances,
52  Eigen::MatrixXf &intensity_spin_image)
53 {
54  // Determine the number of bins to use based on the size of intensity_spin_image
55  int nr_distance_bins = static_cast<int> (intensity_spin_image.cols ());
56  int nr_intensity_bins = static_cast<int> (intensity_spin_image.rows ());
57 
58  // Find the min and max intensity values in the given neighborhood
59  float min_intensity = std::numeric_limits<float>::max ();
60  float max_intensity = std::numeric_limits<float>::min ();
61  for (int idx = 0; idx < k; ++idx)
62  {
63  min_intensity = (std::min) (min_intensity, cloud.points[indices[idx]].intensity);
64  max_intensity = (std::max) (max_intensity, cloud.points[indices[idx]].intensity);
65  }
66 
67  float constant = 1.0f / (2.0f * sigma_ * sigma_);
68  // Compute the intensity spin image
69  intensity_spin_image.setZero ();
70  for (int idx = 0; idx < k; ++idx)
71  {
72  // Normalize distance and intensity values to: 0.0 <= d,i < nr_distance_bins,nr_intensity_bins
73  const float eps = std::numeric_limits<float>::epsilon ();
74  float d = static_cast<float> (nr_distance_bins) * sqrtf (squared_distances[idx]) / (radius + eps);
75  float i = static_cast<float> (nr_intensity_bins) *
76  (cloud.points[indices[idx]].intensity - min_intensity) / (max_intensity - min_intensity + eps);
77 
78  if (sigma == 0)
79  {
80  // If sigma is zero, update the histogram with no smoothing kernel
81  int d_idx = static_cast<int> (d);
82  int i_idx = static_cast<int> (i);
83  intensity_spin_image (i_idx, d_idx) += 1;
84  }
85  else
86  {
87  // Compute the bin indices that need to be updated (+/- 3 standard deviations)
88  int d_idx_min = (std::max)(static_cast<int> (floor (d - 3*sigma)), 0);
89  int d_idx_max = (std::min)(static_cast<int> (ceil (d + 3*sigma)), nr_distance_bins - 1);
90  int i_idx_min = (std::max)(static_cast<int> (floor (i - 3*sigma)), 0);
91  int i_idx_max = (std::min)(static_cast<int> (ceil (i + 3*sigma)), nr_intensity_bins - 1);
92 
93  // Update the appropriate bins of the histogram
94  for (int i_idx = i_idx_min; i_idx <= i_idx_max; ++i_idx)
95  {
96  for (int d_idx = d_idx_min; d_idx <= d_idx_max; ++d_idx)
97  {
98  // Compute a "soft" update weight based on the distance between the point and the bin
99  float w = expf (-powf (d - static_cast<float> (d_idx), 2.0f) * constant - powf (i - static_cast<float> (i_idx), 2.0f) * constant);
100  intensity_spin_image (i_idx, d_idx) += w;
101  }
102  }
103  }
104  }
105 }
106 
108 template <typename PointInT, typename PointOutT> void
110 {
111  // Make sure a search radius is set
112  if (search_radius_ == 0.0)
113  {
114  PCL_ERROR ("[pcl::%s::computeFeature] The search radius must be set before computing the feature!\n",
115  getClassName ().c_str ());
116  output.width = output.height = 0;
117  output.points.clear ();
118  return;
119  }
120 
121  // Make sure the spin image has valid dimensions
122  if (nr_intensity_bins_ <= 0)
123  {
124  PCL_ERROR ("[pcl::%s::computeFeature] The number of intensity bins must be greater than zero!\n",
125  getClassName ().c_str ());
126  output.width = output.height = 0;
127  output.points.clear ();
128  return;
129  }
130  if (nr_distance_bins_ <= 0)
131  {
132  PCL_ERROR ("[pcl::%s::computeFeature] The number of distance bins must be greater than zero!\n",
133  getClassName ().c_str ());
134  output.width = output.height = 0;
135  output.points.clear ();
136  return;
137  }
138 
139  Eigen::MatrixXf intensity_spin_image (nr_intensity_bins_, nr_distance_bins_);
140  // Allocate enough space to hold the radiusSearch results
141  std::vector<int> nn_indices (surface_->points.size ());
142  std::vector<float> nn_dist_sqr (surface_->points.size ());
143 
144  output.is_dense = true;
145  // Iterating over the entire index vector
146  for (size_t idx = 0; idx < indices_->size (); ++idx)
147  {
148  // Find neighbors within the search radius
149  // TODO: do we want to use searchForNeigbors instead?
150  int k = tree_->radiusSearch ((*indices_)[idx], search_radius_, nn_indices, nn_dist_sqr);
151  if (k == 0)
152  {
153  for (int bin = 0; bin < nr_intensity_bins_ * nr_distance_bins_; ++bin)
154  output.points[idx].histogram[bin] = std::numeric_limits<float>::quiet_NaN ();
155  output.is_dense = false;
156  continue;
157  }
158 
159  // Compute the intensity spin image
160  computeIntensitySpinImage (*surface_, static_cast<float> (search_radius_), sigma_, k, nn_indices, nn_dist_sqr, intensity_spin_image);
161 
162  // Copy into the resultant cloud
163  int bin = 0;
164  for (int bin_j = 0; bin_j < intensity_spin_image.cols (); ++bin_j)
165  for (int bin_i = 0; bin_i < intensity_spin_image.rows (); ++bin_i)
166  output.points[idx].histogram[bin++] = intensity_spin_image (bin_i, bin_j);
167  }
168 }
169 
171 template <typename PointInT> void
173 {
174  // These should be moved into initCompute ()
175  {
176  // Make sure a search radius is set
177  if (search_radius_ == 0.0)
178  {
179  PCL_ERROR ("[pcl::%s::computeFeature] The search radius must be set before computing the feature!\n",
180  getClassName ().c_str ());
181  output.width = output.height = 0;
182  output.points.resize (0, 0);
183  return;
184  }
185 
186  // Make sure the spin image has valid dimensions
187  if (nr_intensity_bins_ <= 0)
188  {
189  PCL_ERROR ("[pcl::%s::computeFeature] The number of intensity bins must be greater than zero!\n",
190  getClassName ().c_str ());
191  output.width = output.height = 0;
192  output.points.resize (0, 0);
193  return;
194  }
195  if (nr_distance_bins_ <= 0)
196  {
197  PCL_ERROR ("[pcl::%s::computeFeature] The number of distance bins must be greater than zero!\n",
198  getClassName ().c_str ());
199  output.width = output.height = 0;
200  output.points.resize (0, 0);
201  return;
202  }
203  }
204 
205  output.points.resize (indices_->size (), nr_intensity_bins_ * nr_distance_bins_);
206  Eigen::MatrixXf intensity_spin_image (nr_intensity_bins_, nr_distance_bins_);
207  // Allocate enough space to hold the radiusSearch results
208  std::vector<int> nn_indices;
209  std::vector<float> nn_dist_sqr;
210 
211  output.is_dense = true;
212  // Iterating over the entire index vector
213  for (size_t idx = 0; idx < indices_->size (); ++idx)
214  {
215  // Find neighbors within the search radius
216  int k = tree_->radiusSearch ((*indices_)[idx], search_radius_, nn_indices, nn_dist_sqr);
217  if (k == 0)
218  {
219  output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ());
220  output.is_dense = false;
221  continue;
222  }
223 
224  // Compute the intensity spin image
225  this->computeIntensitySpinImage (*surface_, static_cast<float> (search_radius_), sigma_, k, nn_indices, nn_dist_sqr, intensity_spin_image);
226 
227  // Copy into the resultant cloud
228  int bin = 0;
229  for (int bin_j = 0; bin_j < intensity_spin_image.cols (); ++bin_j)
230  for (int bin_i = 0; bin_i < intensity_spin_image.rows (); ++bin_i)
231  output.points (idx, bin++) = intensity_spin_image (bin_i, bin_j);
232  }
233 }
234 
235 
236 #define PCL_INSTANTIATE_IntensitySpinEstimation(T,NT) template class PCL_EXPORTS pcl::IntensitySpinEstimation<T,NT>;
237 
238 #endif // PCL_FEATURES_IMPL_INTENSITY_SPIN_H_
239