cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
loam_feature_extractor_impl.hpp
Go to the documentation of this file.
1#pragma once
2
5#include <algorithm>
6#include <cmath>
7#include <future>
8#include <vector>
9
10namespace toolbox::pcl
11{
12
13template<typename DataType, typename KNN>
15{
16 m_cloud = std::make_shared<point_cloud>(cloud);
17 return m_cloud->size();
18}
19
20template<typename DataType, typename KNN>
22{
23 m_cloud = cloud;
24 return m_cloud->size();
25}
26
27template<typename DataType, typename KNN>
29{
30 m_knn = const_cast<knn_type*>(&knn);
31 if (m_cloud) {
32 m_knn->set_input(m_cloud->points);
33 }
34 return m_cloud ? m_cloud->size() : 0;
35}
36
37template<typename DataType, typename KNN>
39{
40 // LOAM uses fixed number of neighbors instead of radius
41 // But we can use radius for secondary validation
42 return 0;
43}
44
45template<typename DataType, typename KNN>
47{
48 m_enable_parallel = enable;
49}
50
51template<typename DataType, typename KNN>
54{
55 if (!m_cloud || !m_knn || point_idx >= m_cloud->size()) {
56 return CurvatureInfo{0, false};
57 }
58
59 const auto& query_point = m_cloud->points[point_idx];
60 std::vector<std::size_t> neighbor_indices;
61 std::vector<data_type> neighbor_distances;
62
63 // Find k nearest neighbors
64 m_knn->kneighbors(query_point, m_num_scan_neighbors, neighbor_indices, neighbor_distances);
65
66 if (neighbor_indices.size() < 5) { // Need minimum neighbors
67 return CurvatureInfo{0, false};
68 }
69
70 // LOAM curvature formula:
71 // c = |Σ(X_i - X_j)|/(k * |X_j|)
72 // where X_j is the query point and X_i are neighbors
73
74 data_type sum_diff_x = 0;
75 data_type sum_diff_y = 0;
76 data_type sum_diff_z = 0;
77
78 for (const auto& idx : neighbor_indices) {
79 if (idx != point_idx) { // Skip self
80 const auto& neighbor = m_cloud->points[idx];
81 sum_diff_x += neighbor.x - query_point.x;
82 sum_diff_y += neighbor.y - query_point.y;
83 sum_diff_z += neighbor.z - query_point.z;
84 }
85 }
86
87 // Compute curvature magnitude
88 const data_type diff_magnitude = std::sqrt(
89 sum_diff_x * sum_diff_x +
90 sum_diff_y * sum_diff_y +
91 sum_diff_z * sum_diff_z
92 );
93
94 const data_type point_magnitude = std::sqrt(
95 query_point.x * query_point.x +
96 query_point.y * query_point.y +
97 query_point.z * query_point.z
98 );
99
100 data_type curvature = 0;
101 if (point_magnitude > 1e-6) {
102 curvature = diff_magnitude / (static_cast<data_type>(neighbor_indices.size()) * point_magnitude);
103 }
104
105 return CurvatureInfo{curvature, true};
106}
107
108template<typename DataType, typename KNN>
109void loam_feature_extractor_t<DataType, KNN>::compute_curvatures_range(
110 std::vector<CurvatureInfo>& curvatures,
111 std::size_t start_idx,
112 std::size_t end_idx)
113{
114 for (std::size_t i = start_idx; i < end_idx; ++i) {
115 curvatures[i] = compute_point_curvature(i);
116 }
117}
118
119template<typename DataType, typename KNN>
120std::vector<typename loam_feature_extractor_t<DataType, KNN>::CurvatureInfo>
121loam_feature_extractor_t<DataType, KNN>::compute_curvatures()
122{
123 if (!m_cloud) {
124 return {};
125 }
126
127 const std::size_t num_points = m_cloud->size();
128 std::vector<CurvatureInfo> curvatures(num_points);
129
130 if (m_enable_parallel && num_points > k_parallel_threshold) {
131 // Parallel computation
132 const std::size_t num_threads = toolbox::base::thread_pool_singleton_t::instance().get_thread_count();
133 const std::size_t chunk_size = (num_points + num_threads - 1) / num_threads;
134
135 std::vector<std::future<void>> futures;
136 for (std::size_t t = 0; t < num_threads; ++t) {
137 const std::size_t start_idx = t * chunk_size;
138 const std::size_t end_idx = std::min(start_idx + chunk_size, num_points);
139
140 if (start_idx < end_idx) {
141 futures.emplace_back(
143 [this, &curvatures, start_idx, end_idx]() {
144 compute_curvatures_range(curvatures, start_idx, end_idx);
145 }
146 )
147 );
148 }
149 }
150
151 // Wait for all threads to complete
152 for (auto& future : futures) {
153 future.wait();
154 }
155 } else {
156 // Sequential computation
157 compute_curvatures_range(curvatures, 0, num_points);
158 }
159
160 return curvatures;
161}
162
163template<typename DataType, typename KNN>
164std::vector<uint8_t> loam_feature_extractor_t<DataType, KNN>::classify_features(
165 const std::vector<CurvatureInfo>& curvatures)
166{
167 std::vector<uint8_t> labels(curvatures.size(), static_cast<uint8_t>(feature_label::none));
168
169 for (std::size_t i = 0; i < curvatures.size(); ++i) {
170 if (!curvatures[i].is_valid) {
171 continue;
172 }
173
174 const data_type curvature = curvatures[i].curvature;
175
176 if (curvature < m_curvature_threshold) {
177 // Too low curvature, skip
178 continue;
179 }
180
181 if (curvature > m_edge_threshold) {
182 // High curvature -> edge point
183 labels[i] = static_cast<uint8_t>(feature_label::edge);
184 } else if (curvature < m_planar_threshold) {
185 // Low curvature -> planar point
186 labels[i] = static_cast<uint8_t>(feature_label::planar);
187 }
188 // else: remains as none
189 }
190
191 return labels;
192}
193
194template<typename DataType, typename KNN>
197{
198 if (!m_cloud || !m_knn) {
199 return {};
200 }
201
202 // Compute curvatures
203 auto curvatures = compute_curvatures();
204
205 // Get all feature indices (both edge and planar)
206 indices_vector feature_indices;
207
208 for (std::size_t i = 0; i < curvatures.size(); ++i) {
209 if (!curvatures[i].is_valid) continue;
210
211 const data_type curvature = curvatures[i].curvature;
212 if (curvature < m_curvature_threshold) continue;
213
214 if (curvature > m_edge_threshold || curvature < m_planar_threshold) {
215 feature_indices.push_back(i);
216 }
217 }
218
219 return feature_indices;
220}
221
222template<typename DataType, typename KNN>
224{
225 keypoint_indices = extract_impl();
226}
227
228template<typename DataType, typename KNN>
231{
232 if (!m_cloud || !m_knn) {
233 return point_cloud{};
234 }
235
236 // For compatibility with base class, return all feature points
237 auto feature_indices = extract_impl();
238
239 point_cloud features;
240 features.points.reserve(feature_indices.size());
241
242 for (const auto& idx : feature_indices) {
243 features.points.push_back(m_cloud->points[idx]);
244 }
245
246 return features;
247}
248
249template<typename DataType, typename KNN>
251{
252 auto features = extract_keypoints_impl();
253 *output = std::move(features);
254}
255
256template<typename DataType, typename KNN>
259{
260 loam_result result;
261
262 if (!m_cloud || !m_knn) {
263 return result;
264 }
265
266 // Copy the cloud
267 result.cloud = *m_cloud;
268
269 // Compute curvatures
270 auto curvatures = compute_curvatures();
271
272 // Classify features
273 result.labels = classify_features(curvatures);
274
275 return result;
276}
277
278// Static utility methods
279
280template<typename DataType, typename KNN>
283{
284 point_cloud edges;
285 for (std::size_t i = 0; i < result.cloud.size() && i < result.labels.size(); ++i) {
286 if (static_cast<feature_label>(result.labels[i]) == feature_label::edge) {
287 edges.points.push_back(result.cloud.points[i]);
288 }
289 }
290 return edges;
291}
292
293template<typename DataType, typename KNN>
296{
297 point_cloud planars;
298 for (std::size_t i = 0; i < result.cloud.size() && i < result.labels.size(); ++i) {
299 if (static_cast<feature_label>(result.labels[i]) == feature_label::planar) {
300 planars.points.push_back(result.cloud.points[i]);
301 }
302 }
303 return planars;
304}
305
306template<typename DataType, typename KNN>
309{
310 point_cloud non_features;
311 for (std::size_t i = 0; i < result.cloud.size() && i < result.labels.size(); ++i) {
312 if (static_cast<feature_label>(result.labels[i]) == feature_label::none) {
313 non_features.points.push_back(result.cloud.points[i]);
314 }
315 }
316 return non_features;
317}
318
319template<typename DataType, typename KNN>
322{
323 indices_vector indices;
324 for (std::size_t i = 0; i < labels.size(); ++i) {
325 if (static_cast<feature_label>(labels[i]) == feature_label::edge) {
326 indices.push_back(i);
327 }
328 }
329 return indices;
330}
331
332template<typename DataType, typename KNN>
335{
336 indices_vector indices;
337 for (std::size_t i = 0; i < labels.size(); ++i) {
338 if (static_cast<feature_label>(labels[i]) == feature_label::planar) {
339 indices.push_back(i);
340 }
341 }
342 return indices;
343}
344
345} // namespace toolbox::pcl
static thread_pool_singleton_t & instance()
获取单例实例/Get the singleton instance
Definition thread_pool_singleton.hpp:23
LOAM (Lidar Odometry and Mapping) 特征提取器 / LOAM (Lidar Odometry and Mapping) feature extractor.
Definition loam_feature_extractor.hpp:26
static point_cloud extract_edge_points(const loam_result &result)
Definition loam_feature_extractor_impl.hpp:282
typename base_type::knn_type knn_type
Definition loam_feature_extractor.hpp:32
typename base_type::data_type data_type
Definition loam_feature_extractor.hpp:31
typename base_type::indices_vector indices_vector
Definition loam_feature_extractor.hpp:35
point_cloud extract_keypoints_impl()
Definition loam_feature_extractor_impl.hpp:230
indices_vector extract_impl()
Definition loam_feature_extractor_impl.hpp:196
std::size_t set_knn_impl(const knn_type &knn)
Definition loam_feature_extractor_impl.hpp:28
static indices_vector extract_planar_indices(const std::vector< uint8_t > &labels)
Definition loam_feature_extractor_impl.hpp:334
loam_result extract_labeled_cloud()
Definition loam_feature_extractor_impl.hpp:258
static indices_vector extract_edge_indices(const std::vector< uint8_t > &labels)
Definition loam_feature_extractor_impl.hpp:321
void enable_parallel_impl(bool enable)
Definition loam_feature_extractor_impl.hpp:46
typename base_type::point_cloud point_cloud
Definition loam_feature_extractor.hpp:33
std::size_t set_input_impl(const point_cloud &cloud)
Definition loam_feature_extractor_impl.hpp:14
typename base_type::point_cloud_ptr point_cloud_ptr
Definition loam_feature_extractor.hpp:34
std::size_t set_search_radius_impl(data_type radius)
Definition loam_feature_extractor_impl.hpp:38
feature_label
Definition loam_feature_extractor.hpp:38
static point_cloud extract_planar_points(const loam_result &result)
Definition loam_feature_extractor_impl.hpp:295
static point_cloud extract_non_feature_points(const loam_result &result)
Definition loam_feature_extractor_impl.hpp:308
Definition base_correspondence_generator.hpp:18
Definition loam_feature_extractor.hpp:45
point_cloud cloud
Definition loam_feature_extractor.hpp:46
std::vector< uint8_t > labels
Definition loam_feature_extractor.hpp:47