ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
neighbors.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 
8 #include "ml/contrib/neighbors.h"
9 
10 namespace cloudViewer {
11 namespace ml {
12 namespace contrib {
13 
14 void brute_neighbors(std::vector<PointXYZ>& queries,
15  std::vector<PointXYZ>& supports,
16  std::vector<int>& neighbors_indices,
17  float radius,
18  int verbose) {
19  // Initiate variables
20  // ******************
21 
22  // square radius
23  float r2 = radius * radius;
24 
25  // indices
26  int i0 = 0;
27 
28  // Counting vector
29  int max_count = 0;
30  std::vector<std::vector<int>> tmp(queries.size());
31 
32  // Search neigbors indices
33  // ***********************
34 
35  for (auto& p0 : queries) {
36  int i = 0;
37  for (auto& p : supports) {
38  if ((p0 - p).sq_norm() < r2) {
39  tmp[i0].push_back(i);
40  if ((signed)tmp[i0].size() > max_count)
41  max_count = tmp[i0].size();
42  }
43  i++;
44  }
45  i0++;
46  }
47 
48  // Reserve the memory
49  neighbors_indices.resize(queries.size() * max_count);
50  i0 = 0;
51  for (auto& inds : tmp) {
52  for (int j = 0; j < max_count; j++) {
53  if (j < (signed)inds.size())
54  neighbors_indices[i0 * max_count + j] = inds[j];
55  else
56  neighbors_indices[i0 * max_count + j] = -1;
57  }
58  i0++;
59  }
60 
61  return;
62 }
63 
64 void ordered_neighbors(std::vector<PointXYZ>& queries,
65  std::vector<PointXYZ>& supports,
66  std::vector<int>& neighbors_indices,
67  float radius) {
68  // Initiate variables
69  // ******************
70 
71  // square radius
72  float r2 = radius * radius;
73 
74  // indices
75  int i0 = 0;
76 
77  // Counting vector
78  int max_count = 0;
79  float d2;
80  std::vector<std::vector<int>> tmp(queries.size());
81  std::vector<std::vector<float>> dists(queries.size());
82 
83  // Search neigbors indices
84  // ***********************
85 
86  for (auto& p0 : queries) {
87  int i = 0;
88  for (auto& p : supports) {
89  d2 = (p0 - p).sq_norm();
90  if (d2 < r2) {
91  // Find order of the new point
92  auto it = std::upper_bound(dists[i0].begin(), dists[i0].end(),
93  d2);
94  int index = std::distance(dists[i0].begin(), it);
95 
96  // Insert element
97  dists[i0].insert(it, d2);
98  tmp[i0].insert(tmp[i0].begin() + index, i);
99 
100  // Update max count
101  if ((signed)tmp[i0].size() > max_count)
102  max_count = tmp[i0].size();
103  }
104  i++;
105  }
106  i0++;
107  }
108 
109  // Reserve the memory
110  neighbors_indices.resize(queries.size() * max_count);
111  i0 = 0;
112  for (auto& inds : tmp) {
113  for (int j = 0; j < max_count; j++) {
114  if (j < (signed)inds.size())
115  neighbors_indices[i0 * max_count + j] = inds[j];
116  else
117  neighbors_indices[i0 * max_count + j] = -1;
118  }
119  i0++;
120  }
121 
122  return;
123 }
124 
125 void batch_nanoflann_neighbors(std::vector<PointXYZ>& queries,
126  std::vector<PointXYZ>& supports,
127  std::vector<int>& q_batches,
128  std::vector<int>& s_batches,
129  std::vector<int>& neighbors_indices,
130  float radius) {
131  // Initiate variables
132  // ******************
133 
134  // indices
135  int i0 = 0;
136 
137  // Square radius
138  float r2 = radius * radius;
139 
140  // Counting vector
141  int max_count = 0;
142  std::vector<std::vector<nanoflann::ResultItem<unsigned int, float>>>
143  all_inds_dists(queries.size());
144 
145  // batch index
146  int b = 0;
147  int sum_qb = 0;
148  int sum_sb = 0;
149 
150  // Nanoflann related variables
151  // ***************************
152 
153  // CLoud variable
154  PointCloud current_cloud;
155 
156  // Tree parameters
157  nanoflann::KDTreeSingleIndexAdaptorParams tree_params(10 /* max leaf */);
158 
159  // KDTree type definition
160  typedef nanoflann::KDTreeSingleIndexAdaptor<
161  nanoflann::L2_Simple_Adaptor<float, PointCloud>, PointCloud, 3>
162  my_kd_tree_t;
163 
164  // Pointer to trees
165  my_kd_tree_t* index;
166 
167  // Build KDTree for the first batch element
168  current_cloud.pts =
169  std::vector<PointXYZ>(supports.begin() + sum_sb,
170  supports.begin() + sum_sb + s_batches[b]);
171  index = new my_kd_tree_t(3, current_cloud, tree_params);
172  index->buildIndex();
173 
174  // Search neigbors indices
175  // ***********************
176 
177  // Search params
178  nanoflann::SearchParameters search_params;
179  search_params.sorted = true;
180 
181  for (auto& p0 : queries) {
182  // Check if we changed batch
183  if (i0 == sum_qb + q_batches[b]) {
184  sum_qb += q_batches[b];
185  sum_sb += s_batches[b];
186  b++;
187 
188  // Change the points
189  current_cloud.pts.clear();
190  current_cloud.pts = std::vector<PointXYZ>(
191  supports.begin() + sum_sb,
192  supports.begin() + sum_sb + s_batches[b]);
193 
194  // Build KDTree of the current element of the batch
195  delete index;
196  index = new my_kd_tree_t(3, current_cloud, tree_params);
197  index->buildIndex();
198  }
199 
200  // Initial guess of neighbors size
201  all_inds_dists[i0].reserve(max_count);
202 
203  // Find neighbors
204  float query_pt[3] = {p0.x, p0.y, p0.z};
205  size_t nMatches = index->radiusSearch(query_pt, r2, all_inds_dists[i0],
206  search_params);
207 
208  // Update max count
209  if ((signed)nMatches > max_count) max_count = nMatches;
210 
211  // Increment query idx
212  i0++;
213  }
214 
215  // Reserve the memory
216  neighbors_indices.resize(queries.size() * max_count);
217  i0 = 0;
218  sum_sb = 0;
219  sum_qb = 0;
220  b = 0;
221  for (auto& inds_dists : all_inds_dists) {
222  // Check if we changed batch
223  if (i0 == sum_qb + q_batches[b]) {
224  sum_qb += q_batches[b];
225  sum_sb += s_batches[b];
226  b++;
227  }
228 
229  for (int j = 0; j < max_count; j++) {
230  if (j < (signed)inds_dists.size())
231  neighbors_indices[i0 * max_count + j] =
232  inds_dists[j].first + sum_sb;
233  else
234  neighbors_indices[i0 * max_count + j] = supports.size();
235  }
236  i0++;
237  }
238 
239  delete index;
240 
241  return;
242 }
243 
244 } // namespace contrib
245 } // namespace ml
246 } // namespace cloudViewer
int size
::ccPointCloud PointCloud
Definition: PointCloud.h:19
void batch_nanoflann_neighbors(std::vector< PointXYZ > &queries, std::vector< PointXYZ > &supports, std::vector< int > &q_batches, std::vector< int > &s_batches, std::vector< int > &neighbors_indices, float radius)
Definition: neighbors.cpp:125
void ordered_neighbors(std::vector< PointXYZ > &queries, std::vector< PointXYZ > &supports, std::vector< int > &neighbors_indices, float radius)
Definition: neighbors.cpp:64
void brute_neighbors(std::vector< PointXYZ > &queries, std::vector< PointXYZ > &supports, std::vector< int > &neighbors_indices, float radius, int verbose)
Definition: neighbors.cpp:14
Generic file read and write utility for python interface.