ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
VoxelBlockGridCPU.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include <Logging.h>
9 #include <tbb/concurrent_unordered_set.h>
10 
12 #include "cloudViewer/core/Dtype.h"
23 
24 namespace cloudViewer {
25 namespace t {
26 namespace geometry {
27 namespace kernel {
28 namespace voxel_grid {
29 
30 using index_t = int;
31 
32 struct Coord3i {
33  Coord3i(index_t x, index_t y, index_t z) : x_(x), y_(y), z_(z) {}
34  bool operator==(const Coord3i &other) const {
35  return x_ == other.x_ && y_ == other.y_ && z_ == other.z_;
36  }
37 
41 };
42 
43 struct Coord3iHash {
44  size_t operator()(const Coord3i &k) const {
45  static const size_t p0 = 73856093;
46  static const size_t p1 = 19349669;
47  static const size_t p2 = 83492791;
48 
49  return (static_cast<size_t>(k.x_) * p0) ^
50  (static_cast<size_t>(k.y_) * p1) ^
51  (static_cast<size_t>(k.z_) * p2);
52  }
53 };
54 
56  std::shared_ptr<core::HashMap>
57  &hashmap, // dummy for now, one pass insertion is faster
58  const core::Tensor &points,
59  core::Tensor &voxel_block_coords,
60  index_t voxel_grid_resolution,
61  float voxel_size,
62  float sdf_trunc) {
63  index_t resolution = voxel_grid_resolution;
64  float block_size = voxel_size * resolution;
65 
66  index_t n = points.GetLength();
67  const float *pcd_ptr = static_cast<const float *>(points.GetDataPtr());
68 
69  tbb::concurrent_unordered_set<Coord3i, Coord3iHash> set;
70  core::ParallelFor(core::Device("CPU:0"), n, [&](index_t workload_idx) {
71  float x = pcd_ptr[3 * workload_idx + 0];
72  float y = pcd_ptr[3 * workload_idx + 1];
73  float z = pcd_ptr[3 * workload_idx + 2];
74 
75  index_t xb_lo =
76  static_cast<index_t>(std::floor((x - sdf_trunc) / block_size));
77  index_t xb_hi =
78  static_cast<index_t>(std::floor((x + sdf_trunc) / block_size));
79  index_t yb_lo =
80  static_cast<index_t>(std::floor((y - sdf_trunc) / block_size));
81  index_t yb_hi =
82  static_cast<index_t>(std::floor((y + sdf_trunc) / block_size));
83  index_t zb_lo =
84  static_cast<index_t>(std::floor((z - sdf_trunc) / block_size));
85  index_t zb_hi =
86  static_cast<index_t>(std::floor((z + sdf_trunc) / block_size));
87  for (index_t xb = xb_lo; xb <= xb_hi; ++xb) {
88  for (index_t yb = yb_lo; yb <= yb_hi; ++yb) {
89  for (index_t zb = zb_lo; zb <= zb_hi; ++zb) {
90  set.emplace(xb, yb, zb);
91  }
92  }
93  }
94  });
95 
96  index_t block_count = set.size();
97  if (block_count == 0) {
99  "No block is touched in TSDF volume, abort integration. Please "
100  "check specified parameters, "
101  "especially depth_scale and voxel_size");
102  }
103 
104  voxel_block_coords =
105  core::Tensor({block_count, 3}, core::Int32, points.GetDevice());
106  index_t *block_coords_ptr =
107  static_cast<index_t *>(voxel_block_coords.GetDataPtr());
108  index_t count = 0;
109  for (auto it = set.begin(); it != set.end(); ++it, ++count) {
110  index_t offset = count * 3;
111  block_coords_ptr[offset + 0] = static_cast<index_t>(it->x_);
112  block_coords_ptr[offset + 1] = static_cast<index_t>(it->y_);
113  block_coords_ptr[offset + 2] = static_cast<index_t>(it->z_);
114  }
115 }
116 
117 void DepthTouchCPU(std::shared_ptr<core::HashMap> &hashmap,
118  const core::Tensor &depth,
119  const core::Tensor &intrinsic,
120  const core::Tensor &extrinsic,
121  core::Tensor &voxel_block_coords,
122  index_t voxel_grid_resolution,
123  float voxel_size,
124  float sdf_trunc,
125  float depth_scale,
126  float depth_max,
127  index_t stride) {
128  core::Device device = depth.GetDevice();
129  NDArrayIndexer depth_indexer(depth, 2);
131  TransformIndexer ti(intrinsic, pose, 1.0f);
132 
133  // Output
134  index_t rows_strided = depth_indexer.GetShape(0) / stride;
135  index_t cols_strided = depth_indexer.GetShape(1) / stride;
136  index_t n = rows_strided * cols_strided;
137 
138  index_t resolution = voxel_grid_resolution;
139  float block_size = voxel_size * resolution;
140 
141  tbb::concurrent_unordered_set<Coord3i, Coord3iHash> set;
142  DISPATCH_DTYPE_TO_TEMPLATE(depth.GetDtype(), [&]() {
143  core::ParallelFor(device, n, [&](index_t workload_idx) {
144  index_t y = (workload_idx / cols_strided) * stride;
145  index_t x = (workload_idx % cols_strided) * stride;
146 
147  float d = *depth_indexer.GetDataPtr<scalar_t>(x, y) / depth_scale;
148  if (d > 0 && d < depth_max) {
149  float x_c = 0, y_c = 0, z_c = 0;
150  ti.Unproject(static_cast<float>(x), static_cast<float>(y), 1.0,
151  &x_c, &y_c, &z_c);
152  float x_g = 0, y_g = 0, z_g = 0;
153  ti.RigidTransform(x_c, y_c, z_c, &x_g, &y_g, &z_g);
154 
155  // Origin
156  float x_o = 0, y_o = 0, z_o = 0;
157  ti.GetCameraPosition(&x_o, &y_o, &z_o);
158 
159  // Direction
160  float x_d = x_g - x_o;
161  float y_d = y_g - y_o;
162  float z_d = z_g - z_o;
163 
164  const index_t step_size = 3;
165  const float t_min = std::max(d - sdf_trunc, 0.0f);
166  const float t_max = std::min(d + sdf_trunc, depth_max);
167  const float t_step = (t_max - t_min) / step_size;
168 
169  float t = t_min;
170  for (index_t step = 0; step <= step_size; ++step) {
171  index_t xb = static_cast<index_t>(
172  std::floor((x_o + t * x_d) / block_size));
173  index_t yb = static_cast<index_t>(
174  std::floor((y_o + t * y_d) / block_size));
175  index_t zb = static_cast<index_t>(
176  std::floor((z_o + t * z_d) / block_size));
177  set.emplace(xb, yb, zb);
178  t += t_step;
179  }
180  }
181  });
182  });
183 
184  index_t block_count = set.size();
185  if (block_count == 0) {
187  "No block is touched in TSDF volume, abort integration. Please "
188  "check specified parameters, "
189  "especially depth_scale and voxel_size");
190  }
191 
192  voxel_block_coords = core::Tensor({block_count, 3}, core::Int32, device);
193  index_t *block_coords_ptr = voxel_block_coords.GetDataPtr<index_t>();
194  index_t count = 0;
195  for (auto it = set.begin(); it != set.end(); ++it, ++count) {
196  index_t offset = count * 3;
197  block_coords_ptr[offset + 0] = static_cast<index_t>(it->x_);
198  block_coords_ptr[offset + 1] = static_cast<index_t>(it->y_);
199  block_coords_ptr[offset + 2] = static_cast<index_t>(it->z_);
200  }
201 }
202 
203 #define FN_ARGUMENTS \
204  const core::Tensor &depth, const core::Tensor &color, \
205  const core::Tensor &indices, const core::Tensor &block_keys, \
206  TensorMap &value_tensor_map, const core::Tensor &depth_intrinsic, \
207  const core::Tensor &color_intrinsic, \
208  const core::Tensor &extrinsic, index_t resolution, \
209  float voxel_size, float sdf_trunc, float depth_scale, \
210  float depth_max
211 
213  FN_ARGUMENTS);
215  FN_ARGUMENTS);
217  FN_ARGUMENTS);
219 
220 #undef FN_ARGUMENTS
221 
222 #define FN_ARGUMENTS \
223  std::shared_ptr<core::HashMap> &hashmap, const TensorMap &block_value_map, \
224  const core::Tensor &range_map, TensorMap &renderings_map, \
225  const core::Tensor &intrinsic, const core::Tensor &extrinsic, \
226  index_t h, index_t w, index_t block_resolution, float voxel_size, \
227  float depth_scale, float depth_min, float depth_max, \
228  float weight_threshold, float trunc_voxel_multiplier, \
229  int range_map_down_factor
230 
233 
234 #undef FN_ARGUMENTS
235 
236 #define FN_ARGUMENTS \
237  const core::Tensor &block_indices, const core::Tensor &nb_block_indices, \
238  const core::Tensor &nb_block_masks, \
239  const core::Tensor &block_keys, const TensorMap &block_value_map, \
240  core::Tensor &points, core::Tensor &normals, core::Tensor &colors, \
241  index_t block_resolution, float voxel_size, \
242  float weight_threshold, index_t &valid_size
243 
246 
247 #undef FN_ARGUMENTS
248 
249 #define FN_ARGUMENTS \
250  const core::Tensor &block_indices, const core::Tensor &inv_block_indices, \
251  const core::Tensor &nb_block_indices, \
252  const core::Tensor &nb_block_masks, \
253  const core::Tensor &block_keys, const TensorMap &block_value_map, \
254  core::Tensor &vertices, core::Tensor &triangles, \
255  core::Tensor &vertex_normals, core::Tensor &vertex_colors, \
256  index_t block_resolution, float voxel_size, \
257  float weight_threshold, index_t &vertex_count
258 
261 
262 #undef FN_ARGUMENTS
263 
264 } // namespace voxel_grid
265 } // namespace kernel
266 } // namespace geometry
267 } // namespace t
268 } // namespace cloudViewer
#define DISPATCH_DTYPE_TO_TEMPLATE(DTYPE,...)
Definition: Dispatch.h:31
int count
int offset
int points
size_t stride
#define FN_ARGUMENTS
Dtype GetDtype() const
Definition: Tensor.h:1164
Device GetDevice() const override
Definition: Tensor.cpp:1435
CLOUDVIEWER_HOST_DEVICE index_t GetShape(int i) const
Helper class for converting coordinates/indices between 3D/3D, 3D/2D, 2D/3D.
#define LogError(...)
Definition: Logging.h:60
void ParallelFor(const Device &device, int64_t n, const func_t &func)
Definition: ParallelFor.h:111
const Dtype Int32
Definition: Dtype.cpp:46
void DepthTouchCPU(std::shared_ptr< core::HashMap > &hashmap, const core::Tensor &depth, const core::Tensor &intrinsic, const core::Tensor &extrinsic, core::Tensor &voxel_block_coords, index_t voxel_grid_resolution, float voxel_size, float sdf_trunc, float depth_scale, float depth_max, index_t stride)
template void ExtractPointCloudCPU< float, uint16_t, uint16_t >(const core::Tensor &block_indices, const core::Tensor &nb_block_indices, const core::Tensor &nb_block_masks, const core::Tensor &block_keys, const TensorMap &block_value_map, core::Tensor &points, core::Tensor &normals, core::Tensor &colors, index_t block_resolution, float voxel_size, float weight_threshold, index_t &valid_size)
void PointCloudTouchCPU(std::shared_ptr< core::HashMap > &hashmap, const core::Tensor &points, core::Tensor &voxel_block_coords, index_t voxel_grid_resolution, float voxel_size, float sdf_trunc)
CPU.
template void ExtractTriangleMeshCPU< float, float, float >(const core::Tensor &block_indices, const core::Tensor &inv_block_indices, const core::Tensor &nb_block_indices, const core::Tensor &nb_block_masks, const core::Tensor &block_keys, const TensorMap &block_value_map, core::Tensor &vertices, core::Tensor &triangles, core::Tensor &vertex_normals, core::Tensor &vertex_colors, index_t block_resolution, float voxel_size, float weight_threshold, index_t &vertex_count)
template void IntegrateCPU< float, float, float, uint16_t, uint16_t >(const core::Tensor &depth, const core::Tensor &color, const core::Tensor &indices, const core::Tensor &block_keys, TensorMap &value_tensor_map, const core::Tensor &depth_intrinsic, const core::Tensor &color_intrinsic, const core::Tensor &extrinsic, index_t resolution, float voxel_size, float sdf_trunc, float depth_scale, float depth_max)
template void ExtractTriangleMeshCPU< float, uint16_t, uint16_t >(const core::Tensor &block_indices, const core::Tensor &inv_block_indices, const core::Tensor &nb_block_indices, const core::Tensor &nb_block_masks, const core::Tensor &block_keys, const TensorMap &block_value_map, core::Tensor &vertices, core::Tensor &triangles, core::Tensor &vertex_normals, core::Tensor &vertex_colors, index_t block_resolution, float voxel_size, float weight_threshold, index_t &vertex_count)
template void IntegrateCPU< uint16_t, uint8_t, float, uint16_t, uint16_t >(const core::Tensor &depth, const core::Tensor &color, const core::Tensor &indices, const core::Tensor &block_keys, TensorMap &value_tensor_map, const core::Tensor &depth_intrinsic, const core::Tensor &color_intrinsic, const core::Tensor &extrinsic, index_t resolution, float voxel_size, float sdf_trunc, float depth_scale, float depth_max)
template void IntegrateCPU< uint16_t, uint8_t, float, float, float >(const core::Tensor &depth, const core::Tensor &color, const core::Tensor &indices, const core::Tensor &block_keys, TensorMap &value_tensor_map, const core::Tensor &depth_intrinsic, const core::Tensor &color_intrinsic, const core::Tensor &extrinsic, index_t resolution, float voxel_size, float sdf_trunc, float depth_scale, float depth_max)
template void ExtractPointCloudCPU< float, float, float >(const core::Tensor &block_indices, const core::Tensor &nb_block_indices, const core::Tensor &nb_block_masks, const core::Tensor &block_keys, const TensorMap &block_value_map, core::Tensor &points, core::Tensor &normals, core::Tensor &colors, index_t block_resolution, float voxel_size, float weight_threshold, index_t &valid_size)
template void RayCastCPU< float, float, float >(std::shared_ptr< core::HashMap > &hashmap, const TensorMap &block_value_map, const core::Tensor &range_map, TensorMap &renderings_map, const core::Tensor &intrinsic, const core::Tensor &extrinsic, index_t h, index_t w, index_t block_resolution, float voxel_size, float depth_scale, float depth_min, float depth_max, float weight_threshold, float trunc_voxel_multiplier, int range_map_down_factor)
template void RayCastCPU< float, uint16_t, uint16_t >(std::shared_ptr< core::HashMap > &hashmap, const TensorMap &block_value_map, const core::Tensor &range_map, TensorMap &renderings_map, const core::Tensor &intrinsic, const core::Tensor &extrinsic, index_t h, index_t w, index_t block_resolution, float voxel_size, float depth_scale, float depth_min, float depth_max, float weight_threshold, float trunc_voxel_multiplier, int range_map_down_factor)
template void IntegrateCPU< float, float, float, float, float >(const core::Tensor &depth, const core::Tensor &color, const core::Tensor &indices, const core::Tensor &block_keys, TensorMap &value_tensor_map, const core::Tensor &depth_intrinsic, const core::Tensor &color_intrinsic, const core::Tensor &extrinsic, index_t resolution, float voxel_size, float sdf_trunc, float depth_scale, float depth_max)
core::Tensor InverseTransformation(const core::Tensor &T)
TODO(wei): find a proper place for such functionalities.
Definition: Utility.h:77
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
Generic file read and write utility for python interface.