Loading [MathJax]/jax/output/HTML-CSS/config.js
Open3D (C++ API)  0.19.0
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
FeatureImpl.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - Open3D: www.open3d.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.open3d.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 #include "open3d/core/Dispatch.h"
13 
14 namespace open3d {
15 namespace t {
16 namespace pipelines {
17 namespace kernel {
18 
19 #ifndef __CUDACC__
20 using std::max;
21 using std::min;
22 #endif
23 
24 template <typename scalar_t>
25 OPEN3D_HOST_DEVICE void ComputePairFeature(const scalar_t *p1,
26  const scalar_t *n1,
27  const scalar_t *p2,
28  const scalar_t *n2,
29  scalar_t *feature) {
30  scalar_t dp2p1[3], n1_copy[3], n2_copy[3];
31  dp2p1[0] = p2[0] - p1[0];
32  dp2p1[1] = p2[1] - p1[1];
33  dp2p1[2] = p2[2] - p1[2];
34  feature[3] = sqrt(dp2p1[0] * dp2p1[0] + dp2p1[1] * dp2p1[1] +
35  dp2p1[2] * dp2p1[2]);
36  if (feature[3] == 0) {
37  feature[0] = 0;
38  feature[1] = 0;
39  feature[2] = 0;
40  feature[3] = 0;
41  return;
42  }
43 
44  scalar_t angle1 = core::linalg::kernel::dot_3x1(n1, dp2p1) / feature[3];
45  scalar_t angle2 = core::linalg::kernel::dot_3x1(n2, dp2p1) / feature[3];
46  if (acos(fabs(angle1)) > acos(fabs(angle2))) {
47  n1_copy[0] = n2[0];
48  n1_copy[1] = n2[1];
49  n1_copy[2] = n2[2];
50  n2_copy[0] = n1[0];
51  n2_copy[1] = n1[1];
52  n2_copy[2] = n1[2];
53  dp2p1[0] *= -1;
54  dp2p1[1] *= -1;
55  dp2p1[2] *= -1;
56  feature[2] = -angle2;
57  } else {
58  n1_copy[0] = n1[0];
59  n1_copy[1] = n1[1];
60  n1_copy[2] = n1[2];
61  n2_copy[0] = n2[0];
62  n2_copy[1] = n2[1];
63  n2_copy[2] = n2[2];
64  feature[2] = angle1;
65  }
66 
67  scalar_t v[3];
68  core::linalg::kernel::cross_3x1(dp2p1, n1_copy, v);
69  const scalar_t v_norm = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
70  if (v_norm == 0.0) {
71  feature[0] = 0.0;
72  feature[1] = 0.0;
73  feature[2] = 0.0;
74  feature[3] = 0.0;
75  return;
76  }
77  v[0] /= v_norm;
78  v[1] /= v_norm;
79  v[2] /= v_norm;
80  scalar_t w[3];
81  core::linalg::kernel::cross_3x1(n1_copy, v, w);
82  feature[1] = core::linalg::kernel::dot_3x1(v, n2_copy);
83  feature[0] = atan2(core::linalg::kernel::dot_3x1(w, n2_copy),
84  core::linalg::kernel::dot_3x1(n1_copy, n2_copy));
85 }
86 
87 template <typename scalar_t>
88 OPEN3D_HOST_DEVICE void UpdateSPFHFeature(const scalar_t *feature,
89  int64_t idx,
90  scalar_t hist_incr,
91  scalar_t *spfh) {
92  int h_index1 =
93  static_cast<int>(floor(11 * (feature[0] + M_PI) / (2.0 * M_PI)));
94  h_index1 = h_index1 >= 11 ? 10 : max(0, h_index1);
95 
96  int h_index2 = static_cast<int>(floor(11 * (feature[1] + 1.0) * 0.5));
97  h_index2 = h_index2 >= 11 ? 10 : max(0, h_index2);
98 
99  int h_index3 = static_cast<int>(floor(11 * (feature[2] + 1.0) * 0.5));
100  h_index3 = h_index3 >= 11 ? 10 : max(0, h_index3);
101 
102  spfh[idx * 33 + h_index1] += hist_incr;
103  spfh[idx * 33 + h_index2 + 11] += hist_incr;
104  spfh[idx * 33 + h_index3 + 22] += hist_incr;
105 }
106 
107 #if defined(__CUDACC__)
108 void ComputeFPFHFeatureCUDA
109 #else
111 #endif
112  (const core::Tensor &points,
113  const core::Tensor &normals,
114  const core::Tensor &indices,
115  const core::Tensor &distance2,
116  const core::Tensor &counts,
117  core::Tensor &fpfhs,
119  const utility::optional<core::Tensor> &map_info_idx_to_point_idx) {
120  const core::Dtype dtype = points.GetDtype();
121  const core::Device device = points.GetDevice();
122  const int64_t n_points = points.GetLength();
123 
124  const bool filter_fpfh =
125  mask.has_value() && map_info_idx_to_point_idx.has_value();
126  if (mask.has_value() ^ map_info_idx_to_point_idx.has_value()) {
128  "Parameters mask and map_info_idx_to_point_idx must "
129  "either be both provided or both not provided.");
130  }
131  if (filter_fpfh) {
132  if (mask.value().GetShape()[0] != n_points) {
134  "Parameter mask was provided, but its size {:d} should"
135  "be equal to the number of points {:d}.",
136  (int)mask.value().GetShape()[0], n_points);
137  }
138  if (map_info_idx_to_point_idx.value().GetShape()[0] !=
139  counts.GetShape()[0] - (indices.GetShape().size() == 1 ? 1 : 0)) {
141  "Parameter map_info_idx_to_point_idx was provided, "
142  "but its size"
143  "{:d} should be equal to the size of counts {:d}.",
144  (int)map_info_idx_to_point_idx.value().GetShape()[0],
145  (int)counts.GetShape()[0]);
146  }
147  }
148 
149  core::Tensor map_spfh_info_idx_to_point_idx =
150  map_info_idx_to_point_idx.value_or(
151  core::Tensor::Empty({0}, core::Int64, device));
152 
153  const core::Tensor map_fpfh_idx_to_point_idx =
154  filter_fpfh ? mask.value().NonZero().GetItem(
156  : core::Tensor::Empty({0}, core::Int64, device);
157 
158  const int32_t n_fpfh =
159  filter_fpfh ? map_fpfh_idx_to_point_idx.GetLength() : n_points;
160  const int32_t n_spfh =
161  filter_fpfh ? map_spfh_info_idx_to_point_idx.GetLength() : n_points;
162 
163  core::Tensor spfhs =
164  core::Tensor::Zeros({n_spfh, 33}, dtype, fpfhs.GetDevice());
165 
166  core::Tensor map_point_idx_to_spfh_idx;
167  if (filter_fpfh) {
168  map_point_idx_to_spfh_idx = core::Tensor::Full(
169  {n_points}, -1, core::Int64, fpfhs.GetDevice());
170  map_point_idx_to_spfh_idx.IndexSet(
171  {map_spfh_info_idx_to_point_idx},
172  core::Tensor::Arange(0, n_spfh, 1, core::Int64,
173  fpfhs.GetDevice()));
174  } else {
175  map_point_idx_to_spfh_idx =
176  core::Tensor::Empty({0}, core::Int64, fpfhs.GetDevice());
177  }
178 
179  // Check the nns type (knn = hybrid = false, radius = true).
180  // The nns radius search mode will resulting a prefix sum 1D tensor.
181  bool is_radius_search;
182  int nn_size = 0;
183  if (indices.GetShape().size() == 1) {
184  is_radius_search = true;
185  } else {
186  is_radius_search = false;
187  nn_size = indices.GetShape()[1];
188  }
189 
190  DISPATCH_FLOAT_DTYPE_TO_TEMPLATE(dtype, [&]() {
191  const scalar_t *points_ptr = points.GetDataPtr<scalar_t>();
192  const scalar_t *normals_ptr = normals.GetDataPtr<scalar_t>();
193  const int32_t *indices_ptr = indices.GetDataPtr<int32_t>();
194  const scalar_t *distance2_ptr = distance2.GetDataPtr<scalar_t>();
195  const int32_t *counts_ptr = counts.GetDataPtr<int32_t>();
196  scalar_t *spfhs_ptr = spfhs.GetDataPtr<scalar_t>();
197  scalar_t *fpfhs_ptr = fpfhs.GetDataPtr<scalar_t>();
198  const int64_t *map_spfh_info_idx_to_point_idx_ptr =
199  map_spfh_info_idx_to_point_idx.GetDataPtr<int64_t>();
200  const int64_t *map_fpfh_idx_to_point_idx_ptr =
201  map_fpfh_idx_to_point_idx.GetDataPtr<int64_t>();
202  const int64_t *map_point_idx_to_spfh_idx_ptr =
203  map_point_idx_to_spfh_idx.GetDataPtr<int64_t>();
204 
205  // Compute SPFH features for the points.
207  points.GetDevice(), n_spfh,
208  [=] OPEN3D_DEVICE(int64_t workload_idx) {
209  int64_t workload_point_idx =
210  filter_fpfh ? map_spfh_info_idx_to_point_idx_ptr
211  [workload_idx]
212  : workload_idx;
213  int64_t idx = 3 * workload_point_idx;
214  const scalar_t *point = points_ptr + idx;
215  const scalar_t *normal = normals_ptr + idx;
216 
217  const int indice_size =
218  is_radius_search ? (counts_ptr[workload_idx + 1] -
219  counts_ptr[workload_idx])
220  : counts_ptr[workload_idx];
221 
222  if (indice_size > 1) {
223  const scalar_t hist_incr =
224  100.0 / static_cast<scalar_t>(indice_size - 1);
225  for (int i = 1; i < indice_size; i++) {
226  const int point_idx =
227  is_radius_search
228  ? indices_ptr
229  [i +
230  counts_ptr[workload_idx]]
231  : indices_ptr[workload_idx *
232  nn_size +
233  i];
234 
235  const scalar_t *point_ref =
236  points_ptr + 3 * point_idx;
237  const scalar_t *normal_ref =
238  normals_ptr + 3 * point_idx;
239  scalar_t fea[4] = {0};
240  ComputePairFeature<scalar_t>(
241  point, normal, point_ref, normal_ref, fea);
242  UpdateSPFHFeature<scalar_t>(fea, workload_idx,
243  hist_incr, spfhs_ptr);
244  }
245  }
246  });
247 
248  // Compute FPFH features for the points.
250  points.GetDevice(), n_fpfh,
251  [=] OPEN3D_DEVICE(int64_t workload_idx) {
252  int64_t workload_spfh_idx =
253  filter_fpfh ? map_point_idx_to_spfh_idx_ptr
254  [map_fpfh_idx_to_point_idx_ptr
255  [workload_idx]]
256  : workload_idx;
257  const int indice_size =
258  is_radius_search
259  ? (counts_ptr[workload_spfh_idx + 1] -
260  counts_ptr[workload_spfh_idx])
261  : counts_ptr[workload_spfh_idx];
262  if (indice_size > 1) {
263  scalar_t sum[3] = {0.0, 0.0, 0.0};
264  for (int i = 1; i < indice_size; i++) {
265  const int idx =
266  is_radius_search
267  ? i + counts_ptr[workload_spfh_idx]
268  : workload_spfh_idx * nn_size + i;
269  const scalar_t dist = distance2_ptr[idx];
270  if (dist == 0.0) continue;
271  const int32_t spfh_idx =
272  filter_fpfh ? map_point_idx_to_spfh_idx_ptr
273  [indices_ptr[idx]]
274  : indices_ptr[idx];
275  for (int j = 0; j < 33; j++) {
276  const scalar_t val =
277  spfhs_ptr[spfh_idx * 33 + j] / dist;
278  sum[j / 11] += val;
279  fpfhs_ptr[workload_idx * 33 + j] += val;
280  }
281  }
282  for (int j = 0; j < 3; j++) {
283  sum[j] = sum[j] != 0.0 ? 100.0 / sum[j] : 0.0;
284  }
285  for (int j = 0; j < 33; j++) {
286  fpfhs_ptr[workload_idx * 33 + j] *= sum[j / 11];
287  fpfhs_ptr[workload_idx * 33 + j] +=
288  spfhs_ptr[workload_spfh_idx * 33 + j];
289  }
290  }
291  });
292  });
293 }
294 
295 } // namespace kernel
296 } // namespace pipelines
297 } // namespace t
298 } // namespace open3d
Common CUDA utilities.
#define OPEN3D_HOST_DEVICE
Definition: CUDAUtils.h:44
#define OPEN3D_DEVICE
Definition: CUDAUtils.h:45
#define DISPATCH_FLOAT_DTYPE_TO_TEMPLATE(DTYPE,...)
Definition: Dispatch.h:77
#define LogError(...)
Definition: Logging.h:51
double t
Definition: SurfaceReconstructionPoisson.cpp:172
Point< Real, 3 > point
Definition: SurfaceReconstructionPoisson.cpp:163
Definition: Device.h:18
Definition: Dtype.h:20
Definition: Tensor.h:32
T * GetDataPtr()
Definition: Tensor.h:1143
Tensor NonZero() const
Definition: Tensor.cpp:1723
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:368
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.
Definition: Tensor.cpp:404
int64_t GetLength() const
Definition: Tensor.h:1124
static Tensor Full(const SizeVector &shape, T fill_value, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with specified value.
Definition: Tensor.h:252
static Tensor Zeros(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with zeros.
Definition: Tensor.cpp:374
Tensor GetItem(const TensorKey &tk) const
Definition: Tensor.cpp:441
void IndexSet(const std::vector< Tensor > &index_tensors, const Tensor &src_tensor)
Advanced indexing getter.
Definition: Tensor.cpp:904
static TensorKey Index(int64_t index)
Definition: TensorKey.cpp:133
Definition: Optional.h:259
int points
Definition: FilePCD.cpp:54
OPEN3D_HOST_DEVICE OPEN3D_FORCE_INLINE void cross_3x1(const scalar_t *A_3x1_input, const scalar_t *B_3x1_input, scalar_t *C_3x1_output)
Definition: Matrix.h:63
OPEN3D_HOST_DEVICE OPEN3D_FORCE_INLINE scalar_t dot_3x1(const scalar_t *A_3x1_input, const scalar_t *B_3x1_input)
Definition: Matrix.h:89
const Dtype Int64
Definition: Dtype.cpp:47
void ParallelFor(const Device &device, int64_t n, const func_t &func)
Definition: ParallelFor.h:108
const char const char value recording_handle imu_sample recording_handle uint8_t size_t data_size k4a_record_configuration_t config target_format k4a_capture_t capture_handle k4a_imu_sample_t imu_sample playback_handle k4a_logging_message_cb_t void min_level device_handle k4a_imu_sample_t int32_t
Definition: K4aPlugin.cpp:395
OPEN3D_HOST_DEVICE void ComputePairFeature(const scalar_t *p1, const scalar_t *n1, const scalar_t *p2, const scalar_t *n2, scalar_t *feature)
Definition: FeatureImpl.h:25
void ComputeFPFHFeatureCPU(const core::Tensor &points, const core::Tensor &normals, const core::Tensor &indices, const core::Tensor &distance2, const core::Tensor &counts, core::Tensor &fpfhs, const utility::optional< core::Tensor > &mask=utility::nullopt, const utility::optional< core::Tensor > &map_batch_info_idx_to_point_idx=utility::nullopt)
Definition: FeatureImpl.h:112
OPEN3D_HOST_DEVICE void UpdateSPFHFeature(const scalar_t *feature, int64_t idx, scalar_t hist_incr, scalar_t *spfh)
Definition: FeatureImpl.h:88
FN_SPECIFIERS MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
Definition: PinholeCameraIntrinsic.cpp:16