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