cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
rops_extractor.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <vector>
6
12
13#include <Eigen/Core>
14#include <Eigen/Eigenvalues>
15
16namespace toolbox::pcl
17{
18
19template<typename DataType>
20struct rops_signature_t : public base_signature_t<DataType, rops_signature_t<DataType>>
21{
22 static constexpr std::size_t HISTOGRAM_SIZE = 135; // 5 * 3 * 3 * 3
23 std::array<DataType, HISTOGRAM_SIZE> histogram {};
24
25 DataType distance_impl(const rops_signature_t& other) const
26 {
27 DataType dist = 0;
28 for (std::size_t i = 0; i < HISTOGRAM_SIZE; ++i) {
29 DataType diff = histogram[i] - other.histogram[i];
30 dist += diff * diff;
31 }
32 return std::sqrt(dist);
33 }
34};
35
36template<typename DataType,
37 typename KNN = kdtree_generic_t<point_t<DataType>, toolbox::metrics::L2Metric<DataType>>>
39 : public base_descriptor_extractor_t<rops_extractor_t<DataType, KNN>,
40 DataType,
41 rops_signature_t<DataType>>
42{
43public:
44 rops_extractor_t() = default;
45
47 {
48 cloud_ = &cloud;
49 return cloud.size();
50 }
51
52 std::size_t set_knn(KNN& knn)
53 {
54 knn_ = &knn;
55 return cloud_ ? cloud_->size() : 0;
56 }
57
58 std::size_t set_search_radius(DataType radius)
59 {
60 search_radius_ = radius;
61 return cloud_ ? cloud_->size() : 0;
62 }
63
64 std::size_t set_num_neighbors(std::size_t num_neighbors)
65 {
66 num_neighbors_ = num_neighbors;
67 return cloud_ ? cloud_->size() : 0;
68 }
69
70 std::size_t set_num_partitions_x(std::size_t partitions)
71 {
72 num_partitions_x_ = partitions;
73 return cloud_ ? cloud_->size() : 0;
74 }
75
76 std::size_t set_num_partitions_y(std::size_t partitions)
77 {
78 num_partitions_y_ = partitions;
79 return cloud_ ? cloud_->size() : 0;
80 }
81
82 std::size_t set_num_partitions_z(std::size_t partitions)
83 {
84 num_partitions_z_ = partitions;
85 return cloud_ ? cloud_->size() : 0;
86 }
87
88 std::size_t set_num_rotations(std::size_t rotations)
89 {
90 num_rotations_ = rotations;
91 return cloud_ ? cloud_->size() : 0;
92 }
93
94 void enable_parallel_impl(bool enable) { enable_parallel_ = enable; }
95
97 const std::vector<std::size_t>& keypoint_indices,
98 std::vector<rops_signature_t<DataType>>& descriptors) const
99 {
100 descriptors.clear();
101 descriptors.resize(keypoint_indices.size());
102
103 if (!cloud_ || !knn_)
104 return;
105
106 auto compute_descriptor = [&](std::size_t idx)
107 {
108 const auto keypoint_idx = keypoint_indices[idx];
109 compute_rops(cloud, keypoint_idx, descriptors[idx]);
110 };
111
112 if (enable_parallel_) {
113#pragma omp parallel for
114 for (int i = 0; i < static_cast<int>(keypoint_indices.size()); ++i) {
115 compute_descriptor(static_cast<std::size_t>(i));
116 }
117 } else {
118 for (std::size_t i = 0; i < keypoint_indices.size(); ++i) {
119 compute_descriptor(i);
120 }
121 }
122 }
123
125 const std::vector<std::size_t>& keypoint_indices,
126 std::unique_ptr<std::vector<rops_signature_t<DataType>>>
127 descriptors) const
128 {
129 descriptors->clear();
130 compute_impl(cloud, keypoint_indices, *descriptors);
131 }
132
133private:
134 void compute_rops(const toolbox::types::point_cloud_t<DataType>& cloud,
135 std::size_t keypoint_idx,
136 rops_signature_t<DataType>& descriptor) const
137 {
138 // Initialize
139 std::fill(descriptor.histogram.begin(), descriptor.histogram.end(), 0);
140
141 const auto& keypoint = cloud.points[keypoint_idx];
142
143 // Find neighbors
144 std::vector<std::size_t> neighbors;
145 std::vector<DataType> distances;
146 knn_->radius_neighbors(keypoint, search_radius_, neighbors, distances);
147
148 if (neighbors.size() < 3)
149 return;
150
151 // Transform to local coordinates
152 std::vector<Eigen::Vector3f> local_points;
153 local_points.reserve(neighbors.size());
154
155 for (const auto& idx : neighbors) {
156 const auto& pt = cloud.points[idx];
157 local_points.emplace_back(
158 pt.x - keypoint.x, pt.y - keypoint.y, pt.z - keypoint.z);
159 }
160
161 // Compute local reference frame
162 auto lrf = compute_lrf(local_points);
163
164 // Transform points to LRF
165 for (auto& pt : local_points) {
166 pt = lrf.transpose() * pt;
167 }
168
169 // Generate rotation matrices
170 std::vector<Eigen::Matrix3f> rotations;
171 generate_rotation_matrices(rotations);
172
173 // Compute statistics for each rotation
174 std::vector<std::vector<DataType>> rotation_stats;
175 rotation_stats.resize(num_rotations_);
176
177 for (std::size_t r = 0; r < num_rotations_; ++r) {
178 // Rotate points
179 std::vector<Eigen::Vector3f> rotated_points;
180 rotated_points.reserve(local_points.size());
181
182 for (const auto& pt : local_points) {
183 rotated_points.push_back(rotations[r] * pt);
184 }
185
186 // Compute bounding box
187 Eigen::Vector3f bbox_min(std::numeric_limits<float>::max(),
188 std::numeric_limits<float>::max(),
189 std::numeric_limits<float>::max());
190 Eigen::Vector3f bbox_max(std::numeric_limits<float>::lowest(),
191 std::numeric_limits<float>::lowest(),
192 std::numeric_limits<float>::lowest());
193
194 for (const auto& pt : rotated_points) {
195 bbox_min = bbox_min.cwiseMin(pt);
196 bbox_max = bbox_max.cwiseMax(pt);
197 }
198
199 Eigen::Vector3f bbox_size = bbox_max - bbox_min;
200
201 // Create partitions
202 std::vector<std::vector<std::vector<std::vector<float>>>> partitions;
203 partitions.resize(num_partitions_x_);
204 for (auto& x : partitions) {
205 x.resize(num_partitions_y_);
206 for (auto& y : x) {
207 y.resize(num_partitions_z_);
208 }
209 }
210
211 // Assign points to partitions
212 for (const auto& pt : rotated_points) {
213 Eigen::Vector3f normalized = (pt - bbox_min).cwiseQuotient(bbox_size);
214
215 std::size_t x_idx =
216 static_cast<std::size_t>(normalized(0) * num_partitions_x_);
217 std::size_t y_idx =
218 static_cast<std::size_t>(normalized(1) * num_partitions_y_);
219 std::size_t z_idx =
220 static_cast<std::size_t>(normalized(2) * num_partitions_z_);
221
222 // Clamp indices
223 x_idx = std::min(x_idx, num_partitions_x_ - 1);
224 y_idx = std::min(y_idx, num_partitions_y_ - 1);
225 z_idx = std::min(z_idx, num_partitions_z_ - 1);
226
227 // Add point distance to partition
228 float dist = pt.norm();
229 partitions[x_idx][y_idx][z_idx].push_back(dist);
230 }
231
232 // Compute statistics for each partition
233 std::vector<DataType>& stats = rotation_stats[r];
234 stats.reserve(num_partitions_x_ * num_partitions_y_ * num_partitions_z_);
235
236 for (std::size_t x = 0; x < num_partitions_x_; ++x) {
237 for (std::size_t y = 0; y < num_partitions_y_; ++y) {
238 for (std::size_t z = 0; z < num_partitions_z_; ++z) {
239 const auto& partition = partitions[x][y][z];
240
241 if (partition.empty()) {
242 stats.push_back(0);
243 } else {
244 // Compute mean distance
245 DataType sum = 0;
246 for (float d : partition) {
247 sum += d;
248 }
249 stats.push_back(sum / partition.size());
250 }
251 }
252 }
253 }
254 }
255
256 // Build final histogram from all rotation statistics
257 std::size_t hist_idx = 0;
258 for (std::size_t r = 0; r < num_rotations_; ++r) {
259 const auto& stats = rotation_stats[r];
260 for (std::size_t i = 0; i < stats.size(); ++i) {
261 descriptor.histogram[hist_idx++] = stats[i];
262 }
263 }
264
265 // Normalize
266 DataType sum = 0;
267 for (auto& val : descriptor.histogram) {
268 sum += val * val;
269 }
270 if (sum > 0) {
271 sum = std::sqrt(sum);
272 for (auto& val : descriptor.histogram) {
273 val /= sum;
274 }
275 }
276 }
277
278 Eigen::Matrix3f compute_lrf(const std::vector<Eigen::Vector3f>& points) const
279 {
280 // Compute covariance matrix
281 Eigen::Matrix3f covariance = Eigen::Matrix3f::Zero();
282
283 for (const auto& pt : points) {
284 covariance += pt * pt.transpose();
285 }
286 covariance /= points.size();
287
288 // Eigenvalue decomposition
289 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> solver(covariance);
290
291 // Return eigenvectors as local reference frame
292 return solver.eigenvectors();
293 }
294
295 void generate_rotation_matrices(std::vector<Eigen::Matrix3f>& rotations) const
296 {
297 rotations.clear();
298 rotations.resize(num_rotations_);
299
300 // Generate evenly spaced rotations around axes
301 for (std::size_t i = 0; i < num_rotations_; ++i) {
302 DataType angle = 2.0 * M_PI * i / num_rotations_;
303
304 // Simple rotation around Z-axis for now
305 Eigen::Matrix3f rot;
306 rot << std::cos(angle), -std::sin(angle), 0, std::sin(angle),
307 std::cos(angle), 0, 0, 0, 1;
308
309 rotations[i] = rot;
310 }
311 }
312
313private:
314 const toolbox::types::point_cloud_t<DataType>* cloud_ = nullptr;
315 KNN* knn_ = nullptr;
316 DataType search_radius_ = 0.2;
317 std::size_t num_neighbors_ = 50;
318 std::size_t num_partitions_x_ = 3;
319 std::size_t num_partitions_y_ = 3;
320 std::size_t num_partitions_z_ = 3;
321 std::size_t num_rotations_ = 5;
322 bool enable_parallel_ = true;
323};
324
325} // namespace toolbox::pcl
Definition vector_metrics.hpp:18
描述子提取器的基类(CRTP模式) / Base class for descriptor extractors (CRTP pattern)
Definition base_descriptor_extractor.hpp:91
Definition rops_extractor.hpp:42
std::size_t set_search_radius(DataType radius)
Definition rops_extractor.hpp:58
std::size_t set_num_neighbors(std::size_t num_neighbors)
Definition rops_extractor.hpp:64
std::size_t set_num_partitions_x(std::size_t partitions)
Definition rops_extractor.hpp:70
std::size_t set_input(const toolbox::types::point_cloud_t< DataType > &cloud)
Definition rops_extractor.hpp:46
std::size_t set_num_rotations(std::size_t rotations)
Definition rops_extractor.hpp:88
std::size_t set_knn(KNN &knn)
Definition rops_extractor.hpp:52
std::size_t set_num_partitions_y(std::size_t partitions)
Definition rops_extractor.hpp:76
void compute_impl(const toolbox::types::point_cloud_t< DataType > &cloud, const std::vector< std::size_t > &keypoint_indices, std::unique_ptr< std::vector< rops_signature_t< DataType > > > descriptors) const
Definition rops_extractor.hpp:124
void compute_impl(const toolbox::types::point_cloud_t< DataType > &cloud, const std::vector< std::size_t > &keypoint_indices, std::vector< rops_signature_t< DataType > > &descriptors) const
Definition rops_extractor.hpp:96
std::size_t set_num_partitions_z(std::size_t partitions)
Definition rops_extractor.hpp:82
void enable_parallel_impl(bool enable)
Definition rops_extractor.hpp:94
包含点和相关数据的点云类 / A point cloud class containing points and associated data
Definition point.hpp:268
std::vector< point_t< T > > points
点坐标 / Point coordinates
Definition point.hpp:270
auto size() const -> std::size_t
获取点云中的点数 / Get number of points in cloud
Definition point_impl.hpp:293
TContainer::value_type sum(const TContainer &data)
计算容器中元素的总和(返回容器元素类型)/Compute the sum of elements in the container (returns container element type)
Definition statistics.hpp:288
Definition base_correspondence_generator.hpp:18
描述子签名的基类 / Base class for descriptor signatures
Definition base_descriptor_extractor.hpp:38
Definition rops_extractor.hpp:21
std::array< DataType, HISTOGRAM_SIZE > histogram
Definition rops_extractor.hpp:23
DataType distance_impl(const rops_signature_t &other) const
Definition rops_extractor.hpp:25
static constexpr std::size_t HISTOGRAM_SIZE
Definition rops_extractor.hpp:22