28 #include <tbb/parallel_for.h> 32 #include <nanoflann.hpp> 46 template <
int METRIC,
class TReal,
class TIndex>
52 const TReal *
const data_ptr)
74 template <
int M,
typename fake =
void>
77 template <
typename fake>
79 typedef nanoflann::L2_Adaptor<TReal, DataAdaptor, TReal>
adaptor_t;
82 template <
typename fake>
84 typedef nanoflann::L1_Adaptor<TReal, DataAdaptor, TReal>
adaptor_t;
88 typedef nanoflann::KDTreeSingleIndexAdaptor<
97 const TReal *data_ptr) {
109 template <
class T,
int METRIC>
110 void _BuildKdTree(
size_t num_points,
118 template <
class T,
class OUTPUT_ALLOCATOR,
int METRIC>
120 int64_t *query_neighbors_row_splits,
122 const T *
const points,
124 const T *
const queries,
125 const size_t dimension,
127 bool ignore_query_point,
128 bool return_distances,
129 OUTPUT_ALLOCATOR &output_allocator) {
131 if (num_queries == 0 || num_points == 0 || holder ==
nullptr) {
132 std::fill(query_neighbors_row_splits,
133 query_neighbors_row_splits + num_queries + 1, 0);
134 index_t *indices_ptr;
135 output_allocator.AllocIndices(&indices_ptr, 0);
138 output_allocator.AllocDistances(&distances_ptr, 0);
142 auto points_equal = [](
const T *
const p1,
const T *
const p2,
144 std::vector<T> p1_vec(p1, p1 + dimension);
145 std::vector<T> p2_vec(p2, p2 + dimension);
146 return p1_vec == p2_vec;
149 std::vector<std::vector<index_t>> neighbors_indices(num_queries);
150 std::vector<std::vector<T>> neighbors_distances(num_queries);
151 std::vector<uint32_t> neighbors_count(num_queries, 0);
158 tbb::blocked_range<size_t>(0, num_queries),
159 [&](
const tbb::blocked_range<size_t> &r) {
160 std::vector<index_t> result_indices(knn);
161 std::vector<T> result_distances(knn);
162 for (
size_t i = r.begin(); i != r.end(); ++i) {
163 size_t num_valid = holder_->index_->knnSearch(
164 &queries[i * dimension], knn, result_indices.data(),
165 result_distances.data());
167 int num_neighbors = 0;
168 for (
size_t valid_i = 0; valid_i < num_valid; ++valid_i) {
169 index_t idx = result_indices[valid_i];
170 if (ignore_query_point &&
171 points_equal(&queries[i * dimension],
172 &points[idx * dimension], dimension)) {
175 neighbors_indices[i].push_back(idx);
176 if (return_distances) {
177 T dist = result_distances[valid_i];
178 neighbors_distances[i].push_back(dist);
182 neighbors_count[i] = num_neighbors;
186 query_neighbors_row_splits[0] = 0;
188 neighbors_count.data() + neighbors_count.size(),
189 query_neighbors_row_splits + 1);
191 int64_t num_indices = query_neighbors_row_splits[num_queries];
193 index_t *indices_ptr;
194 output_allocator.AllocIndices(&indices_ptr, num_indices);
196 if (return_distances)
197 output_allocator.AllocDistances(&distances_ptr, num_indices);
199 output_allocator.AllocDistances(&distances_ptr, 0);
201 std::fill(neighbors_count.begin(), neighbors_count.end(), 0);
204 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_queries),
205 [&](
const tbb::blocked_range<size_t> &r) {
206 for (
size_t i = r.begin(); i != r.end(); ++i) {
207 int64_t start_idx = query_neighbors_row_splits[i];
208 std::copy(neighbors_indices[i].begin(),
209 neighbors_indices[i].end(),
210 &indices_ptr[start_idx]);
212 if (return_distances) {
213 std::copy(neighbors_distances[i].begin(),
214 neighbors_distances[i].end(),
215 &distances_ptr[start_idx]);
221 template <
class T,
class OUTPUT_ALLOCATOR,
int METRIC>
223 int64_t *query_neighbors_row_splits,
225 const T *
const points,
227 const T *
const queries,
228 const size_t dimension,
229 const T *
const radii,
230 bool ignore_query_point,
231 bool return_distances,
232 bool normalize_distances,
234 OUTPUT_ALLOCATOR &output_allocator) {
235 if (num_queries == 0 || num_points == 0 || holder ==
nullptr) {
236 std::fill(query_neighbors_row_splits,
237 query_neighbors_row_splits + num_queries + 1, 0);
238 index_t *indices_ptr;
239 output_allocator.AllocIndices(&indices_ptr, 0);
242 output_allocator.AllocDistances(&distances_ptr, 0);
246 auto points_equal = [](
const T *
const p1,
const T *
const p2,
248 std::vector<T> p1_vec(p1, p1 + dimension);
249 std::vector<T> p2_vec(p2, p2 + dimension);
250 return p1_vec == p2_vec;
253 std::vector<std::vector<index_t>> neighbors_indices(num_queries);
254 std::vector<std::vector<T>> neighbors_distances(num_queries);
255 std::vector<uint32_t> neighbors_count(num_queries, 0);
257 nanoflann::SearchParams params;
258 params.sorted = sort;
263 tbb::blocked_range<size_t>(0, num_queries),
264 [&](
const tbb::blocked_range<size_t> &r) {
265 std::vector<std::pair<index_t, T>> search_result;
266 for (
size_t i = r.begin(); i != r.end(); ++i) {
269 radius = radius * radius;
272 holder_->index_->radiusSearch(&queries[i * dimension],
273 radius, search_result,
276 int num_neighbors = 0;
277 for (
const auto &idx_dist : search_result) {
278 if (ignore_query_point &&
279 points_equal(&queries[i * dimension],
280 &points[idx_dist.first * dimension],
284 neighbors_indices[i].push_back(idx_dist.first);
285 if (return_distances) {
286 neighbors_distances[i].push_back(idx_dist.second);
290 neighbors_count[i] = num_neighbors;
294 query_neighbors_row_splits[0] = 0;
296 neighbors_count.data() + neighbors_count.size(),
297 query_neighbors_row_splits + 1);
299 int64_t num_indices = query_neighbors_row_splits[num_queries];
301 index_t *indices_ptr;
302 output_allocator.AllocIndices(&indices_ptr, num_indices);
304 if (return_distances)
305 output_allocator.AllocDistances(&distances_ptr, num_indices);
307 output_allocator.AllocDistances(&distances_ptr, 0);
309 std::fill(neighbors_count.begin(), neighbors_count.end(), 0);
313 tbb::blocked_range<size_t>(0, num_queries),
314 [&](
const tbb::blocked_range<size_t> &r) {
315 for (
size_t i = r.begin(); i != r.end(); ++i) {
316 int64_t start_idx = query_neighbors_row_splits[i];
317 std::copy(neighbors_indices[i].begin(),
318 neighbors_indices[i].end(),
319 &indices_ptr[start_idx]);
320 if (return_distances) {
321 std::transform(neighbors_distances[i].begin(),
322 neighbors_distances[i].end(),
323 &distances_ptr[start_idx], [&](T dist) {
325 if (normalize_distances) {
327 d /= (radii[i] * radii[i]);
339 template <
class T,
class OUTPUT_ALLOCATOR,
int METRIC>
342 const T *
const points,
344 const T *
const queries,
345 const size_t dimension,
348 bool ignore_query_point,
349 bool return_distances,
350 OUTPUT_ALLOCATOR &output_allocator) {
351 if (num_queries == 0 || num_points == 0 || holder ==
nullptr) {
352 index_t *indices_ptr, *counts_ptr;
353 output_allocator.AllocIndices(&indices_ptr, 0);
354 output_allocator.AllocCounts(&counts_ptr, 0);
357 output_allocator.AllocDistances(&distances_ptr, 0);
361 T radius_squared = radius * radius;
362 index_t *indices_ptr, *counts_ptr;
365 size_t num_indices =
static_cast<size_t>(max_knn) * num_queries;
366 output_allocator.AllocIndices(&indices_ptr, num_indices);
367 output_allocator.AllocDistances(&distances_ptr, num_indices);
368 output_allocator.AllocCounts(&counts_ptr, num_queries);
370 nanoflann::SearchParams params;
371 params.sorted =
true;
376 tbb::blocked_range<size_t>(0, num_queries),
377 [&](
const tbb::blocked_range<size_t> &r) {
378 std::vector<std::pair<index_t, T>> ret_matches;
379 for (
size_t i = r.begin(); i != r.end(); ++i) {
380 size_t num_results = holder_->index_->radiusSearch(
381 &queries[i * dimension], radius_squared,
382 ret_matches, params);
383 ret_matches.resize(num_results);
385 index_t count_i =
static_cast<index_t
>(num_results);
386 count_i = count_i < max_knn ? count_i : max_knn;
387 counts_ptr[i] = count_i;
389 int neighbor_idx = 0;
390 for (
auto it = ret_matches.begin();
391 it < ret_matches.end() && neighbor_idx < max_knn;
392 it++, neighbor_idx++) {
393 indices_ptr[i * max_knn + neighbor_idx] = it->first;
394 distances_ptr[i * max_knn + neighbor_idx] = it->second;
397 while (neighbor_idx < max_knn) {
398 indices_ptr[i * max_knn + neighbor_idx] = -1;
399 distances_ptr[i * max_knn + neighbor_idx] = 0;
423 std::unique_ptr<NanoFlannIndexHolderBase>
BuildKdTree(
size_t num_points,
428 #define FN_PARAMETERS num_points, points, dimension, &holder 430 #define CALL_TEMPLATE(METRIC) \ 431 if (METRIC == metric) { \ 432 _BuildKdTree<T, METRIC>(FN_PARAMETERS); \ 435 #define CALL_TEMPLATE2 \ 442 #undef CALL_TEMPLATE2 445 return std::unique_ptr<NanoFlannIndexHolderBase>(holder);
500 template <
class T,
class OUTPUT_ALLOCATOR>
502 int64_t *query_neighbors_row_splits,
506 const T *
const queries,
507 const size_t dimension,
510 bool ignore_query_point,
511 bool return_distances,
512 OUTPUT_ALLOCATOR &output_allocator) {
513 #define FN_PARAMETERS \ 514 holder, query_neighbors_row_splits, num_points, points, num_queries, \ 515 queries, dimension, knn, ignore_query_point, return_distances, \ 518 #define CALL_TEMPLATE(METRIC) \ 519 if (METRIC == metric) { \ 520 _KnnSearchCPU<T, OUTPUT_ALLOCATOR, METRIC>(FN_PARAMETERS); \ 523 #define CALL_TEMPLATE2 \ 530 #undef CALL_TEMPLATE2 594 template <
class T,
class OUTPUT_ALLOCATOR>
596 int64_t *query_neighbors_row_splits,
600 const T *
const queries,
601 const size_t dimension,
602 const T *
const radii,
604 bool ignore_query_point,
605 bool return_distances,
606 bool normalize_distances,
608 OUTPUT_ALLOCATOR &output_allocator) {
609 #define FN_PARAMETERS \ 610 holder, query_neighbors_row_splits, num_points, points, num_queries, \ 611 queries, dimension, radii, ignore_query_point, return_distances, \ 612 normalize_distances, sort, output_allocator 614 #define CALL_TEMPLATE(METRIC) \ 615 if (METRIC == metric) { \ 616 _RadiusSearchCPU<T, OUTPUT_ALLOCATOR, METRIC>(FN_PARAMETERS); \ 619 #define CALL_TEMPLATE2 \ 626 #undef CALL_TEMPLATE2 682 template <
class T,
class OUTPUT_ALLOCATOR>
687 const T *
const queries,
688 const size_t dimension,
692 bool ignore_query_point,
693 bool return_distances,
694 OUTPUT_ALLOCATOR &output_allocator) {
695 #define FN_PARAMETERS \ 696 holder, num_points, points, num_queries, queries, dimension, radius, \ 697 max_knn, ignore_query_point, return_distances, output_allocator 699 #define CALL_TEMPLATE(METRIC) \ 700 if (METRIC == metric) { \ 701 _HybridSearchCPU<T, OUTPUT_ALLOCATOR, METRIC>(FN_PARAMETERS); \ 704 #define CALL_TEMPLATE2 \ 711 #undef CALL_TEMPLATE2 bool kdtree_get_bbox(BBOX &) const
Definition: NanoFlannImpl.h:64
Definition: NeighborSearchCommon.h:38
std::unique_ptr< KDTree_t > index_
Definition: NanoFlannImpl.h:103
std::unique_ptr< NanoFlannIndexHolderBase > BuildKdTree(size_t num_points, const T *const points, size_t dimension, const Metric metric)
Definition: NanoFlannImpl.h:423
Base struct for NanoFlann index holder.
Definition: NeighborSearchCommon.h:72
std::unique_ptr< DataAdaptor > adaptor_
Definition: NanoFlannImpl.h:104
void InclusivePrefixSum(const Tin *first, const Tin *last, Tout *out)
Definition: ParallelScan.h:85
void RadiusSearchCPU(NanoFlannIndexHolderBase *holder, int64_t *query_neighbors_row_splits, size_t num_points, const T *const points, size_t num_queries, const T *const queries, const size_t dimension, const T *const radii, const Metric metric, bool ignore_query_point, bool return_distances, bool normalize_distances, bool sort, OUTPUT_ALLOCATOR &output_allocator)
Definition: NanoFlannImpl.h:595
Metric
Supported metrics.
Definition: NeighborSearchCommon.h:38
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:408
const TReal *const data_ptr_
Definition: NanoFlannImpl.h:70
size_t dataset_size_
Definition: NanoFlannImpl.h:68
NanoFlann Index Holder.
Definition: NanoFlannImpl.h:47
void KnnSearchCPU(NanoFlannIndexHolderBase *holder, int64_t *query_neighbors_row_splits, size_t num_points, const T *const points, size_t num_queries, const T *const queries, const size_t dimension, int knn, const Metric metric, bool ignore_query_point, bool return_distances, OUTPUT_ALLOCATOR &output_allocator)
Definition: NanoFlannImpl.h:501
Definition: NeighborSearchCommon.h:38
void HybridSearchCPU(const Tensor &points, const Tensor &queries, double radius, int max_knn, const Tensor &points_row_splits, const Tensor &queries_row_splits, const Tensor &hash_table_splits, const Tensor &hash_table_index, const Tensor &hash_table_cell_splits, const Metric metric, Tensor &neighbors_index, Tensor &neighbors_count, Tensor &neighbors_distance)
Definition: FixedRadiusSearchOps.cpp:93
Adaptor Selector.
Definition: NanoFlannImpl.h:75
int32_t index_t
Definition: NanoFlannImpl.h:43
This class is the Adaptor for connecting Open3D Tensor and NanoFlann.
Definition: NanoFlannImpl.h:49
NanoFlannIndexHolder(size_t dataset_size, int dimension, const TReal *data_ptr)
Definition: NanoFlannImpl.h:95
nanoflann::L2_Adaptor< TReal, DataAdaptor, TReal > adaptor_t
Definition: NanoFlannImpl.h:79
DataAdaptor(size_t dataset_size, int dimension, const TReal *const data_ptr)
Definition: NanoFlannImpl.h:50
nanoflann::L1_Adaptor< TReal, DataAdaptor, TReal > adaptor_t
Definition: NanoFlannImpl.h:84
Definition: PinholeCameraIntrinsic.cpp:35
nanoflann::KDTreeSingleIndexAdaptor< typename SelectNanoflannAdaptor< METRIC >::adaptor_t, DataAdaptor, -1, TIndex > KDTree_t
typedef for KDtree.
Definition: NanoFlannImpl.h:93
size_t kdtree_get_point_count() const
Definition: NanoFlannImpl.h:57
TReal kdtree_get_pt(const size_t idx, const size_t dim) const
Definition: NanoFlannImpl.h:59
int dimension_
Definition: NanoFlannImpl.h:69