Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
voxel_grid.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: voxel_grid.hpp 6144 2012-07-04 22:06:28Z rusu $
35  *
36  */
37 
38 #ifndef PCL_FILTERS_IMPL_VOXEL_GRID_H_
39 #define PCL_FILTERS_IMPL_VOXEL_GRID_H_
40 
41 #include <pcl/common/common.h>
42 #include <pcl/filters/voxel_grid.h>
43 
45 template <typename PointT> void
47  const std::string &distance_field_name, float min_distance, float max_distance,
48  Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, bool limit_negative)
49 {
50  Eigen::Array4f min_p, max_p;
51  min_p.setConstant (FLT_MAX);
52  max_p.setConstant (-FLT_MAX);
53 
54  // Get the fields list and the distance field index
55  std::vector<sensor_msgs::PointField> fields;
56  int distance_idx = pcl::getFieldIndex (*cloud, distance_field_name, fields);
57 
58  float distance_value;
59  // If dense, no need to check for NaNs
60  if (cloud->is_dense)
61  {
62  for (size_t i = 0; i < cloud->points.size (); ++i)
63  {
64  // Get the distance value
65  const uint8_t* pt_data = reinterpret_cast<const uint8_t*> (&cloud->points[i]);
66  memcpy (&distance_value, pt_data + fields[distance_idx].offset, sizeof (float));
67 
68  if (limit_negative)
69  {
70  // Use a threshold for cutting out points which inside the interval
71  if ((distance_value < max_distance) && (distance_value > min_distance))
72  continue;
73  }
74  else
75  {
76  // Use a threshold for cutting out points which are too close/far away
77  if ((distance_value > max_distance) || (distance_value < min_distance))
78  continue;
79  }
80  // Create the point structure and get the min/max
81  pcl::Array4fMapConst pt = cloud->points[i].getArray4fMap ();
82  min_p = min_p.min (pt);
83  max_p = max_p.max (pt);
84  }
85  }
86  else
87  {
88  for (size_t i = 0; i < cloud->points.size (); ++i)
89  {
90  // Get the distance value
91  const uint8_t* pt_data = reinterpret_cast<const uint8_t*> (&cloud->points[i]);
92  memcpy (&distance_value, pt_data + fields[distance_idx].offset, sizeof (float));
93 
94  if (limit_negative)
95  {
96  // Use a threshold for cutting out points which inside the interval
97  if ((distance_value < max_distance) && (distance_value > min_distance))
98  continue;
99  }
100  else
101  {
102  // Use a threshold for cutting out points which are too close/far away
103  if ((distance_value > max_distance) || (distance_value < min_distance))
104  continue;
105  }
106 
107  // Check if the point is invalid
108  if (!pcl_isfinite (cloud->points[i].x) ||
109  !pcl_isfinite (cloud->points[i].y) ||
110  !pcl_isfinite (cloud->points[i].z))
111  continue;
112  // Create the point structure and get the min/max
113  pcl::Array4fMapConst pt = cloud->points[i].getArray4fMap ();
114  min_p = min_p.min (pt);
115  max_p = max_p.max (pt);
116  }
117  }
118  min_pt = min_p;
119  max_pt = max_p;
120 }
121 
123 {
124  unsigned int idx;
125  unsigned int cloud_point_index;
126 
127  cloud_point_index_idx (unsigned int idx_, unsigned int cloud_point_index_) : idx (idx_), cloud_point_index (cloud_point_index_) {}
128  bool operator < (const cloud_point_index_idx &p) const { return (idx < p.idx); }
129 };
130 
132 template <typename PointT> void
134 {
135  // Has the input dataset been set already?
136  if (!input_)
137  {
138  PCL_WARN ("[pcl::%s::applyFilter] No input dataset given!\n", getClassName ().c_str ());
139  output.width = output.height = 0;
140  output.points.clear ();
141  return;
142  }
143 
144  // Copy the header (and thus the frame_id) + allocate enough space for points
145  output.height = 1; // downsampling breaks the organized structure
146  output.is_dense = true; // we filter out invalid points
147 
148  Eigen::Vector4f min_p, max_p;
149  // Get the minimum and maximum dimensions
150  if (!filter_field_name_.empty ()) // If we don't want to process the entire cloud...
151  getMinMax3D<PointT>(input_, filter_field_name_, static_cast<float> (filter_limit_min_), static_cast<float> (filter_limit_max_), min_p, max_p, filter_limit_negative_);
152  else
153  getMinMax3D<PointT>(*input_, min_p, max_p);
154 
155  // Compute the minimum and maximum bounding box values
156  min_b_[0] = static_cast<int> (floor (min_p[0] * inverse_leaf_size_[0]));
157  max_b_[0] = static_cast<int> (floor (max_p[0] * inverse_leaf_size_[0]));
158  min_b_[1] = static_cast<int> (floor (min_p[1] * inverse_leaf_size_[1]));
159  max_b_[1] = static_cast<int> (floor (max_p[1] * inverse_leaf_size_[1]));
160  min_b_[2] = static_cast<int> (floor (min_p[2] * inverse_leaf_size_[2]));
161  max_b_[2] = static_cast<int> (floor (max_p[2] * inverse_leaf_size_[2]));
162 
163  // Compute the number of divisions needed along all axis
164  div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones ();
165  div_b_[3] = 0;
166 
167  // Set up the division multiplier
168  divb_mul_ = Eigen::Vector4i (1, div_b_[0], div_b_[0] * div_b_[1], 0);
169 
170  int centroid_size = 4;
171  if (downsample_all_data_)
172  centroid_size = boost::mpl::size<FieldList>::value;
173 
174  // ---[ RGB special case
175  std::vector<sensor_msgs::PointField> fields;
176  int rgba_index = -1;
177  rgba_index = pcl::getFieldIndex (*input_, "rgb", fields);
178  if (rgba_index == -1)
179  rgba_index = pcl::getFieldIndex (*input_, "rgba", fields);
180  if (rgba_index >= 0)
181  {
182  rgba_index = fields[rgba_index].offset;
183  centroid_size += 3;
184  }
185 
186  std::vector<cloud_point_index_idx> index_vector;
187  index_vector.reserve(input_->points.size());
188 
189  // If we don't want to process the entire cloud, but rather filter points far away from the viewpoint first...
190  if (!filter_field_name_.empty ())
191  {
192  // Get the distance field index
193  std::vector<sensor_msgs::PointField> fields;
194  int distance_idx = pcl::getFieldIndex (*input_, filter_field_name_, fields);
195  if (distance_idx == -1)
196  PCL_WARN ("[pcl::%s::applyFilter] Invalid filter field name. Index is %d.\n", getClassName ().c_str (), distance_idx);
197 
198  // First pass: go over all points and insert them into the index_vector vector
199  // with calculated idx. Points with the same idx value will contribute to the
200  // same point of resulting CloudPoint
201  for (unsigned int cp = 0; cp < static_cast<unsigned int> (input_->points.size ()); ++cp)
202  {
203  if (!input_->is_dense)
204  // Check if the point is invalid
205  if (!pcl_isfinite (input_->points[cp].x) ||
206  !pcl_isfinite (input_->points[cp].y) ||
207  !pcl_isfinite (input_->points[cp].z))
208  continue;
209 
210  // Get the distance value
211  const uint8_t* pt_data = reinterpret_cast<const uint8_t*> (&input_->points[cp]);
212  float distance_value = 0;
213  memcpy (&distance_value, pt_data + fields[distance_idx].offset, sizeof (float));
214 
215  if (filter_limit_negative_)
216  {
217  // Use a threshold for cutting out points which inside the interval
218  if ((distance_value < filter_limit_max_) && (distance_value > filter_limit_min_))
219  continue;
220  }
221  else
222  {
223  // Use a threshold for cutting out points which are too close/far away
224  if ((distance_value > filter_limit_max_) || (distance_value < filter_limit_min_))
225  continue;
226  }
227 
228  int ijk0 = static_cast<int> (floor (input_->points[cp].x * inverse_leaf_size_[0]) - min_b_[0]);
229  int ijk1 = static_cast<int> (floor (input_->points[cp].y * inverse_leaf_size_[1]) - min_b_[1]);
230  int ijk2 = static_cast<int> (floor (input_->points[cp].z * inverse_leaf_size_[2]) - min_b_[2]);
231 
232  // Compute the centroid leaf index
233  int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
234  index_vector.push_back (cloud_point_index_idx (static_cast<unsigned int> (idx), cp));
235  }
236  }
237  // No distance filtering, process all data
238  else
239  {
240  // First pass: go over all points and insert them into the index_vector vector
241  // with calculated idx. Points with the same idx value will contribute to the
242  // same point of resulting CloudPoint
243  for (unsigned int cp = 0; cp < static_cast<unsigned int> (input_->points.size ()); ++cp)
244  {
245  if (!input_->is_dense)
246  // Check if the point is invalid
247  if (!pcl_isfinite (input_->points[cp].x) ||
248  !pcl_isfinite (input_->points[cp].y) ||
249  !pcl_isfinite (input_->points[cp].z))
250  continue;
251 
252  int ijk0 = static_cast<int> (floor (input_->points[cp].x * inverse_leaf_size_[0]) - min_b_[0]);
253  int ijk1 = static_cast<int> (floor (input_->points[cp].y * inverse_leaf_size_[1]) - min_b_[1]);
254  int ijk2 = static_cast<int> (floor (input_->points[cp].z * inverse_leaf_size_[2]) - min_b_[2]);
255 
256  // Compute the centroid leaf index
257  int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
258  index_vector.push_back (cloud_point_index_idx (static_cast<unsigned int> (idx), cp));
259  }
260  }
261 
262  // Second pass: sort the index_vector vector using value representing target cell as index
263  // in effect all points belonging to the same output cell will be next to each other
264  std::sort (index_vector.begin (), index_vector.end (), std::less<cloud_point_index_idx> ());
265 
266  // Third pass: count output cells
267  // we need to skip all the same, adjacenent idx values
268  unsigned int total = 0;
269  unsigned int index = 0;
270  while (index < index_vector.size ())
271  {
272  unsigned int i = index + 1;
273  while (i < index_vector.size () && index_vector[i].idx == index_vector[index].idx)
274  ++i;
275  ++total;
276  index = i;
277  }
278 
279  // Fourth pass: compute centroids, insert them into their final position
280  output.points.resize (total);
281  if (save_leaf_layout_)
282  {
283  try
284  {
285  // Resizing won't reset old elements to -1. If leaf_layout_ has been used previously, it needs to be re-initialized to -1
286  uint32_t new_layout_size = div_b_[0]*div_b_[1]*div_b_[2];
287  //This is the number of elements that need to be re-initialized to -1
288  uint32_t reinit_size = std::min (static_cast<unsigned int> (new_layout_size), static_cast<unsigned int> (leaf_layout_.size()));
289  for (uint32_t i = 0; i < reinit_size; i++)
290  {
291  leaf_layout_[i] = -1;
292  }
293  leaf_layout_.resize (new_layout_size, -1);
294  }
295  catch (std::bad_alloc&)
296  {
297  throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout",
298  "voxel_grid.hpp", "applyFilter");
299  }
300  catch (std::length_error&)
301  {
302  throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout",
303  "voxel_grid.hpp", "applyFilter");
304  }
305  }
306 
307  index = 0;
308  Eigen::VectorXf centroid = Eigen::VectorXf::Zero (centroid_size);
309  Eigen::VectorXf temporary = Eigen::VectorXf::Zero (centroid_size);
310 
311  for (unsigned int cp = 0; cp < index_vector.size ();)
312  {
313  // calculate centroid - sum values from all input points, that have the same idx value in index_vector array
314  if (!downsample_all_data_)
315  {
316  centroid[0] = input_->points[index_vector[cp].cloud_point_index].x;
317  centroid[1] = input_->points[index_vector[cp].cloud_point_index].y;
318  centroid[2] = input_->points[index_vector[cp].cloud_point_index].z;
319  }
320  else
321  {
322  // ---[ RGB special case
323  if (rgba_index >= 0)
324  {
325  // Fill r/g/b data, assuming that the order is BGRA
326  pcl::RGB rgb;
327  memcpy (&rgb, reinterpret_cast<const char*> (&input_->points[index_vector[cp].cloud_point_index]) + rgba_index, sizeof (RGB));
328  centroid[centroid_size-3] = rgb.r;
329  centroid[centroid_size-2] = rgb.g;
330  centroid[centroid_size-1] = rgb.b;
331  }
332  pcl::for_each_type <FieldList> (NdCopyPointEigenFunctor <PointT> (input_->points[index_vector[cp].cloud_point_index], centroid));
333  }
334 
335  unsigned int i = cp + 1;
336  while (i < index_vector.size () && index_vector[i].idx == index_vector[cp].idx)
337  {
338  if (!downsample_all_data_)
339  {
340  centroid[0] += input_->points[index_vector[i].cloud_point_index].x;
341  centroid[1] += input_->points[index_vector[i].cloud_point_index].y;
342  centroid[2] += input_->points[index_vector[i].cloud_point_index].z;
343  }
344  else
345  {
346  // ---[ RGB special case
347  if (rgba_index >= 0)
348  {
349  // Fill r/g/b data, assuming that the order is BGRA
350  pcl::RGB rgb;
351  memcpy (&rgb, reinterpret_cast<const char*> (&input_->points[index_vector[i].cloud_point_index]) + rgba_index, sizeof (RGB));
352  temporary[centroid_size-3] = rgb.r;
353  temporary[centroid_size-2] = rgb.g;
354  temporary[centroid_size-1] = rgb.b;
355  }
356  pcl::for_each_type <FieldList> (NdCopyPointEigenFunctor <PointT> (input_->points[index_vector[i].cloud_point_index], temporary));
357  centroid += temporary;
358  }
359  ++i;
360  }
361 
362  // index is centroid final position in resulting PointCloud
363  if (save_leaf_layout_)
364  leaf_layout_[index_vector[cp].idx] = index;
365 
366  centroid /= static_cast<float> (i - cp);
367 
368  // store centroid
369  // Do we need to process all the fields?
370  if (!downsample_all_data_)
371  {
372  output.points[index].x = centroid[0];
373  output.points[index].y = centroid[1];
374  output.points[index].z = centroid[2];
375  }
376  else
377  {
378  pcl::for_each_type<FieldList> (pcl::NdCopyEigenPointFunctor <PointT> (centroid, output.points[index]));
379  // ---[ RGB special case
380  if (rgba_index >= 0)
381  {
382  // pack r/g/b into rgb
383  float r = centroid[centroid_size-3], g = centroid[centroid_size-2], b = centroid[centroid_size-1];
384  int rgb = (static_cast<int> (r) << 16) | (static_cast<int> (g) << 8) | static_cast<int> (b);
385  memcpy (reinterpret_cast<char*> (&output.points[index]) + rgba_index, &rgb, sizeof (float));
386  }
387  }
388  cp = i;
389  ++index;
390  }
391  output.width = static_cast<uint32_t> (output.points.size ());
392 }
393 
394 #define PCL_INSTANTIATE_VoxelGrid(T) template class PCL_EXPORTS pcl::VoxelGrid<T>;
395 #define PCL_INSTANTIATE_getMinMax3D(T) template PCL_EXPORTS void pcl::getMinMax3D<T> (const pcl::PointCloud<T>::ConstPtr &, const std::string &, float, float, Eigen::Vector4f &, Eigen::Vector4f &, bool);
396 
397 #endif // PCL_FILTERS_IMPL_VOXEL_GRID_H_
398