-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Add a part of the new rigid registration method [FRICP] #6199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
yaoyx689
wants to merge
24
commits into
PointCloudLibrary:master
Choose a base branch
from
yaoyx689:add_fricp
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,392
−0
Open
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
aefe5db
add a part of the FRICP (robust transformation estimation)
yaoyx689 213e84f
update
yaoyx689 f2f6dea
Correct format
yaoyx689 f5d0bda
Merge branch 'PointCloudLibrary:master' into add_fricp
duanbotu123 7c81280
add Anderson acceleration fricp.hpp etc.UPdate cmakelist
duanbotu123 d87a99e
fix bug
duanbotu123 574f036
fix bug
duanbotu123 266ab88
fix bug in test
duanbotu123 b1a1a7b
fix the bug of parameter
duanbotu123 d329abf
Update test
duanbotu123 3f9a439
repush
duanbotu123 3d70839
Merge branch 'PointCloudLibrary:master' into add_fricp
duanbotu123 8efff92
fix bug in clang-tidy,merge the new update in pcl
duanbotu123 3fc1db5
fix bug in clang-tidy,merge the new update in pcl
duanbotu123 34d5dc3
fix bug in clang-tidy again
duanbotu123 e8acb9f
fix bug in clang-tidy again
duanbotu123 d5bdecc
fix bug in clang-tidy again
duanbotu123 ee430dc
fix bug in clang-tidy again
duanbotu123 0fe5fdc
Merge branch 'PointCloudLibrary:master' into add_fricp
duanbotu123 08d883c
Address all review comments in PR 6199
duanbotu123 397b7f3
Fix FRICP KdTree/Search mismatch in test_registration_api
duanbotu123 b45c4ea
Update registration/include/pcl/registration/fricp.h
duanbotu123 6ba19c8
Apply PR6199 review fixes without build artifacts
duanbotu123 1e17bf6
Update registration/include/pcl/registration/fricp.h
duanbotu123 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
186 changes: 186 additions & 0 deletions
186
registration/include/pcl/registration/anderson_acceleration.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| #pragma once | ||
|
|
||
| #include <pcl/exceptions.h> | ||
| #include <pcl/memory.h> | ||
|
|
||
| #include <Eigen/Core> | ||
| #include <Eigen/QR> | ||
|
|
||
| #include <algorithm> | ||
| #include <cstddef> | ||
|
|
||
| namespace pcl { | ||
| namespace registration { | ||
|
|
||
| /** | ||
| * \brief Lightweight Anderson acceleration helper used to speed up fixed-point | ||
| * iterations in FRICP. | ||
| * | ||
| * The class stores a short history of the most recent residuals and solves the | ||
| * normal equations following the scheme described in "Fast and Robust Iterative | ||
| * Closest Point", Zhang et al., 2022. | ||
| * | ||
| * Only double precision is supported internally to maximise numerical stability. | ||
| */ | ||
| class AndersonAcceleration { | ||
| public: | ||
| AndersonAcceleration() = default; | ||
|
|
||
| /** | ||
| * \brief Initialise the accelerator with a circular buffer of size \a history. | ||
| * | ||
| * \param[in] history Number of previous iterates to keep (m in the paper). | ||
| * \param[in] dimension Dimensionality of the flattened state vector. | ||
| * \param[in] initial_state Pointer to the initial state (expects | ||
| * \a dimension doubles). | ||
| */ | ||
| inline void | ||
| init(std::size_t history, std::size_t dimension, const double* initial_state) | ||
| { | ||
| if ((history == 0) || (dimension == 0)) { | ||
| PCL_THROW_EXCEPTION(pcl::BadArgumentException, | ||
| "AndersonAcceleration::init expects non-zero sizes"); | ||
| } | ||
|
|
||
| history_length_ = history; | ||
| dimension_ = dimension; | ||
| iteration_ = 0; | ||
| column_index_ = 0; | ||
| initialized_ = true; | ||
|
|
||
| current_u_.resize(dimension_); | ||
| current_F_.resize(dimension_); | ||
| prev_dG_.setZero(dimension_, history_length_); | ||
| prev_dF_.setZero(dimension_, history_length_); | ||
| normal_eq_matrix_.setZero(history_length_, history_length_); | ||
| theta_.setZero(history_length_); | ||
| dF_scale_.setZero(history_length_); | ||
|
|
||
| current_u_ = Eigen::Map<const Eigen::VectorXd>(initial_state, dimension_); | ||
| } | ||
|
|
||
| inline bool | ||
| isInitialized() const | ||
| { | ||
| return initialized_; | ||
| } | ||
|
|
||
| inline std::size_t | ||
| history() const | ||
| { | ||
| return history_length_; | ||
| } | ||
|
|
||
| inline std::size_t | ||
| dimension() const | ||
| { | ||
| return dimension_; | ||
| } | ||
|
|
||
| inline void | ||
| replace(const double* state) | ||
| { | ||
| if (!initialized_) | ||
| return; | ||
| current_u_ = Eigen::Map<const Eigen::VectorXd>(state, dimension_); | ||
| } | ||
|
|
||
| inline void | ||
| reset(const double* state) | ||
| { | ||
| if (!initialized_) | ||
| return; | ||
| iteration_ = 0; | ||
| column_index_ = 0; | ||
| current_u_ = Eigen::Map<const Eigen::VectorXd>(state, dimension_); | ||
| } | ||
|
|
||
| /** | ||
| * \brief Apply one Anderson acceleration update. | ||
| * | ||
| * \param[in] next_state Flattened state obtained from the fixed-point iteration. | ||
| * \return Reference to the accelerated state vector. | ||
| */ | ||
| inline const Eigen::VectorXd& | ||
| compute(const double* next_state) | ||
| { | ||
| if (!initialized_) { | ||
| PCL_THROW_EXCEPTION(pcl::PCLException, | ||
| "AndersonAcceleration::compute called before init"); | ||
| } | ||
|
|
||
| Eigen::Map<const Eigen::VectorXd> G(next_state, dimension_); | ||
| current_F_ = G - current_u_; | ||
|
|
||
| constexpr double eps = 1e-14; | ||
|
|
||
| if (iteration_ == 0) { | ||
| prev_dF_.col(0) = -current_F_; | ||
| prev_dG_.col(0) = -G; | ||
| current_u_ = G; | ||
| } | ||
| else { | ||
| prev_dF_.col(column_index_) += current_F_; | ||
| prev_dG_.col(column_index_) += G; | ||
|
|
||
| double scale = std::max(eps, prev_dF_.col(column_index_).norm()); | ||
| dF_scale_(column_index_) = scale; | ||
| prev_dF_.col(column_index_) /= scale; | ||
|
|
||
| const std::size_t m_k = std::min(history_length_, iteration_); | ||
|
|
||
| if (m_k == 1) { | ||
| theta_(0) = 0.0; | ||
| const double dF_norm = prev_dF_.col(column_index_).norm(); | ||
| normal_eq_matrix_(0, 0) = dF_norm * dF_norm; | ||
| if (dF_norm > eps) { | ||
| theta_(0) = (prev_dF_.col(column_index_) / dF_norm).dot(current_F_ / dF_norm); | ||
| } | ||
| } | ||
| else { | ||
| // update Gram matrix row/column corresponding to the newest column | ||
| const Eigen::RowVectorXd new_inner_prod = | ||
| prev_dF_.col(column_index_).transpose() * | ||
| prev_dF_.block(0, 0, dimension_, m_k); | ||
| normal_eq_matrix_.block(column_index_, 0, 1, m_k) = new_inner_prod; | ||
| normal_eq_matrix_.block(0, column_index_, m_k, 1) = new_inner_prod.transpose(); | ||
|
|
||
| cod_.compute(normal_eq_matrix_.block(0, 0, m_k, m_k)); | ||
| theta_.head(m_k) = | ||
| cod_.solve(prev_dF_.block(0, 0, dimension_, m_k).transpose() * current_F_); | ||
| } | ||
|
|
||
| const Eigen::ArrayXd scaled_theta = | ||
| theta_.head(m_k).array() / dF_scale_.head(m_k).array(); | ||
| current_u_ = G - prev_dG_.block(0, 0, dimension_, m_k) * scaled_theta.matrix(); | ||
|
|
||
| column_index_ = (column_index_ + 1) % history_length_; | ||
| prev_dF_.col(column_index_) = -current_F_; | ||
| prev_dG_.col(column_index_) = -G; | ||
| } | ||
|
|
||
| ++iteration_; | ||
| return current_u_; | ||
| } | ||
|
|
||
| private: | ||
| std::size_t history_length_{0}; | ||
| std::size_t dimension_{0}; | ||
| std::size_t iteration_{0}; | ||
| std::size_t column_index_{0}; | ||
| bool initialized_{false}; | ||
|
|
||
| Eigen::VectorXd current_u_; | ||
| Eigen::VectorXd current_F_; | ||
| Eigen::MatrixXd prev_dG_; | ||
| Eigen::MatrixXd prev_dF_; | ||
| Eigen::MatrixXd normal_eq_matrix_; | ||
| Eigen::VectorXd theta_; | ||
| Eigen::VectorXd dF_scale_; | ||
| Eigen::CompleteOrthogonalDecomposition<Eigen::MatrixXd> cod_; | ||
|
|
||
| PCL_MAKE_ALIGNED_OPERATOR_NEW | ||
| }; | ||
|
|
||
| } // namespace registration | ||
| } // namespace pcl |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| /* | ||
| * SPDX-License-Identifier: BSD-3-Clause | ||
| * | ||
| * Point Cloud Library (PCL) - www.pointclouds.org | ||
| * Copyright (c) 2010-, Open Perception, Inc. | ||
| * | ||
| * All rights reserved. | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <pcl/registration/anderson_acceleration.h> | ||
| #include <pcl/registration/icp.h> | ||
| #include <pcl/search/kdtree.h> | ||
| #include <pcl/search/search.h> | ||
| #include <pcl/pcl_macros.h> | ||
| #include <pcl/point_types.h> | ||
|
|
||
| #include <Eigen/Core> | ||
|
|
||
| #include <cmath> | ||
| #include <vector> | ||
|
|
||
| namespace pcl { | ||
| /** | ||
| * \brief FastRobustIterativeClosestPoint implements the FRICP variant described in | ||
| * "Fast and Robust Iterative Closest Point", Zhang et al., 2021. | ||
| * | ||
| * The solver relies on Welsch reweighting for robustness and optional Anderson | ||
| * acceleration for faster convergence. | ||
| * | ||
duanbotu123 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| * \code | ||
| * pcl::FastRobustIterativeClosestPoint<PointT, PointT> reg; | ||
| * reg.setInputSource (src); // src and tgt are clouds that must be created before | ||
| * reg.setInputTarget (tgt); | ||
| * reg.setMaximumIterations (60); // parameters may have to be tuned, depending on the point clouds | ||
duanbotu123 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * reg.setTransformationEpsilon (1e-8); | ||
| * pcl::PointCloud<PointT> output; | ||
| * reg.align (output); | ||
| * \endcode | ||
| * \ingroup registration | ||
| */ | ||
| template <typename PointSource, typename PointTarget, typename Scalar = float> | ||
| class FastRobustIterativeClosestPoint | ||
| : public IterativeClosestPoint<PointSource, PointTarget, Scalar> { | ||
| public: | ||
| using Base = IterativeClosestPoint<PointSource, PointTarget, Scalar>; | ||
| using typename Base::Matrix4; | ||
| using typename Base::PointCloudSource; | ||
| using typename Base::PointCloudTarget; | ||
|
|
||
| enum class RobustFunction { NONE, WELSCH }; | ||
|
|
||
| FastRobustIterativeClosestPoint(); | ||
|
|
||
| void | ||
| setRobustFunction(RobustFunction f); | ||
|
|
||
| [[nodiscard]] RobustFunction | ||
| getRobustFunction() const; | ||
|
|
||
| /** \brief Enable or disable Anderson acceleration in the FRICP optimization loop. | ||
| * | ||
| * When enabled, convergence can be faster on some datasets but may become less | ||
| * stable. The default is disabled to keep behavior predictable. | ||
| */ | ||
| void | ||
| setUseAndersonAcceleration(bool enabled); | ||
|
|
||
| [[nodiscard]] bool | ||
| getUseAndersonAcceleration() const; | ||
|
|
||
| /** \brief Set the history size used by Anderson acceleration. | ||
| * | ||
| * Larger values may improve acceleration quality but can increase instability and | ||
| * memory usage. Values smaller than 1 are clamped to 1. | ||
| */ | ||
| void | ||
| setAndersonHistorySize(std::size_t history); | ||
|
|
||
| [[nodiscard]] std::size_t | ||
| getAndersonHistorySize() const; | ||
|
|
||
| /** \brief Set the initial Welsch scale ratio used in dynamic robust weighting. | ||
| * | ||
| * Larger values start with weaker down-weighting of outliers. Values are clamped | ||
| * to a small positive threshold. | ||
| */ | ||
| void | ||
| setDynamicWelschBeginRatio(double ratio); | ||
|
|
||
| /** \brief Set the final Welsch scale ratio used in dynamic robust weighting. | ||
| * | ||
| * Smaller values end with stronger outlier suppression. Values are clamped to a | ||
| * small positive threshold. | ||
| */ | ||
| void | ||
| setDynamicWelschEndRatio(double ratio); | ||
mvieth marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** \brief Set the multiplicative decay applied to the dynamic Welsch scale. | ||
| * | ||
| * Valid range is [0, 1]. Smaller values reduce the scale faster per outer | ||
| * iteration, while larger values keep it closer to the current value. | ||
| */ | ||
| void | ||
| setDynamicWelschDecay(double ratio); | ||
|
|
||
| protected: | ||
| void | ||
| computeTransformation(PointCloudSource& output, const Matrix4& guess) override; | ||
|
|
||
| private: | ||
| using Matrix4d = Eigen::Matrix<double, 4, 4>; | ||
| using Matrix3Xd = Eigen::Matrix<double, 3, Eigen::Dynamic>; | ||
| using VectorXd = Eigen::VectorXd; | ||
| using Vector3d = Eigen::Vector3d; | ||
| using AndersonAccelerationType = registration::AndersonAcceleration; | ||
|
|
||
| Matrix4d | ||
| convertGuessToCentered(const Matrix4& guess, | ||
| const Vector3d& source_mean, | ||
| const Vector3d& target_mean) const; | ||
|
|
||
| Matrix4d | ||
| convertCenteredToActual(const Matrix4d& transform, | ||
| const Vector3d& source_mean, | ||
| const Vector3d& target_mean) const; | ||
|
|
||
| bool | ||
| updateCorrespondences(const Matrix4d& transform, | ||
| const Matrix3Xd& source, | ||
| const Matrix3Xd& target, | ||
| pcl::search::Search<pcl::PointXYZ>& tree, | ||
| Matrix3Xd& matched_targets, | ||
| VectorXd& residuals) const; | ||
|
|
||
| double | ||
| computeEnergy(const VectorXd& residuals, double nu) const; | ||
|
|
||
| VectorXd | ||
| computeWeights(const VectorXd& residuals, double nu) const; | ||
|
|
||
| Matrix4d | ||
| computeWeightedRigidTransform(const Matrix3Xd& source, | ||
| const Matrix3Xd& target, | ||
| const VectorXd& weights) const; | ||
|
|
||
| double | ||
| findKNearestMedian(const pcl::PointCloud<pcl::PointXYZ>& cloud, | ||
| pcl::search::Search<pcl::PointXYZ>& tree, | ||
| int neighbors) const; | ||
|
|
||
| Matrix4d | ||
| matrixLog(const Matrix4d& transform) const; | ||
|
|
||
| RobustFunction robust_function_; | ||
| bool use_anderson_ = false; | ||
| std::size_t anderson_history_ = 5; | ||
| double nu_begin_ratio_ = 3.0; | ||
| double nu_end_ratio_ = 1.0 / (3.0 * std::sqrt(3.0)); | ||
| double nu_decay_ratio_ = 0.5; | ||
|
|
||
| static constexpr double same_threshold_ = 1e-6; | ||
|
|
||
| AndersonAccelerationType anderson_; | ||
|
|
||
| PCL_MAKE_ALIGNED_OPERATOR_NEW | ||
| }; | ||
| } // namespace pcl | ||
|
|
||
| #include <pcl/registration/impl/fricp.hpp> | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.