small_gicp
downsampling_tbb.hpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright 2024 Kenji Koide
2 // SPDX-License-Identifier: MIT
3 #pragma once
4 
5 #include <atomic>
6 #include <memory>
7 #include <iostream>
8 
9 #include <tbb/tbb.h>
13 
14 namespace small_gicp {
15 
25 template <typename InputPointCloud, typename OutputPointCloud = InputPointCloud>
26 std::shared_ptr<OutputPointCloud> voxelgrid_sampling_tbb(const InputPointCloud& points, double leaf_size) {
27  if (traits::size(points) == 0) {
28  return std::make_shared<OutputPointCloud>();
29  }
30 
31  const double inv_leaf_size = 1.0 / leaf_size;
32 
33  constexpr std::uint64_t invalid_coord = std::numeric_limits<std::uint64_t>::max();
34  constexpr int coord_bit_size = 21; // Bits to represent each voxel coordinate (pack 21x3 = 63bits in 64bit int)
35  constexpr size_t coord_bit_mask = (1 << 21) - 1; // Bit mask
36  constexpr int coord_offset = 1 << (coord_bit_size - 1); // Coordinate offset to make values positive
37 
38  std::vector<std::pair<std::uint64_t, size_t>> coord_pt(traits::size(points));
39  tbb::parallel_for(tbb::blocked_range<size_t>(0, traits::size(points), 64), [&](const tbb::blocked_range<size_t>& range) {
40  for (size_t i = range.begin(); i != range.end(); i++) {
41  const Eigen::Array4i coord = fast_floor(traits::point(points, i) * inv_leaf_size) + coord_offset;
42  if ((coord < 0).any() || (coord > coord_bit_mask).any()) {
43  std::cerr << "warning: voxel coord is out of range!!" << std::endl;
44  coord_pt[i] = {invalid_coord, i};
45  continue;
46  }
47 
48  // Compute voxel coord bits (0|1bit, z|21bit, y|21bit, x|21bit)
49  const std::uint64_t bits = //
50  (static_cast<std::uint64_t>(coord[0] & coord_bit_mask) << (coord_bit_size * 0)) | //
51  (static_cast<std::uint64_t>(coord[1] & coord_bit_mask) << (coord_bit_size * 1)) | //
52  (static_cast<std::uint64_t>(coord[2] & coord_bit_mask) << (coord_bit_size * 2));
53  coord_pt[i] = {bits, i};
54  }
55  });
56 
57  // Sort by voxel coords
58  tbb::parallel_sort(coord_pt, [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; });
59 
60  auto downsampled = std::make_shared<OutputPointCloud>();
61  traits::resize(*downsampled, traits::size(points));
62 
63  // Take block-wise sum
64  const int block_size = 2048;
65  std::atomic_uint64_t num_points = 0;
66  tbb::parallel_for(tbb::blocked_range<size_t>(0, traits::size(points), block_size), [&](const tbb::blocked_range<size_t>& range) {
67  std::vector<Eigen::Vector4d> sub_points;
68  sub_points.reserve(block_size);
69 
70  Eigen::Vector4d sum_pt = traits::point(points, coord_pt[range.begin()].second);
71  for (size_t i = range.begin() + 1; i != range.end(); i++) {
72  if (coord_pt[i].first == invalid_coord) {
73  continue;
74  }
75 
76  if (coord_pt[i - 1].first != coord_pt[i].first) {
77  sub_points.emplace_back(sum_pt / sum_pt.w());
78  sum_pt.setZero();
79  }
80  sum_pt += traits::point(points, coord_pt[i].second);
81  }
82  sub_points.emplace_back(sum_pt / sum_pt.w());
83 
84  const size_t point_index_begin = num_points.fetch_add(sub_points.size());
85  for (size_t i = 0; i < sub_points.size(); i++) {
86  traits::set_point(*downsampled, point_index_begin + i, sub_points[i]);
87  }
88  });
89 
90  traits::resize(*downsampled, num_points);
91 
92  return downsampled;
93 }
94 
95 } // namespace small_gicp
size_t size(const T &points)
Get the number of points.
Definition: traits.hpp:16
auto point(const T &points, size_t i)
Get i-th point. 4D vector is used to take advantage of SIMD intrinsics. The last element must be fill...
Definition: traits.hpp:40
void set_point(T &points, size_t i, const Eigen::Vector4d &pt)
Set i-th point. (x, y, z, 1)
Definition: traits.hpp:64
void resize(T &points, size_t n)
Resize the point cloud (this function should resize all attributes)
Definition: traits.hpp:58
Definition: flat_container.hpp:12
std::shared_ptr< OutputPointCloud > voxelgrid_sampling_tbb(const InputPointCloud &points, double leaf_size)
Voxel grid downsampling with TBB backend.
Definition: downsampling_tbb.hpp:26