00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
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
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
00129 if (leaf_size_[3] == 0)
00130 leaf_size_[3] = 1;
00131
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
00147 if (leaf_size_[3] == 0)
00148 leaf_size_[3] = 1;
00149
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
00250 if ((diff2min <= displacement.array()).all() && (diff2max >= displacement.array()).all())
00251 neighbors[ni] = leaf_layout_[((ijk + displacement - min_b_).dot(divb_mul_))];
00252 else
00253 neighbors[ni] = -1;
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
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
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
00389 output.height = 1;
00390 output.is_dense = true;
00391
00392 Eigen::Vector4f min_p, max_p;
00393 getMinMax3D<PointT>(*input_, *indices_, min_p, max_p);
00394
00395
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
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
00417 div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones();
00418 div_b_[3] = 0;
00419
00420
00421 divb_mul_ = Eigen::Vector4i(1, div_b_[0], div_b_[0] * div_b_[1], 0);
00422
00423
00424 std::vector<cloud_point_index_idx> index_vector;
00425 index_vector.reserve(indices_->size());
00426
00427
00428
00429
00430
00431 for (std::vector<int>::const_iterator it = indices_->begin(); it != indices_->end(); ++it)
00432 {
00433 if (!input_->is_dense)
00434
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
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
00453
00454 std::sort(index_vector.begin(), index_vector.end(), std::less<cloud_point_index_idx>());
00455
00456
00457
00458 unsigned int total = 0;
00459 unsigned int index = 0;
00460
00461
00462
00463 std::vector<std::pair<unsigned int, unsigned int>> first_and_last_indices_vector;
00464
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
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
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
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 }
00503
00504 #endif // BACKPORT_PCL_VOXEL_GRID
00505
00506 #endif // PCL18_BACKPORTS_VOXEL_GRID_H