78 using pcl::VoxelGrid<PointT>::filter_name_;
79 using pcl::VoxelGrid<PointT>::getClassName;
80 using pcl::VoxelGrid<PointT>::input_;
81 using pcl::VoxelGrid<PointT>::indices_;
82 using pcl::VoxelGrid<PointT>::filter_limit_negative_;
83 using pcl::VoxelGrid<PointT>::filter_limit_min_;
84 using pcl::VoxelGrid<PointT>::filter_limit_max_;
85 using pcl::VoxelGrid<PointT>::filter_field_name_;
87 using pcl::VoxelGrid<PointT>::downsample_all_data_;
88 using pcl::VoxelGrid<PointT>::leaf_layout_;
89 using pcl::VoxelGrid<PointT>::save_leaf_layout_;
90 using pcl::VoxelGrid<PointT>::leaf_size_;
91 using pcl::VoxelGrid<PointT>::min_b_;
92 using pcl::VoxelGrid<PointT>::max_b_;
93 using pcl::VoxelGrid<PointT>::inverse_leaf_size_;
94 using pcl::VoxelGrid<PointT>::div_b_;
95 using pcl::VoxelGrid<PointT>::divb_mul_;
97 typedef typename pcl::traits::fieldList<PointT>::type
FieldList;
103 typedef boost::shared_ptr<pcl::VoxelGrid<PointT>>
Ptr;
104 typedef boost::shared_ptr<const pcl::VoxelGrid<PointT>>
ConstPtr;
107 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
112 cov_(Eigen::Matrix3d::Identity()),
113 icov_(Eigen::Matrix3d::Zero()),
114 evecs_(Eigen::Matrix3d::Identity()),
167 min_points_per_voxel_(6),
168 min_covar_eigvalue_mult_(0.01),
171 voxel_centroidsleaf_indices_(),
173 downsample_all_data_ =
false;
174 save_leaf_layout_ =
false;
175 leaf_size_.setZero();
178 filter_name_ =
"VoxelGridCovariance";
183 if (min_points_per_voxel > 2) {
184 min_points_per_voxel_ = min_points_per_voxel;
186 PCL_WARN(
"%s, Covariance need 3 pts, set min_pt_per_vexel to 3",
187 this->getClassName().c_str());
188 min_points_per_voxel_ = 3;
197 min_covar_eigvalue_mult_ = min_covar_eigvalue_mult;
201 return min_covar_eigvalue_mult_;
206 searchable_ = searchable;
209 if (searchable_ && voxel_centroids_->size() > 0) {
210 kdtree_.setInputCloud(voxel_centroids_);
215 inline void Filter(
bool searchable =
false) {
216 searchable_ = searchable;
218 ApplyFilter(voxel_centroids_);
219 if (searchable_ && voxel_centroids_->size() > 0) {
220 kdtree_.setInputCloud(voxel_centroids_);
226 typename std::map<size_t, Leaf>::iterator leaf_iter = leaves_.find(index);
227 if (leaf_iter != leaves_.end()) {
238 int ijk0 =
static_cast<int>(floor(p.x * inverse_leaf_size_[0]) - min_b_[0]);
239 int ijk1 =
static_cast<int>(floor(p.y * inverse_leaf_size_[1]) - min_b_[1]);
240 int ijk2 =
static_cast<int>(floor(p.z * inverse_leaf_size_[2]) - min_b_[2]);
243 int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
246 typename std::map<size_t, Leaf>::iterator leaf_iter = leaves_.find(idx);
247 if (leaf_iter != leaves_.end()) {
260 static_cast<int>(floor(p[0] * inverse_leaf_size_[0]) - min_b_[0]);
262 static_cast<int>(floor(p[1] * inverse_leaf_size_[1]) - min_b_[1]);
264 static_cast<int>(floor(p[2] * inverse_leaf_size_[2]) - min_b_[2]);
267 int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
270 typename std::map<size_t, Leaf>::iterator leaf_iter = leaves_.find(idx);
271 if (leaf_iter != leaves_.end()) {
281 inline std::map<size_t, Leaf>&
GetLeaves() {
return leaves_; }
286 voxel_centroidsleaf_indices_.clear();
290 PCL_WARN(
"[%s::ApplyFilter] No input dataset given!\n",
291 getClassName().c_str());
292 output->width = output->height = 0;
293 output->points.clear();
298 output->is_dense =
true;
299 output->points.clear();
301 Eigen::Vector4f min_p, max_p;
303 if (!filter_field_name_.empty()) {
304 pcl::getMinMax3D<PointT>(input_, filter_field_name_,
305 static_cast<float>(filter_limit_min_),
306 static_cast<float>(filter_limit_max_), min_p,
307 max_p, filter_limit_negative_);
309 pcl::getMinMax3D<PointT>(*input_, min_p, max_p);
313 static_cast<int64_t
>((max_p[0] - min_p[0]) * inverse_leaf_size_[0]) + 1;
315 static_cast<int64_t
>((max_p[1] - min_p[1]) * inverse_leaf_size_[1]) + 1;
317 static_cast<int64_t
>((max_p[2] - min_p[2]) * inverse_leaf_size_[2]) + 1;
319 if ((dx * dy * dz) > std::numeric_limits<int32_t>::max()) {
321 "[%s::ApplyFilter] leaf size is too small. Integer indices would "
323 getClassName().c_str());
328 min_b_[0] =
static_cast<int>(floor(min_p[0] * inverse_leaf_size_[0]));
329 max_b_[0] =
static_cast<int>(floor(max_p[0] * inverse_leaf_size_[0]));
330 min_b_[1] =
static_cast<int>(floor(min_p[1] * inverse_leaf_size_[1]));
331 max_b_[1] =
static_cast<int>(floor(max_p[1] * inverse_leaf_size_[1]));
332 min_b_[2] =
static_cast<int>(floor(min_p[2] * inverse_leaf_size_[2]));
333 max_b_[2] =
static_cast<int>(floor(max_p[2] * inverse_leaf_size_[2]));
336 div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones();
341 divb_mul_ = Eigen::Vector4i(1, div_b_[0], div_b_[0] * div_b_[1], 0);
342 int centroid_size = 4;
343 if (downsample_all_data_) {
344 centroid_size = boost::mpl::size<FieldList>::value;
347 std::vector<pcl::PCLPointField> fields;
349 rgba_index = pcl::getFieldIndex(*input_,
"rgb", fields);
350 if (rgba_index == -1) {
351 rgba_index = pcl::getFieldIndex(*input_,
"rgba", fields);
353 if (rgba_index >= 0) {
354 rgba_index = fields[rgba_index].offset;
359 if (!filter_field_name_.empty()) {
361 std::vector<pcl::PCLPointField> fields;
363 pcl::getFieldIndex(*input_, filter_field_name_, fields);
364 if (distance_idx == -1) {
366 "[pcl::%s::ApplyFilter] Invalid filter field name. Index is %d.\n",
367 getClassName().c_str(), distance_idx);
371 for (
size_t cp = 0; cp < input_->points.size(); ++cp) {
372 if (!input_->is_dense) {
374 if (!std::isfinite(input_->points[cp].x) ||
375 !std::isfinite(input_->points[cp].y) ||
376 !std::isfinite(input_->points[cp].z)) {
381 const uint8_t* pt_data =
382 reinterpret_cast<const uint8_t*
>(&input_->points[cp]);
383 float distance_value = 0.0f;
384 memcpy(&distance_value, pt_data + fields[distance_idx].offset,
387 if (filter_limit_negative_) {
389 if ((distance_value < filter_limit_max_) &&
390 (distance_value > filter_limit_min_)) {
395 if ((distance_value > filter_limit_max_) ||
396 (distance_value < filter_limit_min_)) {
401 int ijk0 =
static_cast<int>(
402 floor(input_->points[cp].x * inverse_leaf_size_[0]) -
403 static_cast<float>(min_b_[0]));
404 int ijk1 =
static_cast<int>(
405 floor(input_->points[cp].y * inverse_leaf_size_[1]) -
406 static_cast<float>(min_b_[1]));
407 int ijk2 =
static_cast<int>(
408 floor(input_->points[cp].z * inverse_leaf_size_[2]) -
409 static_cast<float>(min_b_[2]));
412 ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
414 Leaf& leaf = leaves_[idx];
415 if (leaf.nr_points_ == 0) {
416 leaf.centroid.resize(centroid_size);
417 leaf.centroid.setZero();
421 leaf.cloud_.points.push_back(input_->points[cp]);
423 Eigen::Vector3d pt3d(input_->points[cp].x, input_->points[cp].y,
424 input_->points[cp].z);
428 leaf.cov_ += pt3d * pt3d.transpose();
431 if (!downsample_all_data_) {
432 Eigen::Vector4f pt(input_->points[cp].x, input_->points[cp].y,
433 input_->points[cp].z, 0);
434 leaf.centroid.template head<4>() += pt;
437 Eigen::VectorXf centroid = Eigen::VectorXf::Zero(centroid_size);
438 pcl::for_each_type<FieldList>(pcl::NdCopyPointEigenFunctor<PointT>(
439 input_->points[cp], centroid));
441 if (rgba_index >= 0) {
443 const pcl::RGB& rgb = *
reinterpret_cast<const pcl::RGB*
>(
444 reinterpret_cast<const char*
>(&input_->points[cp]) +
446 centroid[centroid_size - 4] = rgb.a;
447 centroid[centroid_size - 3] = rgb.r;
448 centroid[centroid_size - 2] = rgb.g;
449 centroid[centroid_size - 1] = rgb.b;
451 leaf.centroid += centroid;
457 for (
size_t cp = 0; cp < input_->points.size(); ++cp) {
458 if (!input_->is_dense) {
460 if (!std::isfinite(input_->points[cp].x) ||
461 !std::isfinite(input_->points[cp].y) ||
462 !std::isfinite(input_->points[cp].z)) {
466 int ijk0 =
static_cast<int>(
467 floor(input_->points[cp].x * inverse_leaf_size_[0]) -
468 static_cast<float>(min_b_[0]));
469 int ijk1 =
static_cast<int>(
470 floor(input_->points[cp].y * inverse_leaf_size_[1]) -
471 static_cast<float>(min_b_[1]));
472 int ijk2 =
static_cast<int>(
473 floor(input_->points[cp].z * inverse_leaf_size_[2]) -
474 static_cast<float>(min_b_[2]));
478 ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
484 Leaf& leaf = leaves_[idx];
485 if (leaf.nr_points_ == 0) {
486 leaf.centroid.resize(centroid_size);
487 leaf.centroid.setZero();
491 leaf.cloud_.points.push_back(input_->points[cp]);
493 Eigen::Vector3d pt3d(input_->points[cp].x, input_->points[cp].y,
494 input_->points[cp].z);
498 leaf.cov_ += pt3d * pt3d.transpose();
501 if (!downsample_all_data_) {
502 Eigen::Vector4f pt(input_->points[cp].x, input_->points[cp].y,
503 input_->points[cp].z, 0);
504 leaf.centroid.template head<4>() += pt;
507 Eigen::VectorXf centroid = Eigen::VectorXf::Zero(centroid_size);
508 pcl::for_each_type<FieldList>(pcl::NdCopyPointEigenFunctor<PointT>(
509 input_->points[cp], centroid));
511 if (rgba_index >= 0) {
513 const pcl::RGB& rgb = *
reinterpret_cast<const pcl::RGB*
>(
514 reinterpret_cast<const char*
>(&input_->points[cp]) +
516 centroid[centroid_size - 4] = rgb.a;
517 centroid[centroid_size - 3] = rgb.r;
518 centroid[centroid_size - 2] = rgb.g;
519 centroid[centroid_size - 1] = rgb.b;
521 leaf.centroid += centroid;
528 output->points.reserve(leaves_.size());
530 voxel_centroidsleaf_indices_.reserve(leaves_.size());
533 if (save_leaf_layout_) {
534 leaf_layout_.resize(div_b_[0] * div_b_[1] * div_b_[2], -1);
537 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver;
538 Eigen::Matrix3d eigen_val;
539 Eigen::Vector3d pt_sum;
543 double min_covar_eigvalue;
545 for (
typename std::map<size_t, Leaf>::iterator it = leaves_.begin();
546 it != leaves_.end(); ++it) {
548 Leaf& leaf = it->second;
551 leaf.centroid /=
static_cast<float>(leaf.nr_points_);
555 leaf.mean_ /= leaf.nr_points_;
557 if (leaf.nr_points_ >= min_points_per_voxel_) {
558 if (save_leaf_layout_) {
559 leaf_layout_[it->first] = cp++;
561 output->push_back(
PointT());
563 if (!downsample_all_data_) {
564 output->points.back().x = leaf.centroid[0];
565 output->points.back().y = leaf.centroid[1];
566 output->points.back().z = leaf.centroid[2];
568 pcl::for_each_type<FieldList>(pcl::NdCopyEigenPointFunctor<PointT>(
569 leaf.centroid, output->back()));
571 if (rgba_index >= 0) {
572 pcl::RGB& rgb = *
reinterpret_cast<pcl::RGB*
>(
573 reinterpret_cast<char*
>(&output->points.back()) + rgba_index);
574 rgb.a =
static_cast<uint8_t
>(leaf.centroid[centroid_size - 4]);
575 rgb.r =
static_cast<uint8_t
>(leaf.centroid[centroid_size - 3]);
576 rgb.g =
static_cast<uint8_t
>(leaf.centroid[centroid_size - 2]);
577 rgb.b =
static_cast<uint8_t
>(leaf.centroid[centroid_size - 1]);
583 voxel_centroidsleaf_indices_.push_back(
static_cast<int>(it->first));
587 leaf.cov_ = (leaf.cov_ - 2 * (pt_sum * leaf.mean_.transpose())) /
589 leaf.mean_ * leaf.mean_.transpose();
590 leaf.cov_ *= (leaf.nr_points_ - 1.0) / leaf.nr_points_;
593 eigensolver.compute(leaf.cov_);
594 eigen_val = eigensolver.eigenvalues().asDiagonal();
595 leaf.evecs_ = eigensolver.eigenvectors();
597 if (eigen_val(0, 0) < 0 || eigen_val(1, 1) < 0 ||
598 eigen_val(2, 2) <= 0) {
599 leaf.nr_points_ = -1;
604 min_covar_eigvalue = min_covar_eigvalue_mult_ * eigen_val(2, 2);
605 if (eigen_val(0, 0) < min_covar_eigvalue) {
606 eigen_val(0, 0) = min_covar_eigvalue;
607 if (eigen_val(1, 1) < min_covar_eigvalue) {
608 eigen_val(1, 1) = min_covar_eigvalue;
610 leaf.cov_ = leaf.evecs_ * eigen_val * leaf.evecs_.inverse();
612 leaf.evals_ = eigen_val.diagonal();
614 leaf.icov_ = leaf.cov_.inverse();
615 if (leaf.icov_.maxCoeff() == std::numeric_limits<float>::infinity() ||
616 leaf.icov_.minCoeff() == -std::numeric_limits<float>::infinity()) {
617 leaf.nr_points_ = -1;
621 output->width =
static_cast<uint32_t
>(output->points.size());
628 int min_points_per_voxel_;
631 double min_covar_eigvalue_mult_;
634 std::map<size_t, Leaf> leaves_;
642 std::vector<int> voxel_centroidsleaf_indices_;
645 pcl::KdTreeFLANN<PointT> kdtree_;