cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
pca_norm_impl.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <Eigen/Dense>
4#include <Eigen/Eigenvalues>
6#include <future>
7#include <memory>
8
9namespace toolbox::pcl
10{
11
12template<typename DataType, typename KNN>
14 const point_cloud& cloud)
15{
16 auto cloud_ptr = std::make_shared<point_cloud>(cloud);
17 return set_input_impl(cloud_ptr);
18}
19
20template<typename DataType, typename KNN>
22 const point_cloud_ptr& cloud)
23{
24 m_cloud = cloud;
25 if (m_knn && cloud) {
26 m_knn->set_input(cloud);
27 }
28 return cloud ? cloud->size() : 0;
29}
30
31template<typename DataType, typename KNN>
33 const knn_type& knn)
34{
35 m_knn = const_cast<knn_type*>(&knn);
36 if (m_cloud && m_knn) {
37 m_knn->set_input(m_cloud);
38 }
39 return 0;
40}
41
42template<typename DataType, typename KNN>
44 std::size_t num_neighbors)
45{
46 m_num_neighbors = num_neighbors;
47 return m_num_neighbors;
48}
49
50template<typename DataType, typename KNN>
53{
54 auto output = std::make_shared<point_cloud>();
55 extract_impl(output);
56 return *output;
57}
58
59template<typename DataType, typename KNN>
61{
62 if (!m_cloud || !m_knn || m_num_neighbors == 0) {
63 return;
64 }
65
66 const std::size_t num_points = m_cloud->size();
67 output->points.clear();
68 output->normals.clear();
69 output->normals.resize(num_points);
70
71 if (m_enable_parallel) {
72 // Parallel processing
74 const std::size_t num_threads = thread_pool.get_thread_count();
75 const std::size_t chunk_size = (num_points + num_threads - 1) / num_threads;
76
77 std::vector<std::future<void>> futures;
78 futures.reserve(num_threads);
79
80 for (std::size_t t = 0; t < num_threads; ++t) {
81 const std::size_t start_idx = t * chunk_size;
82 const std::size_t end_idx = std::min(start_idx + chunk_size, num_points);
83
84 if (start_idx >= end_idx) break;
85
86 auto future = thread_pool.submit([this, output, start_idx, end_idx]() {
87 this->compute_normals_range(output, start_idx, end_idx);
88 });
89
90 futures.push_back(std::move(future));
91 }
92
93 // Wait for all tasks to complete
94 for (auto& future : futures) {
95 future.get();
96 }
97 } else {
98 // Sequential processing
99 compute_normals_range(output, 0, num_points);
100 }
101
102 // Copy points from input cloud
103 output->points = m_cloud->points;
104}
105
106template<typename DataType, typename KNN>
108 point_cloud_ptr output, std::size_t start_idx, std::size_t end_idx)
109{
110 std::vector<std::size_t> indices;
111 std::vector<data_type> distances;
112
113 for (std::size_t i = start_idx; i < end_idx; ++i) {
114 const auto& query_point = m_cloud->points[i];
115
116 // Find k-nearest neighbors
117 indices.clear();
118 distances.clear();
119
120 if (!m_knn->kneighbors(query_point, m_num_neighbors, indices, distances)) {
121 // If KNN search fails, use default normal (0, 0, 1)
122 output->normals[i] = point_t<data_type>(0, 0, 1);
123 continue;
124 }
125
126 // Compute normal using PCA
127 output->normals[i] = compute_pca_normal(indices);
128 }
129}
130
131template<typename DataType, typename KNN>
132point_t<typename pca_norm_extractor_t<DataType, KNN>::data_type>
133pca_norm_extractor_t<DataType, KNN>::compute_pca_normal(
134 const std::vector<std::size_t>& indices)
135{
136 if (indices.size() < 3) {
137 // Need at least 3 points for PCA
138 return point_t<data_type>(0, 0, 1);
139 }
140
141 // Compute centroid
142 Eigen::Vector3d centroid = Eigen::Vector3d::Zero();
143 for (const auto& idx : indices) {
144 const auto& pt = m_cloud->points[idx];
145 centroid += Eigen::Vector3d(static_cast<double>(pt.x),
146 static_cast<double>(pt.y),
147 static_cast<double>(pt.z));
148 }
149 centroid /= static_cast<double>(indices.size());
150
151 // Compute covariance matrix
152 Eigen::Matrix3d covariance = Eigen::Matrix3d::Zero();
153 for (const auto& idx : indices) {
154 const auto& pt = m_cloud->points[idx];
155 Eigen::Vector3d point_vec(static_cast<double>(pt.x),
156 static_cast<double>(pt.y),
157 static_cast<double>(pt.z));
158 Eigen::Vector3d centered = point_vec - centroid;
159 covariance += centered * centered.transpose();
160 }
161 covariance /= static_cast<double>(indices.size() - 1);
162
163 // Compute eigenvalues and eigenvectors
164 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigen_solver(covariance);
165 if (eigen_solver.info() != Eigen::Success) {
166 // If eigenvalue computation fails, use default normal
167 return point_t<data_type>(0, 0, 1);
168 }
169
170 // The normal is the eigenvector corresponding to the smallest eigenvalue
171 const Eigen::Vector3d& normal_vec = eigen_solver.eigenvectors().col(0);
172
173 // Convert back to data_type and create point_t
174 return point_t<data_type>(static_cast<data_type>(normal_vec.x()),
175 static_cast<data_type>(normal_vec.y()),
176 static_cast<data_type>(normal_vec.z()));
177}
178
179} // namespace toolbox::pcl
static thread_pool_singleton_t & instance()
获取单例实例/Get the singleton instance
Definition thread_pool_singleton.hpp:23
基于PCA的法向量提取器 / PCA-based normal extractor
Definition pca_norm.hpp:56
typename base_type::knn_type knn_type
Definition pca_norm.hpp:61
point_cloud extract_impl()
提取法向量的实现 / Implementation of extracting normals
Definition pca_norm_impl.hpp:52
typename base_type::point_cloud point_cloud
Definition pca_norm.hpp:62
std::size_t set_knn_impl(const knn_type &knn)
设置KNN搜索算法的实现 / Implementation of setting KNN search algorithm
Definition pca_norm_impl.hpp:32
typename base_type::point_cloud_ptr point_cloud_ptr
Definition pca_norm.hpp:63
std::size_t set_num_neighbors_impl(std::size_t num_neighbors)
设置近邻数量的实现 / Implementation of setting number of neighbors
Definition pca_norm_impl.hpp:43
std::size_t set_input_impl(const point_cloud &cloud)
设置输入点云的实现 / Implementation of setting input point cloud
Definition pca_norm_impl.hpp:13
Definition base_correspondence_generator.hpp:18
3D点/向量模板类 / A 3D point/vector template class
Definition point.hpp:48