cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
aa_icp_impl.hpp
Go to the documentation of this file.
1#pragma once
2
4
5namespace toolbox::pcl
6{
7
8template<typename DataType, typename KNNSearcher, typename BaseICP>
10 const transformation_t& initial_guess, result_type& result)
11{
12 // 初始化
13 transformation_t current_transform = initial_guess;
14 transformation_t previous_transform = current_transform;
15
16 DataType previous_error = std::numeric_limits<DataType>::max();
17 bool converged = false;
18
19 // 清空历史记录
20 m_g_history.clear();
21 m_x_history.clear();
22 m_initialized = false;
23
24 // 传递基类参数到基础ICP,并设置点云
25 m_base_icp.set_source(this->m_source_cloud);
26 m_base_icp.set_target(this->m_target_cloud);
27 m_base_icp.set_max_iterations(10); // 设置更多迭代次数
28 m_base_icp.set_max_correspondence_distance(this->m_max_correspondence_distance);
29 m_base_icp.set_transformation_epsilon(this->m_transformation_epsilon);
30 m_base_icp.set_euclidean_fitness_epsilon(this->m_euclidean_fitness_epsilon);
31
32 // 迭代优化
33 for (std::size_t iter = 0; iter < this->m_max_iterations; ++iter) {
34 // 执行一步基础ICP
35 DataType current_error;
36 std::size_t num_correspondences;
37 transformation_t icp_transform = perform_base_icp_step(
38 current_transform, current_error, num_correspondences);
39
40 if (num_correspondences == 0) {
41 LOG_ERROR_S << "未找到有效的对应关系 / No valid correspondences found";
42 result.termination_reason = "no correspondences";
43 return false;
44 }
45
46 // 转换为向量表示
47 VectorX x_current = transformation_to_vector(current_transform);
48 VectorX x_icp = transformation_to_vector(icp_transform);
49
50 // 计算定点迭代的残差 g(x) = f(x) - x
51 VectorX g_current = x_icp - x_current;
52
53 // 更新历史记录
54 m_x_history.push_back(x_current);
55 m_g_history.push_back(g_current);
56
57 // 限制历史记录大小
58 if (m_x_history.size() > m_anderson_m + 1) {
59 m_x_history.pop_front();
60 m_g_history.pop_front();
61 }
62
63 // 计算下一次迭代的变换
64 VectorX x_next;
65
66 if (m_x_history.size() <= 1 || iter < 2) {
67 // 前几次迭代使用标准ICP更新
68 x_next = x_icp;
69 } else {
70 // 使用Anderson加速
71 x_next = anderson_acceleration_update(m_g_history, m_x_history);
72
73 // 安全保护:检查Anderson加速的结果
74 if (m_enable_safeguarding) {
75 if (!is_numerically_stable(x_next)) {
76 LOG_WARN_S << "Anderson加速结果不稳定,回退到标准ICP / "
77 "Anderson acceleration unstable, falling back to standard ICP";
78 x_next = x_icp;
79
80 // 清空历史,重新开始
81 m_x_history.clear();
82 m_g_history.clear();
83 m_x_history.push_back(x_current);
84 m_g_history.push_back(g_current);
85 } else {
86 // 计算新变换对应的误差
87 transformation_t test_transform = vector_to_transformation(x_next);
88 DataType test_error;
89 std::size_t test_corr;
90 perform_base_icp_step(test_transform, test_error, test_corr);
91
92 // 如果误差增加太多,使用阻尼
93 if (test_error > current_error * (1.0 + 0.1)) {
94 x_next = m_beta * x_next + (1.0 - m_beta) * x_icp;
95 }
96 }
97 }
98 }
99
100 // 更新变换
101 transformation_t next_transform = vector_to_transformation(x_next);
102
103 // 记录迭代状态
104 DataType error_change = std::abs(current_error - previous_error);
105 this->record_iteration(result, iter, next_transform, current_error,
106 error_change, num_correspondences);
107
108 // 检查收敛
109 std::string termination_reason;
110 if (this->has_converged(iter, next_transform, current_transform,
111 current_error, previous_error, termination_reason)) {
112 converged = true;
113 result.termination_reason = termination_reason;
114 break;
115 }
116
117 // 更新状态
118 previous_transform = current_transform;
119 current_transform = next_transform;
120 previous_error = current_error;
121 }
122
123 // 设置结果
124 result.transformation = current_transform;
125 result.converged = converged;
126 result.iterations_performed = result.history.size();
127 result.final_error = previous_error;
128
129 if (!converged && result.termination_reason.empty()) {
130 result.termination_reason = "maximum iterations reached";
131 }
132
133 return true;
134}
135
136template<typename DataType, typename KNNSearcher, typename BaseICP>
139 const transformation_t& transform) const
140{
141 VectorX vec(12);
142
143 // 将4x4矩阵的前3行展平为向量
144 for (int i = 0; i < 3; ++i) {
145 for (int j = 0; j < 4; ++j) {
146 vec[i * 4 + j] = transform(i, j);
147 }
148 }
149
150 return vec;
151}
152
153template<typename DataType, typename KNNSearcher, typename BaseICP>
156 const VectorX& vec) const
157{
158 transformation_t transform = transformation_t::Identity();
159
160 // 从向量恢复4x4矩阵的前3行
161 for (int i = 0; i < 3; ++i) {
162 for (int j = 0; j < 4; ++j) {
163 transform(i, j) = vec[i * 4 + j];
164 }
165 }
166
167 // 正交化旋转矩阵部分(使用SVD)
168 Eigen::Matrix<DataType, 3, 3> R = transform.template block<3, 3>(0, 0);
169 Eigen::JacobiSVD<Eigen::Matrix<DataType, 3, 3>> svd(R, Eigen::ComputeFullU | Eigen::ComputeFullV);
170 R = svd.matrixU() * svd.matrixV().transpose();
171
172 // 处理反射
173 if (R.determinant() < 0) {
174 Eigen::Matrix<DataType, 3, 3> V = svd.matrixV();
175 V.col(2) *= -1;
176 R = svd.matrixU() * V.transpose();
177 }
178
179 transform.template block<3, 3>(0, 0) = R;
180
181 return transform;
182}
183
184template<typename DataType, typename KNNSearcher, typename BaseICP>
187 const transformation_t& current_transform,
188 DataType& error,
189 std::size_t& num_correspondences)
190{
191 // 创建临时结果对象
192 result_type temp_result;
193
194 LOG_DEBUG_S << "AA-ICP: 执行基础ICP步骤,源点云大小=" << this->m_source_cloud->size()
195 << ",目标点云大小=" << this->m_target_cloud->size()
196 << ",最大对应距离=" << this->m_max_correspondence_distance;
197
198 // 执行一步基础ICP
199 m_base_icp.align(current_transform, temp_result);
200
201 // 提取结果
202 error = temp_result.final_error;
203 num_correspondences = temp_result.history.empty() ? 0 :
204 temp_result.history.back().num_correspondences;
205
206 return temp_result.transformation;
207}
208
209template<typename DataType, typename KNNSearcher, typename BaseICP>
212 const std::deque<VectorX>& g_history,
213 const std::deque<VectorX>& x_history)
214{
215 const std::size_t m_k = std::min(m_anderson_m, g_history.size() - 1);
216
217 if (m_k == 0) {
218 // 标准定点迭代
219 return x_history.back() + g_history.back();
220 }
221
222 // 构建矩阵 G_k = [g_k - g_{k-1}, ..., g_k - g_{k-m_k}]
223 MatrixX G_k(g_history.back().size(), m_k);
224
225 for (std::size_t i = 0; i < m_k; ++i) {
226 G_k.col(i) = g_history[g_history.size() - 1] - g_history[g_history.size() - 2 - i];
227 }
228
229 // 求解最小二乘问题:min ||G_k * gamma + g_k||^2
230 // 使用QR分解求解
231 Eigen::HouseholderQR<MatrixX> qr(G_k);
232 VectorX gamma = qr.solve(-g_history.back());
233
234 // 检查解的数值稳定性
235 DataType gamma_norm = gamma.norm();
236 if (gamma_norm > 10.0) {
237 // 如果系数太大,进行截断
238 gamma *= 10.0 / gamma_norm;
239 }
240
241 // 计算加权组合
242 VectorX x_next = x_history.back() + g_history.back();
243
244 for (std::size_t i = 0; i < m_k; ++i) {
245 std::size_t idx = x_history.size() - 2 - i;
246 x_next -= gamma[i] * (x_history[idx + 1] - x_history[idx] +
247 g_history[idx + 1] - g_history[idx]);
248 }
249
250 return x_next;
251}
252
253template<typename DataType, typename KNNSearcher, typename BaseICP>
255 const VectorX& vec) const
256{
257 // 检查是否包含NaN或Inf
258 if (!vec.allFinite()) {
259 return false;
260 }
261
262 // 检查向量范数是否合理
263 DataType norm = vec.norm();
264 if (norm > 1e6 || norm < 1e-6) {
265 return false;
266 }
267
268 // 检查变换矩阵的合理性
269 transformation_t transform = vector_to_transformation(vec);
270
271 // 旋转部分的行列式应该接近1
272 DataType det = transform.template block<3, 3>(0, 0).determinant();
273 if (std::abs(det - 1.0) > 0.1) {
274 return false;
275 }
276
277 // 平移部分不应该太大
278 DataType translation_norm = transform.template block<3, 1>(0, 3).norm();
279 if (translation_norm > 100.0) {
280 return false;
281 }
282
283 return true;
284}
285
286} // namespace toolbox::pcl
Eigen::Matrix< DataType, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Definition aa_icp.hpp:53
transformation_t vector_to_transformation(const VectorX &vec) const
将向量表示转换为变换矩阵 / Convert vector representation to transformation matrix
Definition aa_icp_impl.hpp:155
VectorX transformation_to_vector(const transformation_t &transform) const
将变换矩阵转换为向量表示 / Convert transformation matrix to vector representation
Definition aa_icp_impl.hpp:138
bool align_impl(const transformation_t &initial_guess, result_type &result)
执行配准 / Perform registration
Definition aa_icp_impl.hpp:9
bool is_numerically_stable(const VectorX &vec) const
检查数值稳定性 / Check numerical stability
Definition aa_icp_impl.hpp:254
Eigen::Matrix< DataType, Eigen::Dynamic, 1 > VectorX
Definition aa_icp.hpp:52
Eigen::Matrix< DataType, 4, 4 > transformation_t
Definition base_fine_registration.hpp:43
VectorX anderson_acceleration_update(const std::deque< VectorX > &g_history, const std::deque< VectorX > &x_history)
Anderson加速更新 / Anderson acceleration update.
Definition aa_icp_impl.hpp:211
transformation_t perform_base_icp_step(const transformation_t &current_transform, DataType &error, std::size_t &num_correspondences)
执行一步基础ICP迭代 / Perform one step of base ICP iteration
Definition aa_icp_impl.hpp:186
Eigen::Matrix< DataType, 4, 4 > transformation_t
Definition base_fine_registration.hpp:43
#define LOG_DEBUG_S
DEBUG级别流式日志的宏 / Macro for DEBUG level stream logging.
Definition thread_logger.hpp:1329
#define LOG_ERROR_S
ERROR级别流式日志的宏 / Macro for ERROR level stream logging.
Definition thread_logger.hpp:1332
#define LOG_WARN_S
WARN级别流式日志的宏 / Macro for WARN level stream logging.
Definition thread_logger.hpp:1331
Definition base_correspondence_generator.hpp:18
细配准结果 / Fine registration result
Definition registration_result.hpp:46
std::vector< iteration_state_t< DataType > > history
迭代历史(可选) / Iteration history (optional)
Definition registration_result.hpp:61
std::string termination_reason
终止原因 / Termination reason
Definition registration_result.hpp:58
transformation_t transformation
最终变换 / Final transformation
Definition registration_result.hpp:49
bool converged
是否收敛 / Whether converged
Definition registration_result.hpp:57
DataType final_error
最终误差 / Final error
Definition registration_result.hpp:53
std::size_t iterations_performed
执行的迭代次数 / Iterations performed
Definition registration_result.hpp:55