cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
iss_keypoints_impl.hpp
Go to the documentation of this file.
1#pragma once
2
5#include <Eigen/Dense>
6#include <Eigen/Eigenvalues>
7#include <algorithm>
8#include <cmath>
9#include <future>
10#include <vector>
11
12namespace toolbox::pcl
13{
14
15template<typename DataType, typename KNN>
17{
18 m_cloud = std::make_shared<point_cloud>(cloud);
19 return m_cloud->size();
20}
21
22template<typename DataType, typename KNN>
24{
25 m_cloud = cloud;
26 return m_cloud->size();
27}
28
29template<typename DataType, typename KNN>
31{
32 m_knn = const_cast<knn_type*>(&knn);
33 if (m_cloud) {
34 m_knn->set_input(m_cloud->points);
35 }
36 return m_cloud ? m_cloud->size() : 0;
37}
38
39template<typename DataType, typename KNN>
41{
42 m_salient_radius = radius;
43 return 0;
44}
45
46template<typename DataType, typename KNN>
48{
49 m_enable_parallel = enable;
50}
51
52template<typename DataType, typename KNN>
55{
56 if (!m_cloud || !m_knn || point_idx >= m_cloud->size()) {
57 return ISSInfo{0, 0, 0, 0, false};
58 }
59
60 const auto& query_point = m_cloud->points[point_idx];
61 std::vector<std::size_t> neighbor_indices;
62 std::vector<data_type> neighbor_distances;
63
64 // 在显著性半径内查找邻居 / Find neighbors within salient radius
65 m_knn->radius_neighbors(query_point, m_salient_radius, neighbor_indices, neighbor_distances);
66
67 if (neighbor_indices.size() < m_min_neighbors) {
68 return ISSInfo{0, 0, 0, 0, false};
69 }
70
71 // 基于距离计算权重函数 / Compute weight function based on distance
72 auto compute_weight = [this](data_type distance) -> double {
73 if (distance >= m_salient_radius) return 0.0;
74 const double ratio = static_cast<double>(distance) / static_cast<double>(m_salient_radius);
75 return 1.0 - ratio; // 线性权重函数 / Linear weight function
76 };
77
78 // 计算加权散布矩阵 / Compute weighted scatter matrix
79 Eigen::Matrix3d scatter_matrix = Eigen::Matrix3d::Zero();
80 double total_weight = 0.0;
81
82 for (std::size_t i = 0; i < neighbor_indices.size(); ++i) {
83 const auto& neighbor_point = m_cloud->points[neighbor_indices[i]];
84 const double weight = compute_weight(neighbor_distances[i]);
85
86 if (weight > 0.0) {
87 // 从查询点到邻居的向量 / Vector from query point to neighbor
88 Eigen::Vector3d diff(
89 static_cast<double>(neighbor_point.x - query_point.x),
90 static_cast<double>(neighbor_point.y - query_point.y),
91 static_cast<double>(neighbor_point.z - query_point.z)
92 );
93
94 scatter_matrix += weight * (diff * diff.transpose());
95 total_weight += weight;
96 }
97 }
98
99 if (total_weight < 1e-10) {
100 return ISSInfo{0, 0, 0, 0, false};
101 }
102
103 scatter_matrix /= total_weight;
104
105 // 计算特征值 / Compute eigenvalues
106 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigen_solver(scatter_matrix);
107 if (eigen_solver.info() != Eigen::Success) {
108 return ISSInfo{0, 0, 0, 0, false};
109 }
110
111 const Eigen::Vector3d& eigenvalues = eigen_solver.eigenvalues();
112
113 // 按降序排序特征值:λ1 >= λ2 >= λ3 / Sort eigenvalues in descending order: λ1 >= λ2 >= λ3
114 std::vector<double> sorted_eigenvals = {eigenvalues(2), eigenvalues(1), eigenvalues(0)};
115 std::sort(sorted_eigenvals.rbegin(), sorted_eigenvals.rend());
116
117 const double lambda1 = sorted_eigenvals[0];
118 const double lambda2 = sorted_eigenvals[1];
119 const double lambda3 = sorted_eigenvals[2];
120
121 // 检查ISS准则 / Check ISS criteria
122 bool is_valid = true;
123
124 // 避免除零 / Avoid division by zero
125 if (lambda1 < 1e-10) {
126 is_valid = false;
127 } else {
128 // 检查特征值比率 / Check eigenvalue ratios
129 const double ratio21 = lambda2 / lambda1;
130 const double ratio32 = (lambda2 > 1e-10) ? (lambda3 / lambda2) : 0.0;
131
132 if (ratio21 > m_threshold21 || ratio32 > m_threshold32) {
133 is_valid = false;
134 }
135 }
136
137 // ISS显著性是最小的特征值 / ISS saliency is the smallest eigenvalue
138 const double saliency = lambda3;
139
140 return ISSInfo{
141 static_cast<data_type>(lambda1),
142 static_cast<data_type>(lambda2),
143 static_cast<data_type>(lambda3),
144 static_cast<data_type>(saliency),
145 is_valid
146 };
147}
148
149template<typename DataType, typename KNN>
150void iss_keypoint_extractor_t<DataType, KNN>::compute_iss_range(
151 std::vector<ISSInfo>& iss_responses,
152 std::size_t start_idx,
153 std::size_t end_idx)
154{
155 for (std::size_t i = start_idx; i < end_idx; ++i) {
156 iss_responses[i] = compute_iss_response(i);
157 }
158}
159
160template<typename DataType, typename KNN>
161std::vector<typename iss_keypoint_extractor_t<DataType, KNN>::ISSInfo>
162iss_keypoint_extractor_t<DataType, KNN>::compute_all_iss_responses()
163{
164 if (!m_cloud) {
165 return {};
166 }
167
168 const std::size_t num_points = m_cloud->size();
169 std::vector<ISSInfo> iss_responses(num_points);
170
171 if (m_enable_parallel && num_points > k_parallel_threshold) {
172 // 并行计算 / Parallel computation
173 const std::size_t num_threads = toolbox::base::thread_pool_singleton_t::instance().get_thread_count();
174 const std::size_t chunk_size = (num_points + num_threads - 1) / num_threads;
175
176 std::vector<std::future<void>> futures;
177 for (std::size_t t = 0; t < num_threads; ++t) {
178 const std::size_t start_idx = t * chunk_size;
179 const std::size_t end_idx = std::min(start_idx + chunk_size, num_points);
180
181 if (start_idx < end_idx) {
182 futures.emplace_back(
184 [this, &iss_responses, start_idx, end_idx]() {
185 compute_iss_range(iss_responses, start_idx, end_idx);
186 }
187 )
188 );
189 }
190 }
191
192 // 等待所有线程完成 / Wait for all threads to complete
193 for (auto& future : futures) {
194 future.wait();
195 }
196 } else {
197 // 顺序计算 / Sequential computation
198 compute_iss_range(iss_responses, 0, num_points);
199 }
200
201 return iss_responses;
202}
203
204template<typename DataType, typename KNN>
206iss_keypoint_extractor_t<DataType, KNN>::apply_non_maxima_suppression(
207 const std::vector<ISSInfo>& iss_responses)
208{
209 if (!m_cloud || iss_responses.empty()) {
210 return {};
211 }
212
213 indices_vector keypoints;
214 const std::size_t num_points = m_cloud->size();
215
216 for (std::size_t i = 0; i < num_points; ++i) {
217 const auto& current_iss = iss_responses[i];
218
219 // 跳过无效的点 / Skip invalid points
220 if (!current_iss.is_valid || current_iss.saliency <= 0) {
221 continue;
222 }
223
224 // 在非极大值抑制半径内查找邻居 / Find neighbors within non-maxima suppression radius
225 const auto& query_point = m_cloud->points[i];
226 std::vector<std::size_t> neighbor_indices;
227 std::vector<data_type> neighbor_distances;
228
229 m_knn->radius_neighbors(query_point, m_non_maxima_radius, neighbor_indices, neighbor_distances);
230
231 // 检查当前点是否为局部最大值 / Check if current point is local maximum
232 bool is_local_maximum = true;
233 for (const auto& neighbor_idx : neighbor_indices) {
234 if (neighbor_idx != i && neighbor_idx < iss_responses.size()) {
235 const auto& neighbor_iss = iss_responses[neighbor_idx];
236 if (neighbor_iss.is_valid && neighbor_iss.saliency > current_iss.saliency) {
237 is_local_maximum = false;
238 break;
239 }
240 }
241 }
242
243 if (is_local_maximum) {
244 keypoints.push_back(i);
245 }
246 }
247
248 return keypoints;
249}
250
251template<typename DataType, typename KNN>
254{
255 if (!m_cloud || !m_knn) {
256 return {};
257 }
258
259 // 计算所有点的ISS响应 / Compute ISS responses for all points
260 auto iss_responses = compute_all_iss_responses();
261
262 // 应用非极大值抑制找到关键点 / Apply non-maxima suppression to find keypoints
263 return apply_non_maxima_suppression(iss_responses);
264}
265
266template<typename DataType, typename KNN>
268{
269 keypoint_indices = extract_impl();
270}
271
272template<typename DataType, typename KNN>
275{
276 auto keypoint_indices = extract_impl();
277
278 point_cloud keypoints;
279 keypoints.points.reserve(keypoint_indices.size());
280
281 for (const auto& idx : keypoint_indices) {
282 keypoints.points.push_back(m_cloud->points[idx]);
283 }
284
285 return keypoints;
286}
287
288template<typename DataType, typename KNN>
290{
291 auto keypoint_indices = extract_impl();
292
293 output->points.clear();
294 output->points.reserve(keypoint_indices.size());
295
296 for (const auto& idx : keypoint_indices) {
297 output->points.push_back(m_cloud->points[idx]);
298 }
299}
300
301} // namespace toolbox::pcl
static thread_pool_singleton_t & instance()
获取单例实例/Get the singleton instance
Definition thread_pool_singleton.hpp:23
ISS (Intrinsic Shape Signatures) 关键点提取器 / ISS (Intrinsic Shape Signatures) keypoint extractor.
Definition iss_keypoints.hpp:61
indices_vector extract_impl()
CRTP实现方法 - 提取关键点 / CRTP implementation - extract keypoints.
Definition iss_keypoints_impl.hpp:253
void enable_parallel_impl(bool enable)
CRTP实现方法 - 启用并行处理 / CRTP implementation - enable parallel processing.
Definition iss_keypoints_impl.hpp:47
point_cloud extract_keypoints_impl()
Definition iss_keypoints_impl.hpp:274
typename base_type::indices_vector indices_vector
Definition iss_keypoints.hpp:70
typename base_type::point_cloud point_cloud
Definition iss_keypoints.hpp:68
std::size_t set_input_impl(const point_cloud &cloud)
CRTP实现方法 - 设置输入点云 / CRTP implementation - set input point cloud.
Definition iss_keypoints_impl.hpp:16
std::size_t set_search_radius_impl(data_type radius)
CRTP实现方法 - 设置搜索半径 / CRTP implementation - set search radius.
Definition iss_keypoints_impl.hpp:40
typename base_type::point_cloud_ptr point_cloud_ptr
Definition iss_keypoints.hpp:69
std::size_t set_knn_impl(const knn_type &knn)
CRTP实现方法 - 设置KNN算法 / CRTP implementation - set KNN algorithm.
Definition iss_keypoints_impl.hpp:30
typename base_type::data_type data_type
Definition iss_keypoints.hpp:66
typename base_type::knn_type knn_type
Definition iss_keypoints.hpp:67
Definition base_correspondence_generator.hpp:18