ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
GridSubsampling.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 namespace cloudViewer {
11 namespace ml {
12 namespace contrib {
13 
14 void grid_subsampling(std::vector<PointXYZ>& original_points,
15  std::vector<PointXYZ>& subsampled_points,
16  std::vector<float>& original_features,
17  std::vector<float>& subsampled_features,
18  std::vector<int>& original_classes,
19  std::vector<int>& subsampled_classes,
20  float sampleDl,
21  int verbose) {
22  // Initialize variables
23  // ******************
24 
25  // Number of points in the cloud
26  size_t N = original_points.size();
27 
28  // Dimension of the features
29  size_t fdim = original_features.size() / N;
30  size_t ldim = original_classes.size() / N;
31 
32  // Limits of the cloud
33  PointXYZ minCorner = min_point(original_points);
34  PointXYZ maxCorner = max_point(original_points);
35  PointXYZ originCorner =
36  PointXYZ::floor(minCorner * (1 / sampleDl)) * sampleDl;
37 
38  // Dimensions of the grid
39  size_t sampleNX =
40  (size_t)floor((maxCorner.x - originCorner.x) / sampleDl) + 1;
41  size_t sampleNY =
42  (size_t)floor((maxCorner.y - originCorner.y) / sampleDl) + 1;
43  // size_t sampleNZ = (size_t)floor((maxCorner.z - originCorner.z) /
44  // sampleDl) + 1;
45 
46  // Check if features and classes need to be processed
47  bool use_feature = original_features.size() > 0;
48  bool use_classes = original_classes.size() > 0;
49 
50  // Create the sampled map
51  // **********************
52 
53  // Verbose parameters
54  int i = 0;
55  int nDisp = static_cast<int>(N / 100);
56 
57  // Initialize variables
58  std::unordered_map<size_t, SampledData> data;
59 
60  for (auto& p : original_points) {
61  size_t iX, iY, iZ, mapIdx;
62 
63  // Position of point in sample map
64  iX = (size_t)std::floor((p.x - originCorner.x) / sampleDl);
65  iY = (size_t)std::floor((p.y - originCorner.y) / sampleDl);
66  iZ = (size_t)std::floor((p.z - originCorner.z) / sampleDl);
67  mapIdx = iX + sampleNX * iY + sampleNX * sampleNY * iZ;
68 
69  // If not already created, create key
70  if (data.count(mapIdx) < 1)
71  data.emplace(mapIdx, SampledData(fdim, ldim));
72 
73  // Fill the sample map
74  if (use_feature && use_classes)
75  data[mapIdx].update_all(p, original_features.begin() + i * fdim,
76  original_classes.begin() + i * ldim);
77  else if (use_feature)
78  data[mapIdx].update_features(p,
79  original_features.begin() + i * fdim);
80  else if (use_classes)
81  data[mapIdx].update_classes(p, original_classes.begin() + i * ldim);
82  else
83  data[mapIdx].update_points(p);
84 
85  // Display
86  i++;
87  if (verbose > 1 && i % nDisp == 0)
88  std::cout << "\rSampled Map : " << std::setw(3) << i / nDisp << "%";
89  }
90 
91  // Divide for barycentre and transfer to a vector
92  subsampled_points.reserve(data.size());
93  if (use_feature) subsampled_features.reserve(data.size() * fdim);
94  if (use_classes) subsampled_classes.reserve(data.size() * ldim);
95  for (auto& v : data) {
96  subsampled_points.push_back(v.second.point * (1.0f / v.second.count));
97  if (use_feature) {
98  float count = (float)v.second.count;
99  transform(v.second.features.begin(), v.second.features.end(),
100  v.second.features.begin(),
101  [count](float f) { return f / count; });
102  subsampled_features.insert(subsampled_features.end(),
103  v.second.features.begin(),
104  v.second.features.end());
105  }
106  if (use_classes) {
107  for (int i = 0; i < static_cast<int>(ldim); i++)
108  subsampled_classes.push_back(
109  max_element(v.second.labels[i].begin(),
110  v.second.labels[i].end(),
111  [](const std::pair<int, int>& a,
112  const std::pair<int, int>& b) {
113  return a.second < b.second;
114  })
115  ->first);
116  }
117  }
118 
119  return;
120 }
121 
122 void batch_grid_subsampling(std::vector<PointXYZ>& original_points,
123  std::vector<PointXYZ>& subsampled_points,
124  std::vector<float>& original_features,
125  std::vector<float>& subsampled_features,
126  std::vector<int>& original_classes,
127  std::vector<int>& subsampled_classes,
128  std::vector<int>& original_batches,
129  std::vector<int>& subsampled_batches,
130  float sampleDl,
131  int max_p) {
132  // Initialize variables
133  // ******************
134 
135  int b = 0;
136  int sum_b = 0;
137 
138  // Number of points in the cloud
139  size_t N = original_points.size();
140 
141  // Dimension of the features
142  size_t fdim = original_features.size() / N;
143  size_t ldim = original_classes.size() / N;
144 
145  // Handle max_p = 0
146  if (max_p < 1) max_p = static_cast<int>(N);
147 
148  // Loop over batches
149  // *****************
150 
151  for (b = 0; b < static_cast<int>(original_batches.size()); b++) {
152  // Extract batch points features and labels
153  std::vector<PointXYZ> b_o_points = std::vector<PointXYZ>(
154  original_points.begin() + sum_b,
155  original_points.begin() + sum_b + original_batches[b]);
156 
157  std::vector<float> b_o_features;
158  if (original_features.size() > 0) {
159  b_o_features = std::vector<float>(
160  original_features.begin() + sum_b * fdim,
161  original_features.begin() +
162  (sum_b + original_batches[b]) * fdim);
163  }
164 
165  std::vector<int> b_o_classes;
166  if (original_classes.size() > 0) {
167  b_o_classes =
168  std::vector<int>(original_classes.begin() + sum_b * ldim,
169  original_classes.begin() + sum_b +
170  original_batches[b] * ldim);
171  }
172 
173  // Create result containers
174  std::vector<PointXYZ> b_s_points;
175  std::vector<float> b_s_features;
176  std::vector<int> b_s_classes;
177 
178  // Compute subsampling on current batch
179  grid_subsampling(b_o_points, b_s_points, b_o_features, b_s_features,
180  b_o_classes, b_s_classes, sampleDl, 0);
181 
182  // Stack batches points features and labels
183  // ****************************************
184 
185  // If too many points remove some
186  if (static_cast<int>(b_s_points.size()) <= max_p) {
187  subsampled_points.insert(subsampled_points.end(),
188  b_s_points.begin(), b_s_points.end());
189 
190  if (original_features.size() > 0)
191  subsampled_features.insert(subsampled_features.end(),
192  b_s_features.begin(),
193  b_s_features.end());
194 
195  if (original_classes.size() > 0)
196  subsampled_classes.insert(subsampled_classes.end(),
197  b_s_classes.begin(),
198  b_s_classes.end());
199 
200  subsampled_batches.push_back(static_cast<int>(b_s_points.size()));
201  } else {
202  subsampled_points.insert(subsampled_points.end(),
203  b_s_points.begin(),
204  b_s_points.begin() + max_p);
205 
206  if (original_features.size() > 0)
207  subsampled_features.insert(subsampled_features.end(),
208  b_s_features.begin(),
209  b_s_features.begin() + max_p * fdim);
210 
211  if (original_classes.size() > 0)
212  subsampled_classes.insert(subsampled_classes.end(),
213  b_s_classes.begin(),
214  b_s_classes.begin() + max_p * ldim);
215 
216  subsampled_batches.push_back(max_p);
217  }
218 
219  // Stack new batch lengths
220  sum_b += original_batches[b];
221  }
222 
223  return;
224 }
225 
226 } // namespace contrib
227 } // namespace ml
228 } // namespace cloudViewer
int count
static PointXYZ floor(const PointXYZ P)
Definition: Cloud.h:88
PointXYZ min_point(std::vector< PointXYZ > points)
Definition: Cloud.cpp:37
void batch_grid_subsampling(std::vector< PointXYZ > &original_points, std::vector< PointXYZ > &subsampled_points, std::vector< float > &original_features, std::vector< float > &subsampled_features, std::vector< int > &original_classes, std::vector< int > &subsampled_classes, std::vector< int > &original_batches, std::vector< int > &subsampled_batches, float sampleDl, int max_p)
void grid_subsampling(std::vector< PointXYZ > &original_points, std::vector< PointXYZ > &subsampled_points, std::vector< float > &original_features, std::vector< float > &subsampled_features, std::vector< int > &original_classes, std::vector< int > &subsampled_classes, float sampleDl, int verbose)
PointXYZ max_point(std::vector< PointXYZ > points)
Definition: Cloud.cpp:21
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
Generic file read and write utility for python interface.