cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
fpfh_extractor_impl_optimized.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <numeric>
5#include <unordered_set>
6#include <unordered_map>
9
10namespace toolbox::pcl
11{
12
13// Optimized version that only computes SPFH for necessary points
14template<typename DataType, typename KNN>
15void fpfh_extractor_t<DataType, KNN>::compute_impl_optimized(
16 const point_cloud& cloud,
17 const std::vector<std::size_t>& keypoint_indices,
18 std::vector<signature_type>& descriptors) const
19{
20 if (!m_knn || keypoint_indices.empty())
21 {
22 descriptors.clear();
23 return;
24 }
25
26 // Compute normals if not provided
27 point_cloud_ptr normals = m_normals;
28 if (!normals)
29 {
30 normals = std::make_shared<point_cloud>();
31 normals->points.resize(cloud.size());
32 pca_norm_extractor_t<data_type, knn_type> norm_extractor;
33 norm_extractor.set_input(cloud);
34 norm_extractor.set_knn(*m_knn);
35 norm_extractor.set_num_neighbors(m_num_neighbors);
36 norm_extractor.enable_parallel(m_enable_parallel);
37 norm_extractor.extract(normals);
38 }
39
40 // Step 1: Find all points that need SPFH computation
41 std::unordered_set<std::size_t> points_needing_spfh;
42
43 // First pass: add keypoints and find their neighbors
44 for (auto keypoint_idx : keypoint_indices)
45 {
46 points_needing_spfh.insert(keypoint_idx);
47
48 std::vector<std::size_t> neighbor_indices;
49 std::vector<data_type> neighbor_distances;
50 m_knn->radius_neighbors(cloud.points[keypoint_idx], m_search_radius, neighbor_indices, neighbor_distances);
51
52 // Limit neighbors
53 std::size_t num_neighbors = std::min(neighbor_indices.size(), m_num_neighbors);
54 for (std::size_t i = 0; i < num_neighbors; ++i)
55 {
56 points_needing_spfh.insert(neighbor_indices[i]);
57 }
58 }
59
60 // Convert to vector for indexing
61 std::vector<std::size_t> spfh_point_indices(points_needing_spfh.begin(), points_needing_spfh.end());
62
63 // Create mapping from original point index to SPFH array index
64 std::unordered_map<std::size_t, std::size_t> point_to_spfh_idx;
65 for (std::size_t i = 0; i < spfh_point_indices.size(); ++i)
66 {
67 point_to_spfh_idx[spfh_point_indices[i]] = i;
68 }
69
70 // Step 2: Compute SPFH only for necessary points
71 std::vector<spfh_signature_t> spfh_features(spfh_point_indices.size());
72
73 auto compute_spfh_for_points = [&](const std::vector<std::size_t>& indices) {
74 for (std::size_t i : indices)
75 {
76 std::size_t point_idx = spfh_point_indices[i];
77 std::vector<std::size_t> neighbor_indices;
78 std::vector<data_type> neighbor_distances;
79
80 m_knn->radius_neighbors(cloud.points[point_idx], m_search_radius, neighbor_indices, neighbor_distances);
81
82 if (neighbor_indices.size() > m_num_neighbors)
83 {
84 neighbor_indices.resize(m_num_neighbors);
85 }
86
87 if (!neighbor_indices.empty())
88 {
89 compute_spfh(cloud, *normals, point_idx, neighbor_indices, spfh_features[i]);
90 }
91 }
92 };
93
94 if (m_enable_parallel)
95 {
96 std::vector<std::size_t> indices(spfh_point_indices.size());
97 std::iota(indices.begin(), indices.end(), 0);
98
99 toolbox::concurrent::parallel_for_each(indices.begin(), indices.end(),
100 [&](std::size_t i) {
101 std::size_t point_idx = spfh_point_indices[i];
102 std::vector<std::size_t> neighbor_indices;
103 std::vector<data_type> neighbor_distances;
104
105 m_knn->radius_neighbors(cloud.points[point_idx], m_search_radius, neighbor_indices, neighbor_distances);
106
107 if (neighbor_indices.size() > m_num_neighbors)
108 {
109 neighbor_indices.resize(m_num_neighbors);
110 }
111
112 if (!neighbor_indices.empty())
113 {
114 compute_spfh(cloud, *normals, point_idx, neighbor_indices, spfh_features[i]);
115 }
116 });
117 }
118 else
119 {
120 std::vector<std::size_t> indices(spfh_point_indices.size());
121 std::iota(indices.begin(), indices.end(), 0);
122 compute_spfh_for_points(indices);
123 }
124
125 // Step 3: Compute FPFH for keypoints
126 descriptors.resize(keypoint_indices.size());
127
128 auto compute_fpfh_for_keypoint = [&](std::size_t idx) {
129 std::size_t keypoint_idx = keypoint_indices[idx];
130 auto& fpfh = descriptors[idx];
131
132 // Initialize FPFH histogram
133 std::fill(fpfh.histogram.begin(), fpfh.histogram.end(), DataType(0));
134
135 // Get neighbors
136 std::vector<std::size_t> neighbor_indices;
137 std::vector<data_type> neighbor_distances;
138 m_knn->radius_neighbors(cloud.points[keypoint_idx], m_search_radius, neighbor_indices, neighbor_distances);
139
140 if (neighbor_indices.size() > m_num_neighbors)
141 {
142 neighbor_indices.resize(m_num_neighbors);
143 neighbor_distances.resize(m_num_neighbors);
144 }
145
146 if (neighbor_indices.empty()) return;
147
148 // Copy own SPFH
149 auto it = point_to_spfh_idx.find(keypoint_idx);
150 if (it != point_to_spfh_idx.end())
151 {
152 const auto& own_spfh = spfh_features[it->second];
153 for (std::size_t i = 0; i < 11; ++i)
154 {
155 fpfh.histogram[i] = own_spfh.f1[i];
156 fpfh.histogram[i + 11] = own_spfh.f2[i];
157 fpfh.histogram[i + 22] = own_spfh.f3[i];
158 }
159 }
160
161 // Weight and accumulate neighbor SPFHs
162 data_type weight_sum = DataType(0);
163
164 for (std::size_t i = 0; i < neighbor_indices.size(); ++i)
165 {
166 std::size_t neighbor_idx = neighbor_indices[i];
167 if (neighbor_idx == keypoint_idx) continue;
168
169 auto neighbor_it = point_to_spfh_idx.find(neighbor_idx);
170 if (neighbor_it == point_to_spfh_idx.end()) continue;
171
172 // Use inverse distance as weight
173 data_type weight = DataType(1) / (neighbor_distances[i] + DataType(1e-6));
174 weight_sum += weight;
175
176 const auto& neighbor_spfh = spfh_features[neighbor_it->second];
177 for (std::size_t j = 0; j < 11; ++j)
178 {
179 fpfh.histogram[j] += weight * neighbor_spfh.f1[j];
180 fpfh.histogram[j + 11] += weight * neighbor_spfh.f2[j];
181 fpfh.histogram[j + 22] += weight * neighbor_spfh.f3[j];
182 }
183 }
184
185 // Normalize the final histogram
186 if (weight_sum > DataType(0))
187 {
188 data_type norm_factor = DataType(1) / (DataType(1) + weight_sum);
189 for (std::size_t i = 0; i < 33; ++i)
190 {
191 fpfh.histogram[i] *= norm_factor;
192 }
193 }
194 };
195
196 if (m_enable_parallel)
197 {
198 std::vector<std::size_t> indices(keypoint_indices.size());
199 std::iota(indices.begin(), indices.end(), 0);
200
201 toolbox::concurrent::parallel_for_each(indices.begin(), indices.end(), compute_fpfh_for_keypoint);
202 }
203 else
204 {
205 for (std::size_t i = 0; i < keypoint_indices.size(); ++i)
206 {
207 compute_fpfh_for_keypoint(i);
208 }
209 }
210}
211
212} // namespace toolbox::pcl
void parallel_for_each(Iterator begin, Iterator end, Function func)
使用TBB并行对范围[begin, end)中的每个元素应用函数
Definition parallel_raw.hpp:21
Definition base_correspondence_generator.hpp:18