cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
3dsc_extractor_old.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <vector>
5#include <cmath>
6
11
12namespace toolbox::pcl
13{
14
15template<typename DataType>
16struct dsc3d_signature_t : public base_signature_t<dsc3d_signature_t<DataType>>
17{
18 static constexpr std::size_t HISTOGRAM_SIZE = 1980; // 11 * 12 * 15
19 std::array<DataType, HISTOGRAM_SIZE> histogram{};
20
21 DataType distance(const dsc3d_signature_t& other) const
22 {
23 DataType dist = 0;
24 for (std::size_t i = 0; i < HISTOGRAM_SIZE; ++i)
25 {
26 DataType diff = histogram[i] - other.histogram[i];
27 dist += diff * diff;
28 }
29 return std::sqrt(dist);
30 }
31
32 bool operator==(const dsc3d_signature_t& other) const
33 {
34 return histogram == other.histogram;
35 }
36};
37
38template<typename DataType, typename KNN>
39class dsc3d_extractor_t
40 : public base_descriptor_extractor_t<dsc3d_extractor_t<DataType, KNN>,
41 DataType, dsc3d_signature_t<DataType>>
42{
43public:
44 dsc3d_extractor_t() = default;
45
47 {
48 cloud_ = &cloud;
49 }
50
51 void set_knn(KNN& knn)
52 {
53 knn_ = &knn;
54 }
55
56 void set_search_radius(DataType radius)
57 {
58 search_radius_ = radius;
59 }
60
61 void set_num_neighbors(std::size_t num_neighbors)
62 {
63 num_neighbors_ = num_neighbors;
64 }
65
66 void set_minimal_radius(DataType radius)
67 {
68 minimal_radius_ = radius;
69 }
70
71 void set_point_density_radius(DataType radius)
72 {
73 point_density_radius_ = radius;
74 }
75
76 void enable_parallel_impl(bool enable)
77 {
78 enable_parallel_ = enable;
79 }
80
82 const std::vector<std::size_t>& keypoint_indices,
83 std::vector<dsc3d_signature_t<DataType>>& descriptors) const
84 {
85 descriptors.clear();
86 descriptors.resize(keypoint_indices.size());
87
88 if (!cloud_ || !knn_) return;
89
90 // Compute normals if not provided
91 std::vector<toolbox::types::point_t<DataType>> normals;
92 compute_normals(cloud, normals);
93
94 auto compute_descriptor = [&](std::size_t idx) {
95 const auto keypoint_idx = keypoint_indices[idx];
96 compute_3dsc(cloud, normals, keypoint_idx, descriptors[idx]);
97 };
98
99 if (enable_parallel_)
100 {
102 keypoint_indices.size(), compute_descriptor);
103 }
104 else
105 {
106 for (std::size_t i = 0; i < keypoint_indices.size(); ++i)
107 {
108 compute_descriptor(i);
109 }
110 }
111 }
112
114 const std::vector<std::size_t>& keypoint_indices,
115 std::unique_ptr<std::vector<dsc3d_signature_t<DataType>>> descriptors) const
116 {
117 descriptors->clear();
118 compute_impl(cloud, keypoint_indices, *descriptors);
119 }
120
121private:
122 void compute_normals(const toolbox::types::point_cloud_t<DataType>& cloud,
123 std::vector<toolbox::types::point_t<DataType>>& normals) const
124 {
125 if (!knn_) return;
126
127 pca_norm_t<DataType, KNN> normal_estimator;
128 normal_estimator.set_input(cloud);
129 normal_estimator.set_knn(*knn_);
130 normal_estimator.set_search_radius(search_radius_);
131 normal_estimator.set_num_neighbors(num_neighbors_);
132 normal_estimator.enable_parallel(enable_parallel_);
133
134 normal_estimator.compute(cloud, normals);
135 }
136
137 void compute_3dsc(const toolbox::types::point_cloud_t<DataType>& cloud,
138 const std::vector<toolbox::types::point_t<DataType>>& normals,
139 std::size_t keypoint_idx,
140 dsc3d_signature_t<DataType>& descriptor) const
141 {
142 // Initialize histogram
143 std::fill(descriptor.histogram.begin(), descriptor.histogram.end(), 0);
144
145 const auto& keypoint = cloud.points[keypoint_idx];
146 const auto& normal = normals[keypoint_idx];
147
148 // Find neighbors
149 std::vector<std::size_t> neighbors;
150 std::vector<DataType> distances;
151 knn_->radius_neighbors(keypoint, search_radius_, neighbors, distances);
152
153 if (neighbors.size() < 3) return;
154
155 // Create local reference frame
156 auto lrf = compute_local_reference_frame(cloud, keypoint, normal, neighbors);
157
158 // Compute shape context
159 const std::size_t nr_bins_r = 11; // Radial bins
160 const std::size_t nr_bins_theta = 12; // Azimuth bins
161 const std::size_t nr_bins_phi = 15; // Elevation bins
162
163 DataType min_radius = minimal_radius_;
164 DataType max_radius = search_radius_;
165 DataType log_factor = (std::log(max_radius) - std::log(min_radius)) / nr_bins_r;
166
167 for (const auto& neighbor_idx : neighbors)
168 {
169 if (neighbor_idx == keypoint_idx) continue;
170
171 const auto& neighbor = cloud.points[neighbor_idx];
172
173 // Transform to local frame
174 auto local_pt = transform_to_local_frame(neighbor, keypoint, lrf);
175
176 // Convert to spherical coordinates
177 DataType r = std::sqrt(local_pt.x * local_pt.x +
178 local_pt.y * local_pt.y +
179 local_pt.z * local_pt.z);
180
181 if (r < min_radius) continue;
182
183 DataType theta = std::atan2(local_pt.y, local_pt.x) + M_PI; // [0, 2*pi]
184 DataType phi = std::acos(std::min<DataType>(1.0,
185 std::max<DataType>(-1.0, local_pt.z / r))); // [0, pi]
186
187 // Compute bins
188 std::size_t bin_r = static_cast<std::size_t>(
189 (std::log(r) - std::log(min_radius)) / log_factor);
190 std::size_t bin_theta = static_cast<std::size_t>(
191 theta / (2.0 * M_PI) * nr_bins_theta);
192 std::size_t bin_phi = static_cast<std::size_t>(
193 phi / M_PI * nr_bins_phi);
194
195 // Clamp bins
196 if (bin_r >= nr_bins_r) bin_r = nr_bins_r - 1;
197 if (bin_theta >= nr_bins_theta) bin_theta = nr_bins_theta - 1;
198 if (bin_phi >= nr_bins_phi) bin_phi = nr_bins_phi - 1;
199
200 // Update histogram
201 std::size_t bin_idx = bin_r * nr_bins_theta * nr_bins_phi +
202 bin_theta * nr_bins_phi + bin_phi;
203 descriptor.histogram[bin_idx] += 1.0;
204 }
205
206 // Normalize by point density
207 DataType density_weight = compute_point_density(cloud, keypoint);
208
209 // Normalize histogram
210 DataType sum = 0;
211 for (auto& val : descriptor.histogram)
212 {
213 sum += val;
214 }
215 if (sum > 0)
216 {
217 for (auto& val : descriptor.histogram)
218 {
219 val = (val / sum) * density_weight;
220 }
221 }
222 }
223
224 struct LocalReferenceFrame
225 {
229 };
230
231 LocalReferenceFrame compute_local_reference_frame(
233 const toolbox::types::point_t<DataType>& keypoint,
235 const std::vector<std::size_t>& neighbors) const
236 {
237 LocalReferenceFrame lrf;
238
239 // Z-axis is the normal
240 lrf.z_axis = normal.normalize();
241
242 // Find the point with maximum angle from normal
243 DataType max_angle = 0;
245
246 for (const auto& idx : neighbors)
247 {
248 if (idx == keypoint.index) continue;
249
250 auto diff = cloud.points[idx];
251 diff.x -= keypoint.x;
252 diff.y -= keypoint.y;
253 diff.z -= keypoint.z;
254
255 auto d_norm = diff.normalize();
256 DataType angle = std::acos(std::abs(
257 d_norm.x * lrf.z_axis.x +
258 d_norm.y * lrf.z_axis.y +
259 d_norm.z * lrf.z_axis.z));
260
261 if (angle > max_angle)
262 {
263 max_angle = angle;
264 max_point = d_norm;
265 }
266 }
267
268 // X-axis perpendicular to Z
269 lrf.x_axis = max_point;
270 lrf.x_axis.x -= (lrf.x_axis.x * lrf.z_axis.x +
271 lrf.x_axis.y * lrf.z_axis.y +
272 lrf.x_axis.z * lrf.z_axis.z) * lrf.z_axis.x;
273 lrf.x_axis.y -= (lrf.x_axis.x * lrf.z_axis.x +
274 lrf.x_axis.y * lrf.z_axis.y +
275 lrf.x_axis.z * lrf.z_axis.z) * lrf.z_axis.y;
276 lrf.x_axis.z -= (lrf.x_axis.x * lrf.z_axis.x +
277 lrf.x_axis.y * lrf.z_axis.y +
278 lrf.x_axis.z * lrf.z_axis.z) * lrf.z_axis.z;
279 lrf.x_axis = lrf.x_axis.normalize();
280
281 // Y-axis = Z x X
282 lrf.y_axis.x = lrf.z_axis.y * lrf.x_axis.z - lrf.z_axis.z * lrf.x_axis.y;
283 lrf.y_axis.y = lrf.z_axis.z * lrf.x_axis.x - lrf.z_axis.x * lrf.x_axis.z;
284 lrf.y_axis.z = lrf.z_axis.x * lrf.x_axis.y - lrf.z_axis.y * lrf.x_axis.x;
285
286 return lrf;
287 }
288
289 toolbox::types::point_t<DataType> transform_to_local_frame(
292 const LocalReferenceFrame& lrf) const
293 {
294 // Translate
295 auto p = point;
296 p.x -= origin.x;
297 p.y -= origin.y;
298 p.z -= origin.z;
299
300 // Rotate
302 result.x = p.x * lrf.x_axis.x + p.y * lrf.x_axis.y + p.z * lrf.x_axis.z;
303 result.y = p.x * lrf.y_axis.x + p.y * lrf.y_axis.y + p.z * lrf.y_axis.z;
304 result.z = p.x * lrf.z_axis.x + p.y * lrf.z_axis.y + p.z * lrf.z_axis.z;
305
306 return result;
307 }
308
309 DataType compute_point_density(const toolbox::types::point_cloud_t<DataType>& cloud,
310 const toolbox::types::point_t<DataType>& point) const
311 {
312 std::vector<std::size_t> neighbors;
313 std::vector<DataType> distances;
314 knn_->radius_neighbors(point, point_density_radius_, neighbors, distances);
315
316 DataType volume = (4.0 / 3.0) * M_PI *
317 point_density_radius_ * point_density_radius_ * point_density_radius_;
318
319 return static_cast<DataType>(neighbors.size()) / volume;
320 }
321
322private:
323 const toolbox::types::point_cloud_t<DataType>* cloud_ = nullptr;
324 KNN* knn_ = nullptr;
325 DataType search_radius_ = 0.5;
326 DataType minimal_radius_ = 0.01;
327 DataType point_density_radius_ = 0.05;
328 std::size_t num_neighbors_ = 10;
329 bool enable_parallel_ = true;
330};
331
332} // namespace toolbox::pcl
void set_num_neighbors(std::size_t num_neighbors)
Definition 3dsc_extractor_old.hpp:61
void set_knn(KNN &knn)
Definition 3dsc_extractor_old.hpp:51
void set_search_radius(DataType radius)
Definition 3dsc_extractor_old.hpp:56
void enable_parallel_impl(bool enable)
Definition 3dsc_extractor_old.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< dsc3d_signature_t< DataType > > > descriptors) const
Definition 3dsc_extractor_old.hpp:113
void set_input(const toolbox::types::point_cloud_t< DataType > &cloud)
Definition 3dsc_extractor_old.hpp:46
void compute_impl(const toolbox::types::point_cloud_t< DataType > &cloud, const std::vector< std::size_t > &keypoint_indices, std::vector< dsc3d_signature_t< DataType > > &descriptors) const
Definition 3dsc_extractor_old.hpp:81
void set_minimal_radius(DataType radius)
Definition 3dsc_extractor_old.hpp:66
void set_point_density_radius(DataType radius)
Definition 3dsc_extractor_old.hpp:71
包含点和相关数据的点云类 / 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
void parallel_for_each(Iterator begin, Iterator end, Function func)
使用TBB并行对范围[begin, end)中的每个元素应用函数
Definition parallel_raw.hpp:21
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
3D形状上下文描述子签名 / 3D Shape Context descriptor signature
Definition 3dsc_extractor.hpp:40
DataType distance(const dsc3d_signature_t &other) const
Definition 3dsc_extractor_old.hpp:21
std::array< DataType, HISTOGRAM_SIZE > histogram
直方图数据 / Histogram data
Definition 3dsc_extractor.hpp:44
static constexpr std::size_t HISTOGRAM_SIZE
直方图大小:11 × 12 × 15 / Histogram size: 11 × 12 × 15
Definition 3dsc_extractor.hpp:43
bool operator==(const dsc3d_signature_t &other) const
Definition 3dsc_extractor_old.hpp:32
3D点/向量模板类 / A 3D point/vector template class
Definition point.hpp:48
T x
X坐标 / X coordinate.
Definition point.hpp:51
auto normalize() const -> point_t< double >
返回归一化向量(单位长度) / Return normalized vector (unit length)
Definition point_impl.hpp:105
T z
Z坐标 / Z coordinate.
Definition point.hpp:53
T y
Y坐标 / Y coordinate.
Definition point.hpp:52