Point Cloud Library (PCL)  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
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 Willow Garage, Inc. 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: voxel_grid.h 3746 2011-12-31 22:19:47Z rusu $
00037  *
00038  */
00039 
00040 #ifndef PCL_FILTERS_VOXEL_GRID_MAP_H_
00041 #define PCL_FILTERS_VOXEL_GRID_MAP_H_
00042 
00043 #include "pcl/filters/filter.h"
00044 #include <map>
00045 #include <boost/unordered_map.hpp>
00046 #include <boost/fusion/sequence/intrinsic/at_key.hpp>
00047 
00048 namespace pcl
00049 {
00058   PCL_EXPORTS void 
00059   getMinMax3D (const sensor_msgs::PointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx, 
00060                Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt);
00061 
00076   PCL_EXPORTS void 
00077   getMinMax3D (const sensor_msgs::PointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx, 
00078                const std::string &distance_field_name, float min_distance, float max_distance, 
00079                Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, bool limit_negative = false);
00080 
00085   inline Eigen::MatrixXi
00086   getHalfNeighborCellIndices ()
00087   {
00088     Eigen::MatrixXi relative_coordinates (3, 13);
00089     int idx = 0;
00090 
00091     // 0 - 8
00092     for (int i = -1; i < 2; i++) 
00093     {
00094       for (int j = -1; j < 2; j++) 
00095       {
00096         relative_coordinates (0, idx) = i;
00097         relative_coordinates (1, idx) = j;
00098         relative_coordinates (2, idx) = -1;
00099         idx++;
00100       }
00101     }
00102     // 9 - 11
00103     for (int i = -1; i < 2; i++) 
00104     {
00105       relative_coordinates (0, idx) = i;
00106       relative_coordinates (1, idx) = -1;
00107       relative_coordinates (2, idx) = 0;
00108       idx++;
00109     }
00110     // 12
00111     relative_coordinates (0, idx) = -1;
00112     relative_coordinates (1, idx) = 0;
00113     relative_coordinates (2, idx) = 0;
00114 
00115     return (relative_coordinates);
00116   }
00117 
00122   inline Eigen::MatrixXi
00123   getAllNeighborCellIndices ()
00124   {
00125     Eigen::MatrixXi relative_coordinates = getHalfNeighborCellIndices ();
00126     Eigen::MatrixXi relative_coordinates_all( 3, 26);
00127     relative_coordinates_all.block<3, 13> (0, 0) = relative_coordinates;
00128     relative_coordinates_all.block<3, 13> (0, 13) = -relative_coordinates;
00129     return (relative_coordinates_all);
00130   }
00131 
00143   template <typename PointT> void 
00144   getMinMax3D (const typename pcl::PointCloud<PointT>::ConstPtr &cloud, 
00145                const std::string &distance_field_name, float min_distance, float max_distance,
00146                Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, bool limit_negative = false);
00147 
00160   template <typename PointT>
00161   class VoxelGrid: public Filter<PointT>
00162   {
00163     using Filter<PointT>::filter_name_;
00164     using Filter<PointT>::getClassName;
00165     using Filter<PointT>::input_;
00166     using Filter<PointT>::indices_;
00167 
00168     typedef typename Filter<PointT>::PointCloud PointCloud;
00169     typedef typename PointCloud::Ptr PointCloudPtr;
00170     typedef typename PointCloud::ConstPtr PointCloudConstPtr;
00171 
00172     public:
00174       VoxelGrid () : 
00175         downsample_all_data_ (true), save_leaf_layout_ (false),
00176         filter_field_name_ (""), 
00177         filter_limit_min_ (-FLT_MAX), filter_limit_max_ (FLT_MAX),
00178         filter_limit_negative_ (false)
00179       {
00180         leaf_size_.setZero ();
00181         min_b_.setZero ();
00182         max_b_.setZero ();
00183         filter_name_ = "VoxelGrid";
00184       }
00185 
00187       virtual ~VoxelGrid ()
00188       {
00189         leaves_.clear();
00190       }
00191 
00195       inline void 
00196       setLeafSize (const Eigen::Vector4f &leaf_size) 
00197       { 
00198         leaf_size_ = leaf_size; 
00199         // Avoid division errors
00200         if (leaf_size_[3] == 0)
00201           leaf_size_[3] = 1;
00202         // Use multiplications instead of divisions
00203         inverse_leaf_size_ = Eigen::Array4f::Ones () / leaf_size_.array ();
00204       }
00205 
00211       inline void
00212       setLeafSize (float lx, float ly, float lz)
00213       {
00214         leaf_size_[0] = lx; leaf_size_[1] = ly; leaf_size_[2] = lz;
00215         // Avoid division errors
00216         if (leaf_size_[3] == 0)
00217           leaf_size_[3] = 1;
00218         // Use multiplications instead of divisions
00219         inverse_leaf_size_ = Eigen::Array4f::Ones () / leaf_size_.array ();
00220       }
00221 
00223       inline Eigen::Vector3f 
00224       getLeafSize () { return (leaf_size_.head<3> ()); }
00225 
00229       inline void 
00230       setDownsampleAllData (bool downsample) { downsample_all_data_ = downsample; }
00231 
00235       inline bool 
00236       getDownsampleAllData () { return (downsample_all_data_); }
00237 
00241       inline void 
00242       setSaveLeafLayout (bool save_leaf_layout) { save_leaf_layout_ = save_leaf_layout; }
00243 
00245       inline bool 
00246       getSaveLeafLayout () { return (save_leaf_layout_); }
00247 
00251       inline Eigen::Vector3i 
00252       getMinBoxCoordinates () { return (min_b_.head<3> ()); }
00253 
00257       inline Eigen::Vector3i 
00258       getMaxBoxCoordinates () { return (max_b_.head<3> ()); }
00259 
00263       inline Eigen::Vector3i 
00264       getNrDivisions () { return (div_b_.head<3> ()); }
00265 
00269       inline Eigen::Vector3i 
00270       getDivisionMultiplier () { return (divb_mul_.head<3> ()); }
00271 
00280       inline int 
00281       getCentroidIndex (const PointT &p)
00282       {
00283         return leaf_layout_.at ((Eigen::Vector4i (floor (p.x / leaf_size_[0]), floor (p.y / leaf_size_[1]), floor (p.z / leaf_size_[2]), 0) - min_b_).dot (divb_mul_));
00284       }
00285 
00292       inline std::vector<int> 
00293       getNeighborCentroidIndices (const PointT &reference_point, const Eigen::MatrixXi &relative_coordinates)
00294       {
00295         Eigen::Vector4i ijk (floor (reference_point.x / leaf_size_[0]), floor (reference_point.y / leaf_size_[1]), floor (reference_point.z / leaf_size_[2]), 0);
00296         Eigen::Array4i diff2min = min_b_ - ijk;
00297         Eigen::Array4i diff2max = max_b_ - ijk;
00298         std::vector<int> neighbors (relative_coordinates.cols());
00299         for (int ni = 0; ni < relative_coordinates.cols (); ni++)
00300         {
00301           Eigen::Vector4i displacement = (Eigen::Vector4i() << relative_coordinates.col(ni), 0).finished();
00302           // checking if the specified cell is in the grid
00303           if ((diff2min <= displacement.array()).all() && (diff2max >= displacement.array()).all())
00304             neighbors[ni] = leaf_layout_[((ijk + displacement - min_b_).dot (divb_mul_))]; // .at() can be omitted
00305           else
00306             neighbors[ni] = -1; // cell is out of bounds, consider it empty
00307         }
00308         return (neighbors);
00309       }
00310 
00314       inline std::vector<int> 
00315       getLeafLayout () { return (leaf_layout_); }
00316 
00322       inline Eigen::Vector3i 
00323       getGridCoordinates (float x, float y, float z) 
00324       { 
00325         return (Eigen::Vector3i (floor (x / leaf_size_[0]), floor (y / leaf_size_[1]), floor (z / leaf_size_[2]))); 
00326       }
00327 
00331       inline int 
00332       getCentroidIndexAt (const Eigen::Vector3i &ijk)
00333       {
00334         int idx = ((Eigen::Vector4i() << ijk, 0).finished() - min_b_).dot (divb_mul_);
00335         if (idx < 0 || idx >= (int)leaf_layout_.size ()) // this checks also if leaf_layout_.size () == 0 i.e. everything was computed as needed
00336         {
00337           //if (verbose)
00338           //  PCL_ERROR ("[pcl::%s::getCentroidIndexAt] Specified coordinate is outside grid bounds, or leaf layout is not saved, make sure to call setSaveLeafLayout(true) and filter(output) first!\n", getClassName ().c_str ());
00339           return (-1);
00340         }
00341         return (leaf_layout_[idx]);
00342       }
00343 
00348       inline void
00349       setFilterFieldName (const std::string &field_name)
00350       {
00351         filter_field_name_ = field_name;
00352       }
00353 
00355       inline std::string const
00356       getFilterFieldName ()
00357       {
00358         return (filter_field_name_);
00359       }
00360 
00365       inline void
00366       setFilterLimits (const double &limit_min, const double &limit_max)
00367       {
00368         filter_limit_min_ = limit_min;
00369         filter_limit_max_ = limit_max;
00370       }
00371 
00376       inline void
00377       getFilterLimits (double &limit_min, double &limit_max)
00378       {
00379         limit_min = filter_limit_min_;
00380         limit_max = filter_limit_max_;
00381       }
00382 
00387       inline void
00388       setFilterLimitsNegative (const bool limit_negative)
00389       {
00390         filter_limit_negative_ = limit_negative;
00391       }
00392 
00396       inline void
00397       getFilterLimitsNegative (bool &limit_negative)
00398       {
00399         limit_negative = filter_limit_negative_;
00400       }
00401 
00405       inline bool
00406       getFilterLimitsNegative ()
00407       {
00408         return (filter_limit_negative_);
00409       }
00410 
00411     protected:
00414       struct Leaf
00415       {
00416         Leaf () : nr_points(0) {}
00417         Eigen::VectorXf centroid;    // @todo we do not support FLOAT64 just yet due to memory issues. Need to fix this.
00418         int nr_points;
00419       };
00420 
00422       boost::unordered_map<size_t, Leaf> leaves_;
00423 
00425       Eigen::Vector4f leaf_size_;
00426 
00428       Eigen::Array4f inverse_leaf_size_;
00429 
00431       bool downsample_all_data_;
00432 
00434       bool save_leaf_layout_;
00435 
00437       std::vector<int> leaf_layout_;
00438 
00440       Eigen::Vector4i min_b_, max_b_, div_b_, divb_mul_;
00441 
00443       std::string filter_field_name_;
00444 
00446       double filter_limit_min_;
00447 
00449       double filter_limit_max_;
00450 
00452       bool filter_limit_negative_;
00453 
00454       typedef typename pcl::traits::fieldList<PointT>::type FieldList;
00455 
00459       void 
00460       applyFilter (PointCloud &output);
00461   };
00462 
00475   template <>
00476   class PCL_EXPORTS VoxelGrid<sensor_msgs::PointCloud2> : public Filter<sensor_msgs::PointCloud2>
00477   {
00478     using Filter<sensor_msgs::PointCloud2>::filter_name_;
00479     using Filter<sensor_msgs::PointCloud2>::getClassName;
00480 
00481     typedef sensor_msgs::PointCloud2 PointCloud2;
00482     typedef PointCloud2::Ptr PointCloud2Ptr;
00483     typedef PointCloud2::ConstPtr PointCloud2ConstPtr;
00484 
00485     public:
00487       VoxelGrid () : 
00488         downsample_all_data_ (true), save_leaf_layout_ (false),
00489         filter_field_name_ (""), filter_limit_min_ (-FLT_MAX), filter_limit_max_ (FLT_MAX),
00490         filter_limit_negative_ (false)
00491       {
00492         leaf_size_.setZero ();
00493         min_b_.setZero ();
00494         max_b_.setZero ();
00495         filter_name_ = "VoxelGrid";
00496       }
00497 
00499       virtual ~VoxelGrid ()
00500       {
00501         leaves_.clear ();
00502       }
00503 
00507       inline void 
00508       setLeafSize (const Eigen::Vector4f &leaf_size) 
00509       { 
00510         leaf_size_ = leaf_size; 
00511         // Avoid division errors
00512         if (leaf_size_[3] == 0)
00513           leaf_size_[3] = 1;
00514         // Use multiplications instead of divisions
00515         inverse_leaf_size_ = Eigen::Array4f::Ones () / leaf_size_.array ();
00516       }
00517 
00523       inline void
00524       setLeafSize (float lx, float ly, float lz)
00525       {
00526         leaf_size_[0] = lx; leaf_size_[1] = ly; leaf_size_[2] = lz;
00527         // Avoid division errors
00528         if (leaf_size_[3] == 0)
00529           leaf_size_[3] = 1;
00530         // Use multiplications instead of divisions
00531         inverse_leaf_size_ = Eigen::Array4f::Ones () / leaf_size_.array ();
00532       }
00533 
00535       inline Eigen::Vector3f 
00536       getLeafSize () { return (leaf_size_.head<3> ()); }
00537 
00541       inline void 
00542       setDownsampleAllData (bool downsample) { downsample_all_data_ = downsample; }
00543 
00547       inline bool 
00548       getDownsampleAllData () { return (downsample_all_data_); }
00549 
00553       inline void 
00554       setSaveLeafLayout (bool save_leaf_layout) { save_leaf_layout_ = save_leaf_layout; }
00555 
00557       inline bool 
00558       getSaveLeafLayout () { return (save_leaf_layout_); }
00559 
00563       inline Eigen::Vector3i 
00564       getMinBoxCoordinates () { return (min_b_.head<3> ()); }
00565 
00569       inline Eigen::Vector3i 
00570       getMaxBoxCoordinates () { return (max_b_.head<3> ()); }
00571 
00575       inline Eigen::Vector3i 
00576       getNrDivisions () { return (div_b_.head<3> ()); }
00577 
00581       inline Eigen::Vector3i 
00582       getDivisionMultiplier () { return (divb_mul_.head<3> ()); }
00583 
00591       inline int 
00592       getCentroidIndex (float x, float y, float z)
00593       {
00594         return (leaf_layout_.at ((Eigen::Vector4i ((int) floor (x / leaf_size_[0]), (int) floor (y / leaf_size_[1]), (int) floor (z / leaf_size_[2]), 0) - min_b_).dot (divb_mul_)));
00595       }
00596 
00605       inline std::vector<int> 
00606       getNeighborCentroidIndices (float x, float y, float z, const Eigen::MatrixXi &relative_coordinates)
00607       {
00608         Eigen::Vector4i ijk ((int) floor (x / leaf_size_[0]), (int) floor (y / leaf_size_[1]), (int) floor (z / leaf_size_[2]), 0);
00609         Eigen::Array4i diff2min = min_b_ - ijk;
00610         Eigen::Array4i diff2max = max_b_ - ijk;
00611         std::vector<int> neighbors (relative_coordinates.cols());
00612         for (int ni = 0; ni < relative_coordinates.cols (); ni++)
00613         {
00614           Eigen::Vector4i displacement = (Eigen::Vector4i() << relative_coordinates.col(ni), 0).finished();
00615           // checking if the specified cell is in the grid
00616           if ((diff2min <= displacement.array()).all() && (diff2max >= displacement.array()).all())
00617             neighbors[ni] = leaf_layout_[((ijk + displacement - min_b_).dot (divb_mul_))]; // .at() can be omitted
00618           else
00619             neighbors[ni] = -1; // cell is out of bounds, consider it empty
00620         }
00621         return (neighbors);
00622       }
00623       
00632       inline std::vector<int> 
00633       getNeighborCentroidIndices (float x, float y, float z, const std::vector<Eigen::Vector3i> &relative_coordinates)
00634       {
00635         Eigen::Vector4i ijk ((int) floor (x / leaf_size_[0]), (int) floor (y / leaf_size_[1]), (int) floor (z / leaf_size_[2]), 0);
00636         std::vector<int> neighbors;
00637         neighbors.reserve (relative_coordinates.size ());
00638         for (std::vector<Eigen::Vector3i>::const_iterator it = relative_coordinates.begin (); it != relative_coordinates.end (); it++)
00639           neighbors.push_back (leaf_layout_[(ijk + (Eigen::Vector4i() << *it, 0).finished() - min_b_).dot (divb_mul_)]);
00640         return (neighbors);
00641       }
00642 
00646       inline std::vector<int> 
00647       getLeafLayout () { return (leaf_layout_); }
00648 
00654        inline Eigen::Vector3i 
00655       getGridCoordinates (float x, float y, float z) 
00656       { 
00657         return (Eigen::Vector3i ((int) floor (x / leaf_size_[0]), (int) floor (y / leaf_size_[1]), (int) floor (z / leaf_size_[2]))); 
00658       }
00659 
00663       inline int 
00664       getCentroidIndexAt (const Eigen::Vector3i &ijk)
00665       {
00666         int idx = ((Eigen::Vector4i() << ijk, 0).finished() - min_b_).dot (divb_mul_);
00667         if (idx < 0 || idx >= (int)leaf_layout_.size ()) // this checks also if leaf_layout_.size () == 0 i.e. everything was computed as needed
00668         {
00669           //if (verbose)
00670           //  PCL_ERROR ("[pcl::%s::getCentroidIndexAt] Specified coordinate is outside grid bounds, or leaf layout is not saved, make sure to call setSaveLeafLayout(true) and filter(output) first!\n", getClassName ().c_str ());
00671           return (-1);
00672         }
00673         return (leaf_layout_[idx]);
00674       }
00675 
00680       inline void
00681       setFilterFieldName (const std::string &field_name)
00682       {
00683         filter_field_name_ = field_name;
00684       }
00685 
00687       inline std::string const
00688       getFilterFieldName ()
00689       {
00690         return (filter_field_name_);
00691       }
00692 
00697       inline void
00698       setFilterLimits (const double &limit_min, const double &limit_max)
00699       {
00700         filter_limit_min_ = limit_min;
00701         filter_limit_max_ = limit_max;
00702       }
00703 
00708       inline void
00709       getFilterLimits (double &limit_min, double &limit_max)
00710       {
00711         limit_min = filter_limit_min_;
00712         limit_max = filter_limit_max_;
00713       }
00714 
00719       inline void
00720       setFilterLimitsNegative (const bool limit_negative)
00721       {
00722         filter_limit_negative_ = limit_negative;
00723       }
00724 
00728       inline void
00729       getFilterLimitsNegative (bool &limit_negative)
00730       {
00731         limit_negative = filter_limit_negative_;
00732       }
00733 
00737       inline bool
00738       getFilterLimitsNegative ()
00739       {
00740         return (filter_limit_negative_);
00741       }
00742 
00743     protected:
00746       struct Leaf
00747       {
00748         Leaf () : nr_points(0) { }
00749         Eigen::VectorXf centroid;    // @todo we do not support FLOAT64 just yet due to memory issues. Need to fix this.
00750         int nr_points;
00751       };
00752 
00754       boost::unordered_map<size_t, Leaf> leaves_;
00755 
00757       Eigen::Vector4f leaf_size_;
00758 
00760       Eigen::Array4f inverse_leaf_size_;
00761 
00763       bool downsample_all_data_;
00764 
00768       bool save_leaf_layout_;
00769 
00773       std::vector<int> leaf_layout_;
00774 
00778       Eigen::Vector4i min_b_, max_b_, div_b_, divb_mul_;
00779 
00781       std::string filter_field_name_;
00782 
00784       double filter_limit_min_;
00785 
00787       double filter_limit_max_;
00788 
00790       bool filter_limit_negative_;
00791 
00795       void 
00796       applyFilter (PointCloud2 &output);
00797   };
00798 }
00799 
00800 #endif  //#ifndef PCL_FILTERS_VOXEL_GRID_MAP_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines