38 #ifndef PCL_FILTERS_IMPL_VOXEL_GRID_H_
39 #define PCL_FILTERS_IMPL_VOXEL_GRID_H_
45 #include <pcl/common/io.h>
46 #include <pcl/filters/voxel_grid.h>
47 #include <boost/sort/spreadsort/integer_sort.hpp>
50 template <
typename T>
void
53 if (pcl::traits::asEnum_v<T> != cloud->fields[x_idx].datatype ||
54 pcl::traits::asEnum_v<T> != cloud->fields[y_idx].datatype ||
55 pcl::traits::asEnum_v<T> != cloud->fields[z_idx].datatype)
57 PCL_ERROR(
"[pcl::getMinMax3D] Type of max_pt/min_pt does not match cloud type!\n");
61 T min_x = std::numeric_limits<T>::max();
62 T min_y = std::numeric_limits<T>::max();
63 T min_z = std::numeric_limits<T>::max();
64 T max_x = std::numeric_limits<T>::lowest();
65 T max_y = std::numeric_limits<T>::lowest();
66 T max_z = std::numeric_limits<T>::lowest();
68 const std::uint32_t x_off = cloud->fields[x_idx].offset;
69 const std::uint32_t y_off = cloud->fields[y_idx].offset;
70 const std::uint32_t z_off = cloud->fields[z_idx].offset;
71 const std::uint32_t pt_step = cloud->point_step;
72 const std::size_t nr_points = cloud->width * cloud->height;
74 const std::uint8_t* data_ptr = cloud->data.data();
78 auto update_min_max = [&](
const T& x,
const T& y,
const T& z) {
96 for (std::size_t i = 0; i < nr_points; ++i)
98 std::memcpy(&x, data_ptr + x_off,
sizeof(T));
99 std::memcpy(&y, data_ptr + y_off,
sizeof(T));
100 std::memcpy(&z, data_ptr + z_off,
sizeof(T));
104 update_min_max(x, y, z);
109 for (std::size_t i = 0; i < nr_points; ++i)
111 std::memcpy(&x, data_ptr + x_off,
sizeof(T));
112 std::memcpy(&y, data_ptr + y_off,
sizeof(T));
113 std::memcpy(&z, data_ptr + z_off,
sizeof(T));
118 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
121 update_min_max(x, y, z);
125 min_pt << min_x, min_y, min_z, 0;
126 max_pt << max_x, max_y, max_z, 0;
130 template <
typename T>
void
132 Eigen::Matrix<T, 4, 1> &min_pt, Eigen::Matrix<T, 4, 1> &max_pt)
134 if (pcl::traits::asEnum_v<T> != cloud->fields[x_idx].datatype ||
135 pcl::traits::asEnum_v<T> != cloud->fields[y_idx].datatype ||
136 pcl::traits::asEnum_v<T> != cloud->fields[z_idx].datatype)
138 PCL_ERROR(
"[pcl::getMinMax3D] Type of max_pt/min_pt does not match cloud type!\n");
142 T min_x = std::numeric_limits<T>::max();
143 T min_y = std::numeric_limits<T>::max();
144 T min_z = std::numeric_limits<T>::max();
145 T max_x = std::numeric_limits<T>::lowest();
146 T max_y = std::numeric_limits<T>::lowest();
147 T max_z = std::numeric_limits<T>::lowest();
149 const std::uint32_t x_off = cloud->fields[x_idx].offset;
150 const std::uint32_t y_off = cloud->fields[y_idx].offset;
151 const std::uint32_t z_off = cloud->fields[z_idx].offset;
152 const std::uint32_t pt_step = cloud->point_step;
153 const std::uint8_t* data_ptr = cloud->data.data();
157 auto update_min_max = [&](
const T& x,
const T& y,
const T& z) {
175 for (
const auto& index : indices)
177 const std::uint8_t* pt_data = data_ptr + (index * pt_step);
179 std::memcpy(&x, pt_data + x_off,
sizeof(T));
180 std::memcpy(&y, pt_data + y_off,
sizeof(T));
181 std::memcpy(&z, pt_data + z_off,
sizeof(T));
183 update_min_max(x, y, z);
188 for (
const auto& index : indices)
190 const std::uint8_t* pt_data = data_ptr + (index * pt_step);
192 std::memcpy(&x, pt_data + x_off,
sizeof(T));
193 std::memcpy(&y, pt_data + y_off,
sizeof(T));
194 std::memcpy(&z, pt_data + z_off,
sizeof(T));
197 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
200 update_min_max(x, y, z);
204 min_pt << min_x, min_y, min_z, 0;
205 max_pt << max_x, max_y, max_z, 0;
209 template <
typename T,
typename D>
void
211 const std::string &distance_field_name, D min_distance, D max_distance,
212 Eigen::Matrix<T, 4, 1> &min_pt, Eigen::Matrix<T, 4, 1> &max_pt,
bool limit_negative)
214 if (pcl::traits::asEnum_v<T> != cloud->fields[x_idx].datatype ||
215 pcl::traits::asEnum_v<T> != cloud->fields[y_idx].datatype ||
216 pcl::traits::asEnum_v<T> != cloud->fields[z_idx].datatype)
218 PCL_ERROR(
"[pcl::getMinMax3D] Type of max_pt/min_pt does not match cloud type!\n");
224 if (distance_idx < 0)
226 PCL_ERROR(
"[pcl::getMinMax3D] The specified distance field name is not found in the cloud!\n");
230 if (cloud->fields[distance_idx].datatype != pcl::traits::asEnum_v<D>)
232 PCL_ERROR (
"[pcl::getMinMax3D] min_distance/max_distance are incorrect type!\n");
236 T min_x = std::numeric_limits<T>::max();
237 T min_y = std::numeric_limits<T>::max();
238 T min_z = std::numeric_limits<T>::max();
239 T max_x = std::numeric_limits<T>::lowest();
240 T max_y = std::numeric_limits<T>::lowest();
241 T max_z = std::numeric_limits<T>::lowest();
243 const std::uint32_t x_off = cloud->fields[x_idx].offset;
244 const std::uint32_t y_off = cloud->fields[y_idx].offset;
245 const std::uint32_t z_off = cloud->fields[z_idx].offset;
246 const std::uint32_t pt_step = cloud->point_step;
247 const std::uint8_t* data_ptr = cloud->data.data();
248 const std::size_t nr_points = cloud->width * cloud->height;
250 const std::uint32_t distance_off = cloud->fields[distance_idx].offset;
255 auto update_min_max = [&](
const T& x,
const T& y,
const T& z) {
273 for (std::size_t cp = 0; cp < nr_points; ++cp)
275 std::memcpy(&distance_value, data_ptr + distance_off,
sizeof(D));
277 if (limit_negative == (distance_value < max_distance && distance_value > min_distance))
283 std::memcpy(&x, data_ptr + x_off,
sizeof(T));
284 std::memcpy(&y, data_ptr + y_off,
sizeof(T));
285 std::memcpy(&z, data_ptr + z_off,
sizeof(T));
289 update_min_max(x, y, z);
294 for (std::size_t cp = 0; cp < nr_points; ++cp)
296 std::memcpy(&distance_value, data_ptr + distance_off,
sizeof(D));
298 if (limit_negative == (distance_value < max_distance && distance_value > min_distance))
304 std::memcpy(&x, data_ptr + x_off,
sizeof(T));
305 std::memcpy(&y, data_ptr + y_off,
sizeof(T));
306 std::memcpy(&z, data_ptr + z_off,
sizeof(T));
311 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
314 update_min_max(x, y, z);
318 min_pt << min_x, min_y, min_z, 0;
319 max_pt << max_x, max_y, max_z, 0;
323 template <
typename T,
typename D>
void
325 Eigen::Matrix<T, 4, 1> &min_pt, Eigen::Matrix<T, 4, 1> &max_pt,
bool limit_negative)
327 if (pcl::traits::asEnum_v<T> != cloud->fields[x_idx].datatype ||
328 pcl::traits::asEnum_v<T> != cloud->fields[y_idx].datatype ||
329 pcl::traits::asEnum_v<T> != cloud->fields[z_idx].datatype)
331 PCL_ERROR(
"[pcl::getMinMax3D] Type of max_pt/min_pt does not match cloud type!\n");
337 if (distance_idx < 0)
339 PCL_ERROR(
"[pcl::getMinMax3D] The specified distance field name is not found in the cloud!\n");
343 if (cloud->fields[distance_idx].datatype != pcl::traits::asEnum_v<D>)
345 PCL_ERROR (
"[pcl::getMinMax3D] min_distance/max_distance are incorrect type!\n");
349 T min_x = std::numeric_limits<T>::max();
350 T min_y = std::numeric_limits<T>::max();
351 T min_z = std::numeric_limits<T>::max();
352 T max_x = std::numeric_limits<T>::lowest();
353 T max_y = std::numeric_limits<T>::lowest();
354 T max_z = std::numeric_limits<T>::lowest();
356 const std::uint32_t x_off = cloud->fields[x_idx].offset;
357 const std::uint32_t y_off = cloud->fields[y_idx].offset;
358 const std::uint32_t z_off = cloud->fields[z_idx].offset;
359 const std::uint32_t pt_step = cloud->point_step;
360 const std::uint8_t* data_ptr = cloud->data.data();
362 const std::uint32_t distance_off = cloud->fields[distance_idx].offset;
367 auto update_min_max = [&](
const T& x,
const T& y,
const T& z) {
385 for (
const auto& index : indices)
387 const std::uint8_t* pt_data = data_ptr + (index * pt_step);
389 std::memcpy(&distance_value, pt_data + distance_off,
sizeof(D));
391 if (limit_negative == (distance_value < max_distance && distance_value > min_distance))
396 std::memcpy(&x, pt_data + x_off,
sizeof(T));
397 std::memcpy(&y, pt_data + y_off,
sizeof(T));
398 std::memcpy(&z, pt_data + z_off,
sizeof(T));
400 update_min_max(x, y, z);
405 for (
const auto& index : indices)
407 const std::uint8_t* pt_data = data_ptr + (index * pt_step);
409 std::memcpy(&distance_value, pt_data + distance_off,
sizeof(D));
411 if (limit_negative == (distance_value < max_distance && distance_value > min_distance))
416 std::memcpy(&x, pt_data + x_off,
sizeof(T));
417 std::memcpy(&y, pt_data + y_off,
sizeof(T));
418 std::memcpy(&z, pt_data + z_off,
sizeof(T));
420 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
423 update_min_max(x, y, z);
426 min_pt << min_x, min_y, min_z, 0;
427 max_pt << max_x, max_y, max_z, 0;
431 template <
typename Po
intT>
void
433 const std::string &distance_field_name,
float min_distance,
float max_distance,
434 Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt,
bool limit_negative)
436 Eigen::Array4f min_p, max_p;
437 min_p.setConstant (std::numeric_limits<float>::max());
438 max_p.setConstant (std::numeric_limits<float>::lowest());
441 std::vector<pcl::PCLPointField> fields;
442 int distance_idx = pcl::getFieldIndex<PointT> (distance_field_name, fields);
443 if (distance_idx < 0 || fields.empty()) {
444 PCL_ERROR (
"[pcl::getMinMax3D] Could not find field with name '%s'!\n", distance_field_name.c_str());
447 const auto field_offset = fields[distance_idx].offset;
449 float distance_value;
453 for (
const auto& point: *cloud)
456 const auto* pt_data =
reinterpret_cast<const std::uint8_t*
> (&point);
457 memcpy (&distance_value, pt_data + field_offset,
sizeof (
float));
462 if ((distance_value < max_distance) && (distance_value > min_distance))
468 if ((distance_value > max_distance) || (distance_value < min_distance))
473 min_p = min_p.min (pt);
474 max_p = max_p.max (pt);
479 for (
const auto& point: *cloud)
482 const auto* pt_data =
reinterpret_cast<const std::uint8_t*
> (&point);
483 memcpy (&distance_value, pt_data + field_offset,
sizeof (
float));
488 if ((distance_value < max_distance) && (distance_value > min_distance))
494 if ((distance_value > max_distance) || (distance_value < min_distance))
503 min_p = min_p.min (pt);
504 max_p = max_p.max (pt);
512 template <
typename Po
intT>
void
515 const std::string &distance_field_name,
float min_distance,
float max_distance,
516 Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt,
bool limit_negative)
518 Eigen::Array4f min_p, max_p;
519 min_p.setConstant (std::numeric_limits<float>::max());
520 max_p.setConstant (std::numeric_limits<float>::lowest());
523 std::vector<pcl::PCLPointField> fields;
524 int distance_idx = pcl::getFieldIndex<PointT> (distance_field_name, fields);
525 if (distance_idx < 0 || fields.empty()) {
526 PCL_ERROR (
"[pcl::getMinMax3D] Could not find field with name '%s'!\n", distance_field_name.c_str());
529 const auto field_offset = fields[distance_idx].offset;
531 float distance_value;
535 for (
const auto &index : indices)
538 const auto* pt_data =
reinterpret_cast<const std::uint8_t*
> (&(*cloud)[index]);
539 memcpy (&distance_value, pt_data + field_offset,
sizeof (
float));
544 if ((distance_value < max_distance) && (distance_value > min_distance))
550 if ((distance_value > max_distance) || (distance_value < min_distance))
555 min_p = min_p.min (pt);
556 max_p = max_p.max (pt);
561 for (
const auto &index : indices)
564 const auto* pt_data =
reinterpret_cast<const std::uint8_t*
> (&(*cloud)[index]);
565 memcpy (&distance_value, pt_data + field_offset,
sizeof (
float));
570 if ((distance_value < max_distance) && (distance_value > min_distance))
576 if ((distance_value > max_distance) || (distance_value < min_distance))
581 if (!std::isfinite ((*cloud)[index].x) ||
582 !std::isfinite ((*cloud)[index].y) ||
583 !std::isfinite ((*cloud)[index].z))
587 min_p = min_p.min (pt);
588 max_p = max_p.max (pt);
596 template <
typename Po
intT>
void
602 PCL_WARN (
"[pcl::%s::applyFilter] No input dataset given!\n", getClassName ().c_str ());
612 Eigen::Vector4f min_p, max_p;
614 if (!filter_field_name_.empty ())
615 getMinMax3D<PointT> (input_, *indices_, filter_field_name_,
static_cast<float> (filter_limit_min_),
static_cast<float> (filter_limit_max_), min_p, max_p, filter_limit_negative_);
617 getMinMax3D<PointT> (*input_, *indices_, min_p, max_p);
620 std::int64_t dx =
static_cast<std::int64_t
>((max_p[0] - min_p[0]) * inverse_leaf_size_[0])+1;
621 std::int64_t dy =
static_cast<std::int64_t
>((max_p[1] - min_p[1]) * inverse_leaf_size_[1])+1;
622 std::int64_t dz =
static_cast<std::int64_t
>((max_p[2] - min_p[2]) * inverse_leaf_size_[2])+1;
624 if ((dx*dy*dz) >
static_cast<std::int64_t
>(std::numeric_limits<std::int32_t>::max()))
626 PCL_WARN(
"[pcl::%s::applyFilter] Leaf size is too small for the input dataset. Integer indices would overflow.\n", getClassName().c_str());
632 min_b_[0] =
static_cast<int> (std::floor (min_p[0] * inverse_leaf_size_[0]));
633 max_b_[0] =
static_cast<int> (std::floor (max_p[0] * inverse_leaf_size_[0]));
634 min_b_[1] =
static_cast<int> (std::floor (min_p[1] * inverse_leaf_size_[1]));
635 max_b_[1] =
static_cast<int> (std::floor (max_p[1] * inverse_leaf_size_[1]));
636 min_b_[2] =
static_cast<int> (std::floor (min_p[2] * inverse_leaf_size_[2]));
637 max_b_[2] =
static_cast<int> (std::floor (max_p[2] * inverse_leaf_size_[2]));
640 div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones ();
644 divb_mul_ = Eigen::Vector4i (1, div_b_[0], div_b_[0] * div_b_[1], 0);
647 std::vector<internal::cloud_point_index_idx> index_vector;
648 index_vector.reserve (indices_->size ());
651 if (!filter_field_name_.empty ())
654 std::vector<pcl::PCLPointField> fields;
655 int distance_idx = pcl::getFieldIndex<PointT> (filter_field_name_, fields);
656 if (distance_idx == -1) {
657 PCL_ERROR (
"[pcl::%s::applyFilter] Invalid filter field name (%s).\n", getClassName ().c_str (), filter_field_name_.c_str());
660 const auto field_offset = fields[distance_idx].offset;
665 for (
const auto& index : (*indices_))
667 if (!input_->is_dense)
673 const auto* pt_data =
reinterpret_cast<const std::uint8_t*
> (&(*input_)[index]);
674 float distance_value = 0;
675 memcpy (&distance_value, pt_data + field_offset,
sizeof (
float));
677 if (filter_limit_negative_)
680 if ((distance_value < filter_limit_max_) && (distance_value > filter_limit_min_))
686 if ((distance_value > filter_limit_max_) || (distance_value < filter_limit_min_))
690 int ijk0 =
static_cast<int> (std::floor ((*input_)[index].x * inverse_leaf_size_[0]) -
static_cast<float> (min_b_[0]));
691 int ijk1 =
static_cast<int> (std::floor ((*input_)[index].y * inverse_leaf_size_[1]) -
static_cast<float> (min_b_[1]));
692 int ijk2 =
static_cast<int> (std::floor ((*input_)[index].z * inverse_leaf_size_[2]) -
static_cast<float> (min_b_[2]));
695 int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
696 index_vector.emplace_back(
static_cast<unsigned int> (idx), index);
705 for (
const auto& index : (*indices_))
707 if (!input_->is_dense)
712 int ijk0 =
static_cast<int> (std::floor ((*input_)[index].x * inverse_leaf_size_[0]) -
static_cast<float> (min_b_[0]));
713 int ijk1 =
static_cast<int> (std::floor ((*input_)[index].y * inverse_leaf_size_[1]) -
static_cast<float> (min_b_[1]));
714 int ijk2 =
static_cast<int> (std::floor ((*input_)[index].z * inverse_leaf_size_[2]) -
static_cast<float> (min_b_[2]));
717 int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
718 index_vector.emplace_back(
static_cast<unsigned int> (idx), index);
725 boost::sort::spreadsort::integer_sort(index_vector.begin(), index_vector.end(), rightshift_func);
729 unsigned int total = 0;
730 unsigned int index = 0;
734 std::vector<std::pair<unsigned int, unsigned int> > first_and_last_indices_vector;
736 first_and_last_indices_vector.reserve (index_vector.size ());
737 while (index < index_vector.size ())
739 unsigned int i = index + 1;
740 while (i < index_vector.size () && index_vector[i].idx == index_vector[index].idx)
742 if (i - index >= min_points_per_voxel_)
745 first_and_last_indices_vector.emplace_back(index, i);
752 if (save_leaf_layout_)
757 std::uint32_t new_layout_size = div_b_[0]*div_b_[1]*div_b_[2];
759 std::uint32_t reinit_size = std::min (
static_cast<unsigned int> (new_layout_size),
static_cast<unsigned int> (leaf_layout_.size()));
760 for (std::uint32_t i = 0; i < reinit_size; i++)
762 leaf_layout_[i] = -1;
764 leaf_layout_.resize (new_layout_size, -1);
766 catch (std::bad_alloc&)
768 throw PCLException(
"VoxelGrid bin size is too low; impossible to allocate memory for layout",
769 "voxel_grid.hpp",
"applyFilter");
771 catch (std::length_error&)
773 throw PCLException(
"VoxelGrid bin size is too low; impossible to allocate memory for layout",
774 "voxel_grid.hpp",
"applyFilter");
779 for (
const auto &cp : first_and_last_indices_vector)
782 unsigned int first_index = cp.first;
783 unsigned int last_index = cp.second;
786 if (save_leaf_layout_)
787 leaf_layout_[index_vector[first_index].idx] = index;
790 if (!downsample_all_data_)
792 Eigen::Vector4f centroid (Eigen::Vector4f::Zero ());
794 for (
unsigned int li = first_index; li < last_index; ++li)
795 centroid += (*input_)[index_vector[li].cloud_point_index].getVector4fMap ();
797 centroid /=
static_cast<float> (last_index - first_index);
798 output[index].getVector4fMap () = centroid;
805 for (
unsigned int li = first_index; li < last_index; ++li)
806 centroid.
add ((*input_)[index_vector[li].cloud_point_index]);
808 centroid.
get (output[index]);
816 #define PCL_INSTANTIATE_VoxelGrid(T) template class PCL_EXPORTS pcl::VoxelGrid<T>;
817 #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);
Define methods for centroid estimation and covariance matrix calculus.
A generic class that computes the centroid of points fed to it.
void get(PointOutT &point) const
Retrieve the current centroid.
void add(const PointT &point)
Add a new point to the centroid computation.
A base class for all pcl exceptions which inherits from std::runtime_error.
PointCloud represents the base class in PCL for storing collections of 3D points.
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
void resize(std::size_t count)
Resizes the container to contain count elements.
std::uint32_t width
The point cloud width (if organized as an image-structure).
std::uint32_t height
The point cloud height (if organized as an image-structure).
void clear()
Removes all points in a cloud and sets the width and height to 0.
shared_ptr< const PointCloud< PointT > > ConstPtr
void applyFilter(PointCloud &output) override
Downsample a Point Cloud using a voxelized grid approach.
Define standard C methods and C++ classes that are common to all methods.
void getMinMax3D(const pcl::PointCloud< PointT > &cloud, PointT &min_pt, PointT &max_pt)
Get the minimum and maximum values on each of the 3 (x-y-z) dimensions in a given pointcloud.
int getFieldIndex(const pcl::PointCloud< PointT > &, const std::string &field_name, std::vector< pcl::PCLPointField > &fields)
const Eigen::Map< const Eigen::Array4f, Eigen::Aligned > Array4fMapConst
IndicesAllocator<> Indices
Type used for indices in PCL.
PCLPointCloud2::ConstPtr PCLPointCloud2ConstPtr
constexpr bool isXYZFinite(const PointT &) noexcept
Used internally in voxel grid classes.