voxel_grid.h
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of the copyright holder(s) nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  * $Id$
00037  *
00038  */
00039 
00040 #ifndef PCL18_BACKPORTS_VOXEL_GRID_H
00041 #define PCL18_BACKPORTS_VOXEL_GRID_H
00042 
00043 #ifndef BACKPORT_PCL_VOXEL_GRID
00044 
00045 #include <pcl/filters/voxel_grid.h>
00046 
00047 namespace pcl
00048 {
00049 template <typename PointT>
00050 using VoxelGrid18 = VoxelGrid<PointT>;
00051 }
00052 
00053 #else
00054 
00055 // System has old PCL; backport VoxelGrid from pcl-1.8
00056 
00057 #include <algorithm>
00058 #include <functional>
00059 #include <limits>
00060 #include <string>
00061 #include <utility>
00062 #include <vector>
00063 
00064 #include <pcl18_backports/centroid.h>
00065 #include <pcl/filters/boost.h>
00066 #include <pcl/filters/filter.h>
00067 
00068 namespace pcl
00069 {
00082 template <typename PointT>
00083 class VoxelGrid18 : public Filter<PointT>
00084 {
00085 protected:
00086   using Filter<PointT>::filter_name_;
00087   using Filter<PointT>::getClassName;
00088   using Filter<PointT>::input_;
00089   using Filter<PointT>::indices_;
00090 
00091   typedef typename Filter<PointT>::PointCloud PointCloud;
00092   typedef typename PointCloud::Ptr PointCloudPtr;
00093   typedef typename PointCloud::ConstPtr PointCloudConstPtr;
00094 
00095 public:
00096   typedef boost::shared_ptr<VoxelGrid18<PointT>> Ptr;
00097   typedef boost::shared_ptr<const VoxelGrid18<PointT>> ConstPtr;
00098 
00100   VoxelGrid18()
00101     : leaf_size_(Eigen::Vector4f::Zero())
00102     , inverse_leaf_size_(Eigen::Array4f::Zero())
00103     , leaf_layout_()
00104     , min_b_(Eigen::Vector4i::Zero())
00105     , max_b_(Eigen::Vector4i::Zero())
00106     , div_b_(Eigen::Vector4i::Zero())
00107     , divb_mul_(Eigen::Vector4i::Zero())
00108     , filter_limit_min_(-FLT_MAX)
00109     , filter_limit_max_(FLT_MAX)
00110     , filter_limit_negative_(false)
00111     , min_points_per_voxel_(0)
00112   {
00113     filter_name_ = "VoxelGrid";
00114   }
00115 
00117   virtual ~VoxelGrid18()
00118   {
00119   }
00120 
00124   inline void
00125   setLeafSize(const Eigen::Vector4f& leaf_size)
00126   {
00127     leaf_size_ = leaf_size;
00128     // Avoid division errors
00129     if (leaf_size_[3] == 0)
00130       leaf_size_[3] = 1;
00131     // Use multiplications instead of divisions
00132     inverse_leaf_size_ = Eigen::Array4f::Ones() / leaf_size_.array();
00133   }
00134 
00140   inline void
00141   setLeafSize(float lx, float ly, float lz)
00142   {
00143     leaf_size_[0] = lx;
00144     leaf_size_[1] = ly;
00145     leaf_size_[2] = lz;
00146     // Avoid division errors
00147     if (leaf_size_[3] == 0)
00148       leaf_size_[3] = 1;
00149     // Use multiplications instead of divisions
00150     inverse_leaf_size_ = Eigen::Array4f::Ones() / leaf_size_.array();
00151   }
00152 
00154   inline Eigen::Vector3f
00155   getLeafSize() const
00156   {
00157     return (leaf_size_.head<3>());
00158   }
00159 
00163   inline void
00164   setMinimumPointsNumberPerVoxel(unsigned int min_points_per_voxel)
00165   {
00166     min_points_per_voxel_ = min_points_per_voxel;
00167   }
00168 
00171   inline unsigned int
00172   getMinimumPointsNumberPerVoxel() const
00173   {
00174     return min_points_per_voxel_;
00175   }
00176 
00180   inline Eigen::Vector3i
00181   getMinBoxCoordinates() const
00182   {
00183     return (min_b_.head<3>());
00184   }
00185 
00189   inline Eigen::Vector3i
00190   getMaxBoxCoordinates() const
00191   {
00192     return (max_b_.head<3>());
00193   }
00194 
00198   inline Eigen::Vector3i
00199   getNrDivisions() const
00200   {
00201     return (div_b_.head<3>());
00202   }
00203 
00207   inline Eigen::Vector3i
00208   getDivisionMultiplier() const
00209   {
00210     return (divb_mul_.head<3>());
00211   }
00212 
00221   inline int
00222   getCentroidIndex(const PointT& p) const
00223   {
00224     return (leaf_layout_.at((Eigen::Vector4i(static_cast<int>(floor(p.x * inverse_leaf_size_[0])),
00225                                              static_cast<int>(floor(p.y * inverse_leaf_size_[1])),
00226                                              static_cast<int>(floor(p.z * inverse_leaf_size_[2])), 0) -
00227                              min_b_)
00228                                 .dot(divb_mul_)));
00229   }
00230 
00237   inline std::vector<int>
00238   getNeighborCentroidIndices(const PointT& reference_point, const Eigen::MatrixXi& relative_coordinates) const
00239   {
00240     Eigen::Vector4i ijk(static_cast<int>(floor(reference_point.x * inverse_leaf_size_[0])),
00241                         static_cast<int>(floor(reference_point.y * inverse_leaf_size_[1])),
00242                         static_cast<int>(floor(reference_point.z * inverse_leaf_size_[2])), 0);
00243     Eigen::Array4i diff2min = min_b_ - ijk;
00244     Eigen::Array4i diff2max = max_b_ - ijk;
00245     std::vector<int> neighbors(relative_coordinates.cols());
00246     for (int ni = 0; ni < relative_coordinates.cols(); ni++)
00247     {
00248       Eigen::Vector4i displacement = (Eigen::Vector4i() << relative_coordinates.col(ni), 0).finished();
00249       // checking if the specified cell is in the grid
00250       if ((diff2min <= displacement.array()).all() && (diff2max >= displacement.array()).all())
00251         neighbors[ni] = leaf_layout_[((ijk + displacement - min_b_).dot(divb_mul_))];  // .at() can be omitted
00252       else
00253         neighbors[ni] = -1;  // cell is out of bounds, consider it empty
00254     }
00255     return (neighbors);
00256   }
00257 
00261   inline std::vector<int>
00262   getLeafLayout() const
00263   {
00264     return (leaf_layout_);
00265   }
00266 
00272   inline Eigen::Vector3i
00273   getGridCoordinates(float x, float y, float z) const
00274   {
00275     return (Eigen::Vector3i(static_cast<int>(floor(x * inverse_leaf_size_[0])),
00276                             static_cast<int>(floor(y * inverse_leaf_size_[1])),
00277                             static_cast<int>(floor(z * inverse_leaf_size_[2]))));
00278   }
00279 
00283   inline int
00284   getCentroidIndexAt(const Eigen::Vector3i& ijk) const
00285   {
00286     int idx = ((Eigen::Vector4i() << ijk, 0).finished() - min_b_).dot(divb_mul_);
00287     if (idx < 0 || idx >= static_cast<int>(leaf_layout_.size()))
00288     // this checks also if leaf_layout_.size () == 0 i.e. everything was computed as needed
00289     {
00290       return (-1);
00291     }
00292     return (leaf_layout_[idx]);
00293   }
00294 
00299   inline void
00300   setFilterLimits(const double& limit_min, const double& limit_max)
00301   {
00302     filter_limit_min_ = limit_min;
00303     filter_limit_max_ = limit_max;
00304   }
00305 
00310   inline void
00311   getFilterLimits(double& limit_min, double& limit_max) const
00312   {
00313     limit_min = filter_limit_min_;
00314     limit_max = filter_limit_max_;
00315   }
00316 
00321   inline void
00322   setFilterLimitsNegative(const bool limit_negative)
00323   {
00324     filter_limit_negative_ = limit_negative;
00325   }
00326 
00330   inline void
00331   getFilterLimitsNegative(bool& limit_negative) const
00332   {
00333     limit_negative = filter_limit_negative_;
00334   }
00335 
00339   inline bool
00340   getFilterLimitsNegative() const
00341   {
00342     return (filter_limit_negative_);
00343   }
00344 
00345 protected:
00347   Eigen::Vector4f leaf_size_;
00348 
00350   Eigen::Array4f inverse_leaf_size_;
00351 
00353   std::vector<int> leaf_layout_;
00354 
00356   Eigen::Vector4i min_b_, max_b_, div_b_, divb_mul_;
00357 
00359   double filter_limit_min_;
00360 
00362   double filter_limit_max_;
00363 
00366   bool filter_limit_negative_;
00367 
00369   unsigned int min_points_per_voxel_;
00370 
00371   typedef typename pcl::traits::fieldList<PointT>::type FieldList;
00372 
00376   void
00377   applyFilter(PointCloud& output)
00378   {
00379     // Has the input dataset been set already?
00380     if (!input_)
00381     {
00382       PCL_WARN("[pcl::%s::applyFilter] No input dataset given!\n", getClassName().c_str());
00383       output.width = output.height = 0;
00384       output.points.clear();
00385       return;
00386     }
00387 
00388     // Copy the header (and thus the frame_id) + allocate enough space for points
00389     output.height = 1;       // downsampling breaks the organized structure
00390     output.is_dense = true;  // we filter out invalid points
00391 
00392     Eigen::Vector4f min_p, max_p;
00393     getMinMax3D<PointT>(*input_, *indices_, min_p, max_p);
00394 
00395     // Check that the leaf size is not too small, given the size of the data
00396     int64_t dx = static_cast<int64_t>((max_p[0] - min_p[0]) * inverse_leaf_size_[0]) + 1;
00397     int64_t dy = static_cast<int64_t>((max_p[1] - min_p[1]) * inverse_leaf_size_[1]) + 1;
00398     int64_t dz = static_cast<int64_t>((max_p[2] - min_p[2]) * inverse_leaf_size_[2]) + 1;
00399 
00400     if ((dx * dy * dz) > static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
00401     {
00402       PCL_WARN("[pcl::%s::applyFilter] Leaf size is too small for the input dataset. Integer indices would overflow.",
00403                getClassName().c_str());
00404       output = *input_;
00405       return;
00406     }
00407 
00408     // Compute the minimum and maximum bounding box values
00409     min_b_[0] = static_cast<int>(floor(min_p[0] * inverse_leaf_size_[0]));
00410     max_b_[0] = static_cast<int>(floor(max_p[0] * inverse_leaf_size_[0]));
00411     min_b_[1] = static_cast<int>(floor(min_p[1] * inverse_leaf_size_[1]));
00412     max_b_[1] = static_cast<int>(floor(max_p[1] * inverse_leaf_size_[1]));
00413     min_b_[2] = static_cast<int>(floor(min_p[2] * inverse_leaf_size_[2]));
00414     max_b_[2] = static_cast<int>(floor(max_p[2] * inverse_leaf_size_[2]));
00415 
00416     // Compute the number of divisions needed along all axis
00417     div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones();
00418     div_b_[3] = 0;
00419 
00420     // Set up the division multiplier
00421     divb_mul_ = Eigen::Vector4i(1, div_b_[0], div_b_[0] * div_b_[1], 0);
00422 
00423     // Storage for mapping leaf and pointcloud indexes
00424     std::vector<cloud_point_index_idx> index_vector;
00425     index_vector.reserve(indices_->size());
00426 
00427     // No distance filtering, process all data
00428     // First pass: go over all points and insert them into the index_vector vector
00429     // with calculated idx. Points with the same idx value will contribute to the
00430     // same point of resulting CloudPoint
00431     for (std::vector<int>::const_iterator it = indices_->begin(); it != indices_->end(); ++it)
00432     {
00433       if (!input_->is_dense)
00434         // Check if the point is invalid
00435         if (!pcl_isfinite(input_->points[*it].x) ||
00436             !pcl_isfinite(input_->points[*it].y) ||
00437             !pcl_isfinite(input_->points[*it].z))
00438           continue;
00439 
00440       int ijk0 = static_cast<int>(
00441           floor(input_->points[*it].x * inverse_leaf_size_[0]) - static_cast<float>(min_b_[0]));
00442       int ijk1 = static_cast<int>(
00443           floor(input_->points[*it].y * inverse_leaf_size_[1]) - static_cast<float>(min_b_[1]));
00444       int ijk2 = static_cast<int>(
00445           floor(input_->points[*it].z * inverse_leaf_size_[2]) - static_cast<float>(min_b_[2]));
00446 
00447       // Compute the centroid leaf index
00448       int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
00449       index_vector.push_back(cloud_point_index_idx(static_cast<unsigned int>(idx), *it));
00450     }
00451 
00452     // Second pass: sort the index_vector vector using value representing target cell as index
00453     // in effect all points belonging to the same output cell will be next to each other
00454     std::sort(index_vector.begin(), index_vector.end(), std::less<cloud_point_index_idx>());
00455 
00456     // Third pass: count output cells
00457     // we need to skip all the same, adjacent idx values
00458     unsigned int total = 0;
00459     unsigned int index = 0;
00460     // first_and_last_indices_vector[i] represents the index in index_vector of the first point in
00461     // index_vector belonging to the voxel which corresponds to the i-th output point,
00462     // and of the first point not belonging to.
00463     std::vector<std::pair<unsigned int, unsigned int>> first_and_last_indices_vector;
00464     // Worst case size
00465     first_and_last_indices_vector.reserve(index_vector.size());
00466     while (index < index_vector.size())
00467     {
00468       unsigned int i = index + 1;
00469       while (i < index_vector.size() && index_vector[i].idx == index_vector[index].idx)
00470         ++i;
00471       if (i - index >= min_points_per_voxel_)
00472       {
00473         ++total;
00474         first_and_last_indices_vector.push_back(std::pair<unsigned int, unsigned int>(index, i));
00475       }
00476       index = i;
00477     }
00478 
00479     // Fourth pass: compute centroids, insert them into their final position
00480     output.points.resize(total);
00481 
00482     index = 0;
00483     for (unsigned int cp = 0; cp < first_and_last_indices_vector.size(); ++cp)
00484     {
00485       // calculate centroid - sum values from all input points, that have the same idx value in index_vector array
00486       unsigned int first_index = first_and_last_indices_vector[cp].first;
00487       unsigned int last_index = first_and_last_indices_vector[cp].second;
00488 
00489       CentroidPoint<PointT> centroid;
00490 
00491       // fill in the accumulator with leaf points
00492       for (unsigned int li = first_index; li < last_index; ++li)
00493         centroid.add(input_->points[index_vector[li].cloud_point_index]);
00494 
00495       centroid.get(output.points[index]);
00496 
00497       ++index;
00498     }
00499     output.width = static_cast<uint32_t>(output.points.size());
00500   }
00501 };
00502 }  // namespace pcl
00503 
00504 #endif  // BACKPORT_PCL_VOXEL_GRID
00505 
00506 #endif  // PCL18_BACKPORTS_VOXEL_GRID_H


mcl_3dl
Author(s): Atsushi Watanabe
autogenerated on Thu Jun 20 2019 20:04:43