Point Cloud Library (PCL)  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
voxel_grid.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * $Id: voxel_grid.hpp 3746 2011-12-31 22:19:47Z rusu $
00035  *
00036  */
00037 
00038 #ifndef PCL_FILTERS_IMPL_VOXEL_GRID_H_
00039 #define PCL_FILTERS_IMPL_VOXEL_GRID_H_
00040 
00041 #include "pcl/common/common.h"
00042 #include "pcl/filters/voxel_grid.h"
00043 
00045 template <typename PointT> void
00046 pcl::getMinMax3D (const typename pcl::PointCloud<PointT>::ConstPtr &cloud,
00047                   const std::string &distance_field_name, float min_distance, float max_distance,
00048                   Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, bool limit_negative)
00049 {
00050   Eigen::Array4f min_p, max_p;
00051   min_p.setConstant (FLT_MAX);
00052   max_p.setConstant (-FLT_MAX);
00053 
00054   // Get the fields list and the distance field index
00055   std::vector<sensor_msgs::PointField> fields;
00056   int distance_idx = pcl::getFieldIndex (*cloud, distance_field_name, fields);
00057 
00058   float distance_value;
00059   // If dense, no need to check for NaNs
00060   if (cloud->is_dense)
00061   {
00062     for (size_t i = 0; i < cloud->points.size (); ++i)
00063     {
00064       // Get the distance value
00065       uint8_t* pt_data = (uint8_t*)&cloud->points[i];
00066       memcpy (&distance_value, pt_data + fields[distance_idx].offset, sizeof (float));
00067 
00068       if (limit_negative)
00069       {
00070         // Use a threshold for cutting out points which inside the interval
00071         if ((distance_value < max_distance) && (distance_value > min_distance))
00072           continue;
00073       }
00074       else
00075       {
00076         // Use a threshold for cutting out points which are too close/far away
00077         if ((distance_value > max_distance) || (distance_value < min_distance))
00078           continue;
00079       }
00080       // Create the point structure and get the min/max
00081       pcl::Array4fMapConst pt = cloud->points[i].getArray4fMap ();
00082       min_p = min_p.min (pt);
00083       max_p = max_p.max (pt);
00084     }
00085   }
00086   else
00087   {
00088     for (size_t i = 0; i < cloud->points.size (); ++i)
00089     {
00090       // Get the distance value
00091       uint8_t* pt_data = (uint8_t*)&cloud->points[i];
00092       memcpy (&distance_value, pt_data + fields[distance_idx].offset, sizeof (float));
00093 
00094       if (limit_negative)
00095       {
00096         // Use a threshold for cutting out points which inside the interval
00097         if ((distance_value < max_distance) && (distance_value > min_distance))
00098           continue;
00099       }
00100       else
00101       {
00102         // Use a threshold for cutting out points which are too close/far away
00103         if ((distance_value > max_distance) || (distance_value < min_distance))
00104           continue;
00105       }
00106 
00107       // Check if the point is invalid
00108       if (!pcl_isfinite (cloud->points[i].x) || 
00109           !pcl_isfinite (cloud->points[i].y) || 
00110           !pcl_isfinite (cloud->points[i].z))
00111         continue;
00112       // Create the point structure and get the min/max
00113       pcl::Array4fMapConst pt = cloud->points[i].getArray4fMap ();
00114       min_p = min_p.min (pt);
00115       max_p = max_p.max (pt);
00116     }
00117   }
00118   min_pt = min_p;
00119   max_pt = max_p;
00120 }
00121 
00123 template <typename PointT> void
00124 pcl::VoxelGrid<PointT>::applyFilter (PointCloud &output)
00125 {
00126   // Has the input dataset been set already?
00127   if (!input_)
00128   {
00129     PCL_WARN ("[pcl::%s::applyFilter] No input dataset given!\n", getClassName ().c_str ());
00130     output.width = output.height = 0;
00131     output.points.clear ();
00132     return;
00133   }
00134 
00135   // Copy the header (and thus the frame_id) + allocate enough space for points
00136   output.height       = 1;                    // downsampling breaks the organized structure
00137   output.is_dense     = true;                 // we filter out invalid points
00138 
00139   Eigen::Vector4f min_p, max_p;
00140   // Get the minimum and maximum dimensions
00141   if (!filter_field_name_.empty ()) // If we don't want to process the entire cloud...
00142     getMinMax3D<PointT>(input_, filter_field_name_, filter_limit_min_, filter_limit_max_, min_p, max_p, filter_limit_negative_);
00143   else
00144     getMinMax3D<PointT>(*input_, min_p, max_p);
00145 
00146   // Compute the minimum and maximum bounding box values
00147 //  min_b_ = (min_p.array () * inverse_leaf_size_).template cast<int> ();
00148 //  max_b_ = (max_p.array () * inverse_leaf_size_).template cast<int> ();
00149   min_b_[0] = (int)(floor (min_p[0] * inverse_leaf_size_[0]));
00150   max_b_[0] = (int)(floor (max_p[0] * inverse_leaf_size_[0]));
00151   min_b_[1] = (int)(floor (min_p[1] * inverse_leaf_size_[1]));
00152   max_b_[1] = (int)(floor (max_p[1] * inverse_leaf_size_[1]));
00153   min_b_[2] = (int)(floor (min_p[2] * inverse_leaf_size_[2]));
00154   max_b_[2] = (int)(floor (max_p[2] * inverse_leaf_size_[2]));
00155 
00156   // Compute the number of divisions needed along all axis
00157   div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones ();
00158   div_b_[3] = 0;
00159 
00160   // Clear the leaves
00161   leaves_.clear ();
00162 
00163   // Set up the division multiplier
00164   divb_mul_ = Eigen::Vector4i (1, div_b_[0], div_b_[0] * div_b_[1], 0);
00165 
00166   int centroid_size = 4;
00167   if (downsample_all_data_)
00168     centroid_size = boost::mpl::size<FieldList>::value;
00169 
00170   // ---[ RGB special case
00171   std::vector<sensor_msgs::PointField> fields;
00172   int rgba_index = -1;
00173   rgba_index = pcl::getFieldIndex (*input_, "rgb", fields);
00174   if (rgba_index == -1)
00175     rgba_index = pcl::getFieldIndex (*input_, "rgba", fields);
00176   if (rgba_index >= 0)
00177   {
00178     rgba_index = fields[rgba_index].offset;
00179     centroid_size += 3;
00180   }
00181 
00182   // If we don't want to process the entire cloud, but rather filter points far away from the viewpoint first...
00183   if (!filter_field_name_.empty ())
00184   {
00185     // Get the distance field index
00186     std::vector<sensor_msgs::PointField> fields;
00187     int distance_idx = pcl::getFieldIndex (*input_, filter_field_name_, fields);
00188     if (distance_idx == -1)
00189       PCL_WARN ("[pcl::%s::applyFilter] Invalid filter field name. Index is %d.\n", getClassName ().c_str (), distance_idx);
00190 
00191     // First pass: go over all points and insert them into the right leaf
00192     for (size_t cp = 0; cp < input_->points.size (); ++cp)
00193     {
00194       if (!input_->is_dense)
00195         // Check if the point is invalid
00196         if (!pcl_isfinite (input_->points[cp].x) || 
00197             !pcl_isfinite (input_->points[cp].y) || 
00198             !pcl_isfinite (input_->points[cp].z))
00199           continue;
00200 
00201       // Get the distance value
00202       uint8_t* pt_data = (uint8_t*)&input_->points[cp];
00203       float distance_value = 0;
00204       memcpy (&distance_value, pt_data + fields[distance_idx].offset, sizeof (float));
00205 
00206       if (filter_limit_negative_)
00207       {
00208         // Use a threshold for cutting out points which inside the interval
00209         if ((distance_value < filter_limit_max_) && (distance_value > filter_limit_min_))
00210           continue;
00211       }
00212       else
00213       {
00214         // Use a threshold for cutting out points which are too close/far away
00215         if ((distance_value > filter_limit_max_) || (distance_value < filter_limit_min_))
00216           continue;
00217       }
00218 
00219       Eigen::Vector4i ijk = Eigen::Vector4i::Zero ();
00220       ijk[0] = (int)(floor (input_->points[cp].x * inverse_leaf_size_[0]));
00221       ijk[1] = (int)(floor (input_->points[cp].y * inverse_leaf_size_[1]));
00222       ijk[2] = (int)(floor (input_->points[cp].z * inverse_leaf_size_[2]));
00223 
00224       // Compute the centroid leaf index
00225       int idx = (ijk - min_b_).dot (divb_mul_);
00226 //      int idx = (((input_->points[cp].getArray4fMap () * inverse_leaf_size_).template cast<int> ()).matrix () - min_b_).dot (divb_mul_);
00227       Leaf& leaf = leaves_[idx];
00228       if (leaf.nr_points == 0)
00229       {
00230         leaf.centroid.resize (centroid_size);
00231         leaf.centroid.setZero ();
00232       }
00233 
00234       // Do we need to process all the fields?
00235       if (!downsample_all_data_)
00236       {
00237         Eigen::Vector4f pt (input_->points[cp].x, input_->points[cp].y, input_->points[cp].z, 0);
00238         leaf.centroid.template head<4> () += pt;
00239       }
00240       else
00241       {
00242         // Copy all the fields
00243         Eigen::VectorXf centroid = Eigen::VectorXf::Zero (centroid_size);
00244         // ---[ RGB special case
00245         if (rgba_index >= 0)
00246         {
00247           // fill r/g/b data
00248           pcl::RGB rgb;
00249           memcpy (&rgb, ((char *)&(input_->points[cp])) + rgba_index, sizeof (RGB));
00250           centroid[centroid_size-3] = rgb.r;
00251           centroid[centroid_size-2] = rgb.g;
00252           centroid[centroid_size-1] = rgb.b;
00253         }
00254         pcl::for_each_type <FieldList> (NdCopyPointEigenFunctor <PointT> (input_->points[cp], centroid));
00255         leaf.centroid += centroid;
00256       }
00257       ++leaf.nr_points;
00258     }
00259   }
00260   // No distance filtering, process all data
00261   else
00262   {
00263     // First pass: go over all points and insert them into the right leaf
00264     for (size_t cp = 0; cp < input_->points.size (); ++cp)
00265     {
00266       if (!input_->is_dense)
00267         // Check if the point is invalid
00268         if (!pcl_isfinite (input_->points[cp].x) || 
00269             !pcl_isfinite (input_->points[cp].y) || 
00270             !pcl_isfinite (input_->points[cp].z))
00271           continue;
00272 
00273       Eigen::Vector4i ijk = Eigen::Vector4i::Zero ();
00274       ijk[0] = (int)(floor (input_->points[cp].x * inverse_leaf_size_[0]));
00275       ijk[1] = (int)(floor (input_->points[cp].y * inverse_leaf_size_[1]));
00276       ijk[2] = (int)(floor (input_->points[cp].z * inverse_leaf_size_[2]));
00277 
00278       // Compute the centroid leaf index
00279       int idx = (ijk - min_b_).dot (divb_mul_);
00280       //int idx = (((input_->points[cp].getArray4fMap () * inverse_leaf_size_).template cast<int> ()).matrix () - min_b_).dot (divb_mul_);
00281       Leaf& leaf = leaves_[idx];
00282       if (leaf.nr_points == 0)
00283       {
00284         leaf.centroid.resize (centroid_size);
00285         leaf.centroid.setZero ();
00286       }
00287 
00288       // Do we need to process all the fields?
00289       if (!downsample_all_data_)
00290       {
00291         Eigen::Vector4f pt (input_->points[cp].x, input_->points[cp].y, input_->points[cp].z, 0);
00292         leaf.centroid.template head<4> () += pt;
00293       }
00294       else
00295       {
00296         // Copy all the fields
00297         Eigen::VectorXf centroid = Eigen::VectorXf::Zero (centroid_size);
00298         // ---[ RGB special case
00299         if (rgba_index >= 0)
00300         {
00301           // Fill r/g/b data, assuming that the order is BGRA
00302           pcl::RGB rgb;
00303           memcpy (&rgb, ((char *)&(input_->points[cp])) + rgba_index, sizeof (RGB));
00304           centroid[centroid_size-3] = rgb.r;
00305           centroid[centroid_size-2] = rgb.g;
00306           centroid[centroid_size-1] = rgb.b;
00307         }
00308         pcl::for_each_type <FieldList> (NdCopyPointEigenFunctor <PointT> (input_->points[cp], centroid));
00309         leaf.centroid += centroid;
00310       }
00311       ++leaf.nr_points;
00312     }
00313   }
00314 
00315   // Second pass: go over all leaves and compute centroids
00316   output.points.resize (leaves_.size ());
00317   int cp = 0, i = 0;
00318   if (save_leaf_layout_)
00319   {
00320     try
00321     {
00322       leaf_layout_.resize (div_b_[0]*div_b_[1]*div_b_[2], -1);
00323     }
00324     catch (std::bad_alloc&)
00325     {
00326       throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout", 
00327         "voxel_grid.hpp", "applyFilter"); 
00328     }
00329   }
00330   
00331   for (typename boost::unordered_map<size_t, Leaf>::const_iterator it = leaves_.begin (); it != leaves_.end (); ++it)
00332   {
00333     // Save leaf layout information for fast access to cells relative to current position
00334     if (save_leaf_layout_)
00335       leaf_layout_[it->first] = cp++;
00336 
00337     // Normalize the centroid
00338     const Leaf& leaf = it->second;
00339 
00340     // Normalize the centroid
00341     Eigen::VectorXf centroid = leaf.centroid / leaf.nr_points;
00342 
00343     // Do we need to process all the fields?
00344     if (!downsample_all_data_)
00345     {
00346       output.points[i].x = centroid[0];
00347       output.points[i].y = centroid[1];
00348       output.points[i].z = centroid[2];
00349     }
00350     else
00351     {
00352       pcl::for_each_type <FieldList> (pcl::NdCopyEigenPointFunctor <PointT> (centroid, output.points[i]));
00353       // ---[ RGB special case
00354       if (rgba_index >= 0)
00355       {
00356         // pack r/g/b into rgb
00357         float r = centroid[centroid_size-3], g = centroid[centroid_size-2], b = centroid[centroid_size-1];
00358         int rgb = ((int)r) << 16 | ((int)g) << 8 | ((int)b);
00359         memcpy (((char *)&output.points[i]) + rgba_index, &rgb, sizeof (float));
00360       }
00361     }
00362     i++;
00363   }
00364   output.width = output.points.size ();
00365 }
00366 
00367 #define PCL_INSTANTIATE_VoxelGrid(T) template class PCL_EXPORTS pcl::VoxelGrid<T>;
00368 #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);
00369 
00370 #endif    // PCL_FILTERS_IMPL_VOXEL_GRID_H_
00371 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines