|
Point Cloud Library (PCL)
1.4.0
|
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
1.7.6.1