ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FixedRadiusIndex.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 
9 
10 #include <Logging.h>
11 
14 
15 namespace cloudViewer {
16 namespace core {
17 namespace nns {
18 
20 
22  double radius) {
23  AssertTensorDtypes(dataset_points, {Float32, Float64});
24  SetTensorData(dataset_points, radius);
25 };
26 
28  double radius,
29  const Dtype &index_dtype) {
30  AssertTensorDtypes(dataset_points, {Float32, Float64});
31  assert(index_dtype == Int32 || index_dtype == Int64);
32  SetTensorData(dataset_points, radius, index_dtype);
33 };
34 
36 
37 bool FixedRadiusIndex::SetTensorData(const Tensor &dataset_points,
38  double radius,
39  const Dtype &index_dtype) {
40  const int64_t num_dataset_points = dataset_points.GetShape()[0];
41  Tensor points_row_splits(std::vector<int64_t>({0, num_dataset_points}), {2},
42  Int64);
43  return SetTensorData(dataset_points, points_row_splits, radius,
44  index_dtype);
45 }
46 
47 bool FixedRadiusIndex::SetTensorData(const Tensor &dataset_points,
48  const Tensor &points_row_splits,
49  double radius,
50  const Dtype &index_dtype) {
51  AssertTensorDtypes(dataset_points, {Float32, Float64});
52  assert(index_dtype == Int32 || index_dtype == Int64);
53  AssertTensorDevice(points_row_splits, Device("CPU:0"));
54  AssertTensorDtype(points_row_splits, Int64);
55 
56  if (radius <= 0) {
57  utility::LogError("radius should be positive.");
58  }
59  if (dataset_points.GetShape()[0] != points_row_splits[-1].Item<int64_t>()) {
61  "dataset_points and points_row_splits have incompatible "
62  "shapes.");
63  }
64 
65  dataset_points_ = dataset_points.Contiguous();
66  points_row_splits_ = points_row_splits.Contiguous();
67  index_dtype_ = index_dtype;
68 
69  const int64_t num_dataset_points = GetDatasetSize();
70  const int64_t num_batch = points_row_splits.GetShape()[0] - 1;
71  const Device device = GetDevice();
72  const Dtype dtype = GetDtype();
73 
74  std::vector<uint32_t> hash_table_splits(num_batch + 1, 0);
75  for (int i = 0; i < num_batch; ++i) {
76  int64_t num_dataset_points_i =
77  points_row_splits_[i + 1].Item<int64_t>() -
78  points_row_splits_[i].Item<int64_t>();
79  int64_t hash_table_size = std::min<int64_t>(
80  std::max<int64_t>(hash_table_size_factor * num_dataset_points_i,
81  1),
83  hash_table_splits[i + 1] =
84  hash_table_splits[i] + (uint32_t)hash_table_size;
85  }
86 
87  hash_table_splits_ = Tensor(hash_table_splits, {num_batch + 1}, UInt32);
88  hash_table_index_ = Tensor::Empty({num_dataset_points}, UInt32, device);
90  Tensor::Empty({hash_table_splits.back() + 1}, UInt32, device);
91 
92 #define BUILD_PARAMETERS \
93  dataset_points_, radius, points_row_splits_, hash_table_splits_, \
94  hash_table_index_, hash_table_cell_splits_
95 
96 #define CALL_BUILD(type, fn) \
97  if (Dtype::FromType<type>() == dtype) { \
98  fn<type>(BUILD_PARAMETERS); \
99  return true; \
100  }
101 
102  if (device.IsCUDA()) {
103 #ifdef BUILD_CUDA_MODULE
104  CALL_BUILD(float, BuildSpatialHashTableCUDA)
105  CALL_BUILD(double, BuildSpatialHashTableCUDA)
106 #else
108  "-DBUILD_CUDA_MODULE=OFF. Please compile Open3d with "
109  "-DBUILD_CUDA_MODULE=ON.");
110 #endif
111  } else {
114  }
115  return false;
116 };
117 
118 std::tuple<Tensor, Tensor, Tensor> FixedRadiusIndex::SearchRadius(
119  const Tensor &query_points, double radius, bool sort) const {
120  const int64_t num_query_points = query_points.GetShape()[0];
121  Tensor queries_row_splits(std::vector<int64_t>({0, num_query_points}), {2},
122  Int64);
123  return SearchRadius(query_points, queries_row_splits, radius, sort);
124 }
125 
126 std::tuple<Tensor, Tensor, Tensor> FixedRadiusIndex::SearchRadius(
127  const Tensor &query_points,
128  const Tensor &queries_row_splits,
129  double radius,
130  bool sort) const {
131  const Dtype dtype = GetDtype();
132  const Dtype index_dtype = GetIndexDtype();
133  const Device device = GetDevice();
134 
135  // Check device and dtype.
136  AssertTensorDevice(query_points, device);
137  AssertTensorDtype(query_points, dtype);
138  AssertTensorDevice(queries_row_splits, Device("CPU:0"));
139  AssertTensorDtype(queries_row_splits, Int64);
140 
141  // Check shape.
142  AssertTensorShape(query_points, {utility::nullopt, GetDimension()});
143  AssertTensorShape(queries_row_splits, points_row_splits_.GetShape());
144 
145  const int64_t num_query_points = query_points.GetShape()[0];
146  if (num_query_points != queries_row_splits[-1].Item<int64_t>()) {
148  "query_points and queries_row_splits have incompatible "
149  "shapes.");
150  }
151 
152  if (radius <= 0) {
153  utility::LogError("radius should be positive.");
154  }
155 
156  Tensor query_points_ = query_points.Contiguous();
157  Tensor queries_row_splits_ = queries_row_splits.Contiguous();
158 
159  Tensor neighbors_index, neighbors_distance;
160  Tensor neighbors_row_splits = Tensor({num_query_points + 1}, Int64, device);
161 
162 #define RADIUS_PARAMETERS \
163  dataset_points_, query_points_, radius, points_row_splits_, \
164  queries_row_splits_, hash_table_splits_, hash_table_index_, \
165  hash_table_cell_splits_, Metric::L2, false, true, sort, \
166  neighbors_index, neighbors_row_splits, neighbors_distance
167 
168  if (device.IsCUDA()) {
169 #ifdef BUILD_CUDA_MODULE
170  DISPATCH_FLOAT_INT_DTYPE_TO_TEMPLATE(dtype, index_dtype, [&]() {
171  FixedRadiusSearchCUDA<scalar_t, int_t>(RADIUS_PARAMETERS);
172  });
173 #else
175  "-DBUILD_CUDA_MODULE=OFF. Please compile Open3d with "
176  "-DBUILD_CUDA_MODULE=ON.");
177 #endif
178  } else {
179  DISPATCH_FLOAT_INT_DTYPE_TO_TEMPLATE(dtype, index_dtype, [&]() {
180  FixedRadiusSearchCPU<scalar_t, int_t>(RADIUS_PARAMETERS);
181  });
182  }
183 
184  return std::make_tuple(neighbors_index, neighbors_distance,
185  neighbors_row_splits.To(index_dtype));
186 };
187 
188 std::tuple<Tensor, Tensor, Tensor> FixedRadiusIndex::SearchHybrid(
189  const Tensor &query_points, double radius, int max_knn) const {
190  const int64_t num_query_points = query_points.GetShape()[0];
191  Tensor queries_row_splits(std::vector<int64_t>({0, num_query_points}), {2},
192  Int64);
193  return SearchHybrid(query_points, queries_row_splits, radius, max_knn);
194 }
195 
196 std::tuple<Tensor, Tensor, Tensor> FixedRadiusIndex::SearchHybrid(
197  const Tensor &query_points,
198  const Tensor &queries_row_splits,
199  double radius,
200  int max_knn) const {
201  const Dtype dtype = GetDtype();
202  const Dtype index_dtype = GetIndexDtype();
203  const Device device = GetDevice();
204 
205  // Check device and dtype.
206  AssertTensorDevice(query_points, device);
207  AssertTensorDtype(query_points, dtype);
208  AssertTensorDevice(queries_row_splits, Device("CPU:0"));
209  AssertTensorDtype(queries_row_splits, Int64);
210 
211  // Check shape.
212  AssertTensorShape(query_points, {utility::nullopt, GetDimension()});
213  AssertTensorShape(queries_row_splits, points_row_splits_.GetShape());
214 
215  const int64_t num_query_points = query_points.GetShape()[0];
216  if (num_query_points != queries_row_splits[-1].Item<int64_t>()) {
218  "query_points and queries_row_splits have incompatible "
219  "shapes.");
220  }
221 
222  if (radius <= 0) {
223  utility::LogError("radius should be positive.");
224  }
225 
226  Tensor query_points_ = query_points.Contiguous();
227  Tensor queries_row_splits_ = queries_row_splits.Contiguous();
228 
229  Tensor neighbors_index, neighbors_distance, neighbors_count;
230 
231 #define HYBRID_PARAMETERS \
232  dataset_points_, query_points_, radius, max_knn, points_row_splits_, \
233  queries_row_splits_, hash_table_splits_, hash_table_index_, \
234  hash_table_cell_splits_, Metric::L2, neighbors_index, \
235  neighbors_count, neighbors_distance
236 
237  if (device.IsCUDA()) {
238 #ifdef BUILD_CUDA_MODULE
239  DISPATCH_FLOAT_INT_DTYPE_TO_TEMPLATE(dtype, index_dtype, [&]() {
240  HybridSearchCUDA<scalar_t, int_t>(HYBRID_PARAMETERS);
241  });
242 #else
244  "-DBUILD_CUDA_MODULE=OFF. Please compile Open3d with "
245  "-DBUILD_CUDA_MODULE=ON.");
246 #endif
247  } else {
248  DISPATCH_FLOAT_INT_DTYPE_TO_TEMPLATE(dtype, index_dtype, [&]() {
249  HybridSearchCPU<scalar_t, int_t>(HYBRID_PARAMETERS);
250  });
251  }
252 
253  return std::make_tuple(neighbors_index.View({num_query_points, max_knn}),
254  neighbors_distance.View({num_query_points, max_knn}),
255  neighbors_count.View({num_query_points}));
256 }
257 
258 } // namespace nns
259 } // namespace core
260 } // namespace cloudViewer
#define DISPATCH_FLOAT_INT_DTYPE_TO_TEMPLATE(FDTYPE, IDTYPE,...)
Definition: Dispatch.h:91
#define CALL_BUILD(type, fn)
#define HYBRID_PARAMETERS
#define RADIUS_PARAMETERS
#define AssertTensorDevice(tensor,...)
Definition: TensorCheck.h:45
#define AssertTensorDtype(tensor,...)
Definition: TensorCheck.h:21
#define AssertTensorDtypes(tensor,...)
Definition: TensorCheck.h:33
#define AssertTensorShape(tensor,...)
Definition: TensorCheck.h:61
bool IsCUDA() const
Returns true iff device type is CUDA.
Definition: Device.h:49
Tensor Contiguous() const
Definition: Tensor.cpp:772
Tensor View(const SizeVector &dst_shape) const
Definition: Tensor.cpp:721
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
SizeVector GetShape() const
Definition: Tensor.h:1127
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
std::tuple< Tensor, Tensor, Tensor > SearchHybrid(const Tensor &query_points, double radius, int max_knn) const override
bool SetTensorData(const Tensor &dataset_points, const Dtype &index_dtype=core::Int64) override
std::tuple< Tensor, Tensor, Tensor > SearchRadius(const Tensor &query_points, const Tensor &radii, bool sort=true) const override
#define LogError(...)
Definition: Logging.h:60
void BuildSpatialHashTableCPU(const Tensor &points, double radius, const Tensor &points_row_splits, const Tensor &hash_table_splits, Tensor &hash_table_index, Tensor &hash_table_cell_splits)
const Dtype Int64
Definition: Dtype.cpp:47
const Dtype UInt32
Definition: Dtype.cpp:50
const Dtype Float64
Definition: Dtype.cpp:43
const Dtype Int32
Definition: Dtype.cpp:46
const Dtype Float32
Definition: Dtype.cpp:42
constexpr nullopt_t nullopt
Definition: Optional.h:136
Generic file read and write utility for python interface.