ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvKDTreeFlann.h
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 #pragma once
9 
10 #include <Eigen/Core>
11 #include <memory>
12 #include <nanoflann.hpp>
13 #include <vector>
14 
15 #include "ecvFeature.h"
16 #include "ecvHObject.h"
17 #include "ecvKDTreeSearchParam.h"
18 
20 namespace nanoflann {
21 struct metric_L2;
22 template <class MatrixType, int DIM, class Distance, bool row_major>
23 struct KDTreeEigenMatrixAdaptor;
24 } // namespace nanoflann
26 
27 namespace cloudViewer {
28 namespace geometry {
29 
34 public:
40  KDTreeFlann(const Eigen::MatrixXd &data);
44  KDTreeFlann(const ccHObject &geometry);
49  KDTreeFlann(const utility::Feature &feature);
51  KDTreeFlann(const KDTreeFlann &) = delete;
52  KDTreeFlann &operator=(const KDTreeFlann &) = delete;
53 
54 public:
58  bool SetMatrixData(const Eigen::MatrixXd &data);
62  bool SetGeometry(const ccHObject &geometry);
66  bool SetFeature(const utility::Feature &feature);
67 
68  template <typename T>
69  int Search(const T &query,
70  const KDTreeSearchParam &param,
71  std::vector<int> &indices,
72  std::vector<double> &distance2) const {
73  switch (param.GetSearchType()) {
75  return SearchKNN(query,
76  ((const KDTreeSearchParamKNN &)param).knn_,
77  indices, distance2);
79  return SearchRadius(
80  query, ((const KDTreeSearchParamRadius &)param).radius_,
81  indices, distance2);
83  return SearchHybrid(
84  query, ((const KDTreeSearchParamHybrid &)param).radius_,
85  ((const KDTreeSearchParamHybrid &)param).max_nn_,
86  indices, distance2);
87  default:
88  return -1;
89  }
90  return -1;
91  }
92 
93  template <typename T>
94  int Query(const std::vector<T> &queries,
95  const KDTreeSearchParam &param,
96  std::vector<std::vector<int>> &indices,
97  std::vector<std::vector<double>> &distance2) const {
98  // precompute all neighbours with given queries
99  indices.resize(queries.size());
100  distance2.resize(queries.size());
101  int flag = 1;
102 
103 #ifdef _OPENMP
104 #pragma omp parallel for schedule(static)
105 #endif
106  for (int idx = 0; idx < int(queries.size()); ++idx) {
107  int k = Search(queries[idx], param, indices[idx], distance2[idx]);
108  if (k < 0) {
109  flag = -1;
110  }
111  }
112 
113  if (flag < 0) {
114  utility::LogWarning("[Query] some queries failed!");
115  }
116 
117  return flag;
118  }
119 
120  template <typename T>
121  int SearchKNN(const T &query,
122  int knn,
123  std::vector<int> &indices,
124  std::vector<double> &distance2) const {
125  // This is optimized code for heavily repeated search.
126  // Other flann::Index::knnSearch() implementations lose performance due
127  // to memory allocation/deallocation.
128  if (data_.empty() || dataset_size_ <= 0 ||
129  size_t(query.rows()) != dimension_ || knn < 0) {
130  return -1;
131  }
132  indices.resize(knn);
133  distance2.resize(knn);
134  std::vector<Eigen::Index> indices_eigen(knn);
135  int k = nanoflann_index_->index_->knnSearch(
136  query.data(), knn, indices_eigen.data(), distance2.data());
137  indices.resize(k);
138  distance2.resize(k);
139  std::copy_n(indices_eigen.begin(), k, indices.begin());
140  return k;
141  }
142 
143  template <typename T>
144  int SearchRadius(const T &query,
145  double radius,
146  std::vector<int> &indices,
147  std::vector<double> &distance2) const {
148  // This is optimized code for heavily repeated search.
149  // Since max_nn is not given, we let flann to do its own memory
150  // management. Other flann::Index::radiusSearch() implementations lose
151  // performance due to memory management and CPU caching.
152  if (data_.empty() || dataset_size_ <= 0 ||
153  size_t(query.rows()) != dimension_) {
154  return -1;
155  }
156  std::vector<nanoflann::ResultItem<Eigen::Index, double>> indices_dists;
157  int k = nanoflann_index_->index_->radiusSearch(
158  query.data(), radius * radius, indices_dists,
159  nanoflann::SearchParameters(0.0));
160  indices.resize(k);
161  distance2.resize(k);
162  for (int i = 0; i < k; ++i) {
163  indices[i] = indices_dists[i].first;
164  distance2[i] = indices_dists[i].second;
165  }
166  return k;
167  }
168 
169  template <typename T>
170  int SearchHybrid(const T &query,
171  double radius,
172  int max_nn,
173  std::vector<int> &indices,
174  std::vector<double> &distance2) const {
175  // This is optimized code for heavily repeated search.
176  // It is also the recommended setting for search.
177  // Other flann::Index::radiusSearch() implementations lose performance
178  // due to memory allocation/deallocation.
179  if (data_.empty() || dataset_size_ <= 0 ||
180  size_t(query.rows()) != dimension_ || max_nn < 0) {
181  return -1;
182  }
183  distance2.resize(max_nn);
184  std::vector<Eigen::Index> indices_eigen(max_nn);
185  int k = nanoflann_index_->index_->knnSearch(
186  query.data(), max_nn, indices_eigen.data(), distance2.data());
187  k = std::distance(
188  distance2.begin(),
189  std::lower_bound(distance2.begin(), distance2.begin() + k,
190  radius * radius));
191  indices.resize(k);
192  distance2.resize(k);
193  std::copy_n(indices_eigen.begin(), k, indices.begin());
194  return k;
195  }
196 
197 private:
202  bool SetRawData(const Eigen::Map<const Eigen::MatrixXd> &data);
203 
204 protected:
205  using KDTree_t = nanoflann::KDTreeEigenMatrixAdaptor<
206  Eigen::Map<const Eigen::MatrixXd>,
207  -1,
208  nanoflann::metric_L2,
209  false>;
210 
211  std::vector<double> data_;
212  std::unique_ptr<KDTree_t> nanoflann_index_;
213  std::unique_ptr<Eigen::Map<const Eigen::MatrixXd>> data_interface_;
214  size_t dimension_ = 0;
215  size_t dataset_size_ = 0;
216 };
217 
218 } // namespace geometry
219 } // namespace cloudViewer
#define CV_DB_LIB_API
Definition: CV_db.h:15
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
KDTree with FLANN for nearest neighbor search.
int SearchRadius(const T &query, double radius, std::vector< int > &indices, std::vector< double > &distance2) const
bool SetMatrixData(const Eigen::MatrixXd &data)
bool SetFeature(const utility::Feature &feature)
KDTreeFlann(const KDTreeFlann &)=delete
int SearchKNN(const T &query, int knn, std::vector< int > &indices, std::vector< double > &distance2) const
int SearchHybrid(const T &query, double radius, int max_nn, std::vector< int > &indices, std::vector< double > &distance2) const
KDTreeFlann(const Eigen::MatrixXd &data)
Parameterized Constructor.
std::unique_ptr< KDTree_t > nanoflann_index_
int Query(const std::vector< T > &queries, const KDTreeSearchParam &param, std::vector< std::vector< int >> &indices, std::vector< std::vector< double >> &distance2) const
KDTreeFlann()
Default Constructor.
std::unique_ptr< Eigen::Map< const Eigen::MatrixXd > > data_interface_
KDTreeFlann & operator=(const KDTreeFlann &)=delete
int Search(const T &query, const KDTreeSearchParam &param, std::vector< int > &indices, std::vector< double > &distance2) const
KDTreeFlann(const utility::Feature &feature)
Parameterized Constructor.
bool SetGeometry(const ccHObject &geometry)
nanoflann::KDTreeEigenMatrixAdaptor< Eigen::Map< const Eigen::MatrixXd >, -1, nanoflann::metric_L2, false > KDTree_t
KDTreeFlann(const ccHObject &geometry)
Parameterized Constructor.
KDTree search parameters for hybrid KNN and radius search.
KDTree search parameters for pure KNN search.
KDTree search parameters for pure radius search.
Base class for KDTree search parameters.
SearchType GetSearchType() const
Get the search type (KNN, Radius, Hybrid) for the search parameter.
Class to store featrues for registration.
Definition: ecvFeature.h:29
#define LogWarning(...)
Definition: Logging.h:72
Generic file read and write utility for python interface.