24 std::shared_ptr<core::HashMap> &hashmap,
29 core::Tensor key_buffer_int3_tensor = hashmap->GetKeyTensor();
33 int64_t n = active_keys.
GetShape()[0];
37 for (
int nb = 0; nb < 27; ++nb) {
39 int dy = (nb % 9) / 3;
42 core::Tensor(std::vector<int>{dx - 1, dy - 1, dz - 1}, {1, 3},
44 keys_nb[nb] = active_keys + dt;
46 keys_nb = keys_nb.
View({27 * n, 3});
49 hashmap->Find(keys_nb, buf_indices_nb, masks_nb);
51 masks_nb.
View({27, n, 1}));
56 std::unordered_map<std::string, int> name_attr_map) {
58 for (
auto &v : name_attr_map) {
59 std::string
name = v.first;
60 int buf_idx = v.second;
67 const std::vector<std::string> &attr_names,
68 const std::vector<core::Dtype> &attr_dtypes,
69 const std::vector<core::SizeVector> &attr_channels,
71 int64_t block_resolution,
75 : voxel_size_(voxel_size), block_resolution_(block_resolution) {
77 if (voxel_size <= 0) {
81 if (block_resolution <= 0) {
87 size_t n_attrs = attr_names.size();
88 if (attr_dtypes.size() != n_attrs) {
90 "Number of attribute dtypes ({}) mismatch with names ({}).",
91 attr_dtypes.size(), n_attrs);
93 if (attr_channels.size() != n_attrs) {
95 "Number of attribute channels ({}) mismatch with names ({}).",
96 attr_channels.size(), n_attrs);
100 std::vector<core::SizeVector> attr_element_shapes;
103 for (
size_t i = 0; i < n_attrs; ++i) {
107 block_shape_copy.
insert(block_shape_copy.
end(), attr_channel.
begin(),
109 attr_element_shapes.emplace_back(block_shape_copy);
112 name_attr_map_[attr_names[i]] = i;
115 block_hashmap_ = std::make_shared<core::HashMap>(
117 attr_element_shapes, device, backend);
122 if (name_attr_map_.count(attr_name) == 0) {
127 int buffer_idx = name_attr_map_.at(attr_name);
128 return block_hashmap_->GetValueTensor(buffer_idx);
134 core::Tensor key_tensor = block_hashmap_->GetKeyTensor();
139 voxel_coords[0] += voxel_indices[1];
140 voxel_coords[1] += voxel_indices[2];
141 voxel_coords[2] += voxel_indices[3];
151 int64_t n_blocks = buf_indices.
GetLength();
153 int64_t resolution = block_resolution_;
154 int64_t resolution2 = resolution * resolution;
155 int64_t resolution3 = resolution2 * resolution;
160 0, n_blocks * resolution3, 1,
core::Int64, device);
162 core::Tensor block_idx = linear_coordinates / resolution3;
163 core::Tensor remainder = linear_coordinates - block_idx * resolution3;
167 remainder = remainder - voxel_z * resolution2;
169 core::Tensor voxel_x = remainder - voxel_y * resolution;
174 voxel_indices[1] = voxel_x;
175 voxel_indices[2] = voxel_y;
176 voxel_indices[3] = voxel_z;
178 return voxel_indices;
186 std::pair<core::Tensor, core::Tensor>
190 block_hashmap_->GetActiveIndices());
193 std::pair<core::Tensor, core::Tensor>
200 int64_t resolution3 =
201 block_resolution_ * block_resolution_ * block_resolution_;
208 buf_indices, block_hashmap_->GetKeyTensor(), voxel_coords,
209 flattened_indices, block_resolution_, voxel_size_);
219 float trunc_voxel_multiplier) {
225 const int64_t down_factor = 4;
226 const int64_t est_sample_multiplier = 4;
227 if (frustum_hashmap_ ==
nullptr) {
228 int64_t capacity = (depth.
GetCols() / down_factor) *
229 (depth.
GetRows() / down_factor) *
230 est_sample_multiplier;
231 frustum_hashmap_ = std::make_shared<core::HashMap>(
235 frustum_hashmap_->Clear();
240 intrinsic, extrinsic, block_coords,
241 block_resolution_, voxel_size_,
242 voxel_size_ * trunc_voxel_multiplier,
243 depth_scale, depth_max, down_factor);
249 const PointCloud &pcd,
float trunc_voxel_multiplier) {
253 const int64_t est_neighbor_multiplier = 8;
254 if (frustum_hashmap_ ==
nullptr) {
255 int64_t capacity = positions.
GetLength() * est_neighbor_multiplier;
256 frustum_hashmap_ = std::make_shared<core::HashMap>(
260 frustum_hashmap_->Clear();
265 frustum_hashmap_, positions, block_coords, block_resolution_,
266 voxel_size_, voxel_size_ * trunc_voxel_multiplier);
276 float trunc_voxel_multiplier) {
277 Integrate(block_coords, depth,
Image(), intrinsic, intrinsic, extrinsic,
278 depth_scale, depth_max, trunc_voxel_multiplier);
288 float trunc_voxel_multiplier) {
289 Integrate(block_coords, depth,
color, intrinsic, intrinsic, extrinsic,
290 depth_scale, depth_max, trunc_voxel_multiplier);
301 float trunc_voxel_multiplier) {
303 bool integrate_color =
color.AsTensor().NumElements() > 0;
307 if (integrate_color) {
315 block_hashmap_->Activate(block_coords, buf_indices, masks);
316 block_hashmap_->Find(block_coords, buf_indices, masks);
318 core::Tensor block_keys = block_hashmap_->GetKeyTensor();
324 block_value_map, depth_intrinsic, color_intrinsic, extrinsic,
325 block_resolution_, voxel_size_,
326 voxel_size_ * trunc_voxel_multiplier, depth_scale, depth_max);
334 const std::vector<std::string> attrs,
338 float weight_threshold,
339 float trunc_voxel_multiplier,
340 int range_map_down_factor) {
351 block_coords, range_minmax_map, intrinsic, extrinsic,
height,
width,
352 range_map_down_factor, block_resolution_, voxel_size_, depth_min,
353 depth_max, fragment_buffer_);
355 static const std::unordered_map<std::string, int> kAttrChannelMap = {
366 {
"interp_ratio_dx", 8},
367 {
"interp_ratio_dy", 8},
368 {
"interp_ratio_dz", 8}};
370 auto get_dtype = [&](
const std::string &attr_name) ->
core::Dtype {
371 if (attr_name ==
"mask") {
373 }
else if (attr_name ==
"index") {
381 renderings_map[
"range"] = range_minmax_map;
382 for (
const auto &attr : attrs) {
383 if (kAttrChannelMap.count(attr) == 0) {
385 "Unsupported attribute {}, please implement customized ray "
388 int channel = kAttrChannelMap.at(attr);
390 renderings_map[attr] =
397 block_hashmap_, block_value_map, range_minmax_map, renderings_map,
398 intrinsic, extrinsic,
height,
width, block_resolution_, voxel_size_,
399 depth_scale, depth_min, depth_max, weight_threshold,
400 trunc_voxel_multiplier, range_map_down_factor);
402 return renderings_map;
406 int estimated_point_number) {
409 block_hashmap_->GetActiveIndices(active_buf_indices);
412 std::tie(active_nb_buf_indices, active_nb_masks) =
418 core::Tensor block_keys = block_hashmap_->GetKeyTensor();
422 active_buf_indices, active_nb_buf_indices, active_nb_masks,
424 block_resolution_, voxel_size_, weight_threshold,
425 estimated_point_number);
428 pcd.SetPointNormals(
normals.Slice(0, 0, estimated_point_number));
431 pcd.SetPointColors(
colors.Slice(0, 0, estimated_point_number));
438 int estimated_vertex_number) {
440 core::Tensor active_buf_indices_i32 = block_hashmap_->GetActiveIndices();
442 std::tie(active_nb_buf_indices, active_nb_masks) =
447 int64_t num_blocks = block_hashmap_->Size();
452 inverse_index_map.IndexSet({active_buf_indices_i32.
To(
core::Int64)},
455 core::Tensor vertices, triangles, vertex_normals, vertex_colors;
457 core::Tensor block_keys = block_hashmap_->GetKeyTensor();
461 active_buf_indices_i32, inverse_index_map, active_nb_buf_indices,
462 active_nb_masks, block_keys, block_value_map, vertices, triangles,
463 vertex_normals, vertex_colors, block_resolution_, voxel_size_,
464 weight_threshold, estimated_vertex_number);
479 std::vector<core::Tensor> values = block_hashmap_->GetValueTensors();
483 core::Tensor active_buf_indices_i32 = block_hashmap_->GetActiveIndices();
486 std::unordered_map<std::string, core::Tensor> output;
489 output.emplace(
"voxel_size",
core::Tensor(std::vector<float>{voxel_size_},
491 output.emplace(
"block_resolution",
492 core::Tensor(std::vector<int64_t>{block_resolution_}, {1},
495 output.emplace(block_hashmap_->GetDevice().ToString(),
498 for (
auto &it : name_attr_map_) {
500 output.emplace(
fmt::format(
"attr_name_{}", it.first),
507 output.emplace(
"key", active_keys);
510 for (
auto &it : name_attr_map_) {
511 int value_id = it.second;
513 values[value_id].
IndexGet({active_indices}).
To(host);
514 output.emplace(
fmt::format(
"value_{:03d}", value_id), active_value_i);
521 "File name for a voxel grid should be with the extension "
522 ".npz. Saving to {}.npz",
531 if (!
copy && block_hashmap_->GetDevice() == device) {
535 auto device_hashmap =
536 std::make_shared<core::HashMap>(this->block_hashmap_->To(device));
537 return VoxelBlockGrid(voxel_size_, block_resolution_, device_hashmap,
542 std::unordered_map<std::string, core::Tensor> tensor_map =
545 std::string prefix =
"attr_name_";
546 std::unordered_map<int, std::string> inv_attr_map;
548 std::string kCPU =
"CPU";
549 std::string kCUDA =
"CUDA";
551 std::string device_str =
"CPU:0";
552 for (
auto &it : tensor_map) {
553 if (!it.first.compare(0, prefix.size(), prefix)) {
554 int value_id = it.second[0].Item<
int>();
555 inv_attr_map.emplace(value_id, it.first.substr(prefix.size()));
557 if (!it.first.compare(0, kCPU.size(), kCPU) ||
558 !it.first.compare(0, kCUDA.size(), kCUDA)) {
559 device_str = it.first;
562 if (inv_attr_map.size() == 0) {
564 "Attribute names not found, not a valid file for voxel block "
570 std::vector<std::string> attr_names(inv_attr_map.size());
572 std::vector<core::Tensor> soa_value_tensor(inv_attr_map.size());
573 std::vector<core::Dtype> attr_dtypes(inv_attr_map.size());
574 std::vector<core::SizeVector> attr_channels(inv_attr_map.size());
578 for (
auto &v : inv_attr_map) {
579 int value_id = v.first;
580 attr_names[value_id] = v.second;
583 tensor_map.at(
fmt::format(
"value_{:03d}", value_id));
585 soa_value_tensor[value_id] = value_i.
To(device);
586 attr_dtypes[value_id] = value_i.
GetDtype();
591 attr_channels[value_id] = value_i_shape;
595 float voxel_size = tensor_map.at(
"voxel_size")[0].
Item<
float>();
596 int block_resolution = tensor_map.at(
"block_resolution")[0].Item<int64_t>();
598 VoxelBlockGrid vbg(attr_names, attr_dtypes, attr_channels, voxel_size,
599 block_resolution, keys.
GetLength(), device);
600 auto block_hashmap = vbg.GetHashMap();
601 block_hashmap.Insert(keys, soa_value_tensor);
605 void VoxelBlockGrid::AssertInitialized()
const {
606 if (block_hashmap_ ==
nullptr) {
filament::Texture::InternalFormat format
static const Dtype Float32
Tensor GetValueTensor(size_t index=0) const
iterator erase(const_iterator CI)
iterator insert(iterator I, T &&Elt)
static Tensor Arange(const Scalar start, const Scalar stop, const Scalar step=1, const Dtype dtype=core::Int64, const Device &device=core::Device("CPU:0"))
Create a 1D tensor with evenly spaced values in the given interval.
int64_t GetLength() const
Tensor IndexGet(const std::vector< Tensor > &index_tensors) const
Advanced indexing getter. This will always allocate a new Tensor.
static Tensor Zeros(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with zeros.
Tensor View(const SizeVector &dst_shape) const
SizeVector GetShape() const
Tensor To(Dtype dtype, bool copy=false) const
The Image class stores image with customizable rows, cols, channels, dtype and device.
core::Tensor AsTensor() const
Returns the underlying Tensor of the Image.
int64_t GetCols() const
Get the number of columns of the image.
int64_t GetRows() const
Get the number of rows of the image.
A point cloud contains a list of 3D points.
core::Tensor & GetPointPositions()
Get the value of the "positions" attribute. Convenience function.
A triangle mesh contains vertices and triangles.
void SetVertexNormals(const core::Tensor &value)
void SetVertexColors(const core::Tensor &value)
PointCloud ExtractPointCloud(float weight_threshold=3.0f, int estimated_point_number=-1)
void Save(const std::string &file_name) const
Save a voxel block grid to a .npz file.
VoxelBlockGrid To(const core::Device &device, bool copy=false) const
Convert the hash map to another device.
static VoxelBlockGrid Load(const std::string &file_name)
Load a voxel block grid from a .npz file.
TensorMap RayCast(const core::Tensor &block_coords, const core::Tensor &intrinsic, const core::Tensor &extrinsic, int width, int height, const std::vector< std::string > attrs={"depth", "color"}, float depth_scale=1000.0f, float depth_min=0.1f, float depth_max=3.0f, float weight_threshold=3.0f, float trunc_voxel_multiplier=8.0f, int range_map_down_factor=8)
core::Tensor GetVoxelIndices() const
Get all active voxel indices.
core::Tensor GetVoxelCoordinates(const core::Tensor &voxel_indices) const
std::pair< core::Tensor, core::Tensor > GetVoxelCoordinatesAndFlattenedIndices()
TriangleMesh ExtractTriangleMesh(float weight_threshold=3.0f, int estimated_vertex_numer=-1)
void Integrate(const core::Tensor &block_coords, const Image &depth, const Image &color, const core::Tensor &depth_intrinsic, const core::Tensor &color_intrinsic, const core::Tensor &extrinsic, float depth_scale=1000.0f, float depth_max=3.0f, float trunc_voxel_multiplier=8.0f)
core::Tensor GetAttribute(const std::string &attr_name) const
core::Tensor GetUniqueBlockCoordinates(const Image &depth, const core::Tensor &intrinsic, const core::Tensor &extrinsic, float depth_scale=1000.0f, float depth_max=3.0f, float trunc_voxel_multiplier=8.0)
CLOUDVIEWER_HOST_DEVICE Pair< First, Second > make_pair(const First &_first, const Second &_second)
::ccPointCloud PointCloud
void Integrate(const core::Tensor &depth, const core::Tensor &color, const core::Tensor &block_indices, const core::Tensor &block_keys, TensorMap &block_value_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)
void GetVoxelCoordinatesAndFlattenedIndices(const core::Tensor &buf_indices, const core::Tensor &block_keys, core::Tensor &voxel_coords, core::Tensor &flattened_indices, index_t block_resolution, float voxel_size)
void PointCloudTouch(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)
void ExtractPointCloud(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, int &valid_size)
void RayCast(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)
void DepthTouch(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)
void ExtractTriangleMesh(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, int &vertex_count)
void EstimateRange(const core::Tensor &block_keys, core::Tensor &range_minmax_map, const core::Tensor &intrinsics, const core::Tensor &extrinsics, int h, int w, int down_factor, int64_t block_resolution, float voxel_size, float depth_min, float depth_max, core::Tensor &fragment_buffer)
void CheckDepthTensor(const core::Tensor &depth)
void CheckExtrinsicTensor(const core::Tensor &extrinsic)
void CheckIntrinsicTensor(const core::Tensor &intrinsic)
void CheckBlockCoordinates(const core::Tensor &block_coords)
static TensorMap ConstructTensorMap(const core::HashMap &block_hashmap, std::unordered_map< std::string, int > name_attr_map)
static std::pair< core::Tensor, core::Tensor > BufferRadiusNeighbors(std::shared_ptr< core::HashMap > &hashmap, const core::Tensor &active_buf_indices)
void CheckColorTensor(const core::Tensor &color)
std::unordered_map< std::string, core::Tensor > ReadNpz(const std::string &file_name)
void WriteNpz(const std::string &file_name, const std::unordered_map< std::string, core::Tensor > &tensor_map)
std::string GetFileExtensionInLowerCase(const std::string &filename)
Generic file read and write utility for python interface.