Skip to content

Commit 8efcaf9

Browse files
committed
Use DefaultConvergenceCriteria instead of custom convergence check
Per larshg's review feedback: - Remove ConvergenceTrigger enum and getLastConvergenceTrigger() (these were larshg's test code, not needed for production) - Replace FRICP's own matrix delta check with DefaultConvergenceCriteria - Move delta_transform calculation after Anderson acceleration step - Use DefaultConvergenceCriteria::CONVERGENCE_CRITERIA_NO_CORRESPONDENCES on error paths instead of custom ConvergenceTrigger - Populate correspondences_ so getFitnessScore() works correctly
1 parent eb78352 commit 8efcaf9

2 files changed

Lines changed: 2 additions & 842 deletions

File tree

Lines changed: 1 addition & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -1,207 +1 @@
1-
/*
2-
* SPDX-License-Identifier: BSD-3-Clause
3-
*
4-
* Point Cloud Library (PCL) - www.pointclouds.org
5-
* Copyright (c) 2010-, Open Perception, Inc.
6-
*
7-
* All rights reserved.
8-
*/
9-
10-
#pragma once
11-
12-
#include <pcl/registration/anderson_acceleration.h>
13-
#include <pcl/registration/icp.h>
14-
#include <pcl/search/kdtree.h>
15-
#include <pcl/search/search.h>
16-
#include <pcl/memory.h>
17-
#include <pcl/pcl_macros.h>
18-
#include <pcl/point_types.h>
19-
20-
#include <Eigen/Core>
21-
22-
#include <cmath>
23-
#include <vector>
24-
25-
namespace pcl {
26-
/**
27-
* \brief FastRobustIterativeClosestPoint implements the FRICP variant described in
28-
* "Fast and Robust Iterative Closest Point", Zhang et al., 2021.
29-
*
30-
* The solver relies on Welsch reweighting for robustness and optional Anderson
31-
* acceleration for faster convergence.
32-
*
33-
* \note FRICP uses its own robust correspondence mechanism based on the Welsch
34-
* function. The following inherited ICP settings have no effect:
35-
* - setMaxCorrespondenceDistance() 閳?FRICP controls outlier rejection via
36-
* the Welsch scale parameter instead.
37-
* - Correspondence estimators, rejectors, and reciprocal correspondences
38-
* are not used by this class.
39-
* - setEuclideanFitnessEpsilon() and setRotationEpsilon() are not evaluated.
40-
*
41-
* \note setMaximumIterations() controls the number of inner-loop iterations
42-
* per Welsch scale stage. The outer loop may run multiple stages as the
43-
* scale decays, so the total number of iterations can exceed this value.
44-
*
45-
* \note Input point clouds must not contain NaN or Inf values. Non-finite
46-
* points are not handled and will produce incorrect results.
47-
*
48-
* \code
49-
* pcl::FastRobustIterativeClosestPoint<PointT, PointT> reg;
50-
* reg.setInputSource (src); // src and tgt are clouds that must be created before
51-
* reg.setInputTarget (tgt);
52-
* // parameters may have to be tuned, depending on the point clouds
53-
* reg.setMaximumIterations (60);
54-
* reg.setTransformationEpsilon (1e-8);
55-
* pcl::PointCloud<PointT> output;
56-
* reg.align (output);
57-
* \endcode
58-
* \ingroup registration
59-
*/
60-
template <typename PointSource, typename PointTarget, typename Scalar = float>
61-
class FastRobustIterativeClosestPoint
62-
: public IterativeClosestPoint<PointSource, PointTarget, Scalar> {
63-
public:
64-
using Ptr =
65-
shared_ptr<FastRobustIterativeClosestPoint<PointSource, PointTarget, Scalar>>;
66-
using ConstPtr = shared_ptr<
67-
const FastRobustIterativeClosestPoint<PointSource, PointTarget, Scalar>>;
68-
69-
using Base = IterativeClosestPoint<PointSource, PointTarget, Scalar>;
70-
using typename Base::Matrix4;
71-
using typename Base::PointCloudSource;
72-
using typename Base::PointCloudTarget;
73-
74-
enum class RobustFunction { NONE, WELSCH };
75-
enum class ConvergenceTrigger {
76-
NONE = 0,
77-
DEFAULT_CRITERIA,
78-
FRICP_STOP_THRESHOLD,
79-
ITERATION_LIMIT,
80-
NO_CORRESPONDENCES
81-
};
82-
83-
FastRobustIterativeClosestPoint();
84-
85-
void
86-
setRobustFunction(RobustFunction f);
87-
88-
[[nodiscard]] RobustFunction
89-
getRobustFunction() const;
90-
91-
/** \brief Enable or disable Anderson acceleration in the FRICP optimization loop.
92-
*
93-
* When enabled, convergence can be faster on some datasets but may become less
94-
* stable. The default is disabled to keep behavior predictable.
95-
*/
96-
void
97-
setUseAndersonAcceleration(bool enabled);
98-
99-
[[nodiscard]] bool
100-
getUseAndersonAcceleration() const;
101-
102-
/** \brief Set the history size used by Anderson acceleration.
103-
*
104-
* Larger values may improve acceleration quality but can increase instability and
105-
* memory usage. Values smaller than 1 are clamped to 1.
106-
*/
107-
void
108-
setAndersonHistorySize(std::size_t history);
109-
110-
[[nodiscard]] std::size_t
111-
getAndersonHistorySize() const;
112-
113-
/** \brief Set the initial Welsch scale ratio used in dynamic robust weighting.
114-
*
115-
* Larger values start with weaker down-weighting of outliers. Values are clamped
116-
* to a small positive threshold.
117-
*/
118-
void
119-
setDynamicWelschBeginRatio(double ratio);
120-
121-
/** \brief Set the final Welsch scale ratio used in dynamic robust weighting.
122-
*
123-
* Smaller values end with stronger outlier suppression. Values are clamped to a
124-
* small positive threshold.
125-
*/
126-
void
127-
setDynamicWelschEndRatio(double ratio);
128-
129-
/** \brief Set the multiplicative decay applied to the dynamic Welsch scale.
130-
*
131-
* Valid range is (0, 1]. A value of 0 or a very small positive number is
132-
* silently replaced by the default (0.5). Smaller values reduce the scale
133-
* faster per outer iteration, while larger values keep it closer to the
134-
* current value.
135-
*/
136-
void
137-
setDynamicWelschDecay(double ratio);
138-
139-
[[nodiscard]] ConvergenceTrigger
140-
getLastConvergenceTrigger() const;
141-
142-
protected:
143-
void
144-
computeTransformation(PointCloudSource& output, const Matrix4& guess) override;
145-
146-
private:
147-
using Matrix4d = Eigen::Matrix<double, 4, 4>;
148-
using Matrix3Xd = Eigen::Matrix<double, 3, Eigen::Dynamic>;
149-
using VectorXd = Eigen::VectorXd;
150-
using Vector3d = Eigen::Vector3d;
151-
using AndersonAccelerationType = registration::AndersonAcceleration;
152-
153-
Matrix4d
154-
convertGuessToCentered(const Matrix4& guess,
155-
const Vector3d& source_mean,
156-
const Vector3d& target_mean) const;
157-
158-
Matrix4d
159-
convertCenteredToActual(const Matrix4d& transform,
160-
const Vector3d& source_mean,
161-
const Vector3d& target_mean) const;
162-
163-
bool
164-
updateCorrespondences(const Matrix4d& transform,
165-
const Matrix3Xd& source,
166-
const Matrix3Xd& target,
167-
pcl::search::Search<pcl::PointXYZ>& tree,
168-
Matrix3Xd& matched_targets,
169-
VectorXd& residuals,
170-
pcl::Correspondences* correspondences = nullptr) const;
171-
172-
double
173-
computeEnergy(const VectorXd& residuals, double nu) const;
174-
175-
VectorXd
176-
computeWeights(const VectorXd& residuals, double nu) const;
177-
178-
Matrix4d
179-
computeWeightedRigidTransform(const Matrix3Xd& source,
180-
const Matrix3Xd& target,
181-
const VectorXd& weights) const;
182-
183-
double
184-
findKNearestMedian(const pcl::PointCloud<pcl::PointXYZ>& cloud,
185-
pcl::search::Search<pcl::PointXYZ>& tree,
186-
int neighbors) const;
187-
188-
Matrix4d
189-
matrixLog(const Matrix4d& transform) const;
190-
191-
RobustFunction robust_function_ = RobustFunction::WELSCH;
192-
bool use_anderson_ = false;
193-
std::size_t anderson_history_ = 5;
194-
double nu_begin_ratio_ = 3.0;
195-
double nu_end_ratio_ = 1.0 / (3.0 * std::sqrt(3.0));
196-
double nu_decay_ratio_ = 0.5;
197-
ConvergenceTrigger last_convergence_trigger_ = ConvergenceTrigger::NONE;
198-
199-
static constexpr double same_threshold_ = 1e-6;
200-
201-
AndersonAccelerationType anderson_;
202-
203-
PCL_MAKE_ALIGNED_OPERATOR_NEW
204-
};
205-
} // namespace pcl
206-
207-
#include <pcl/registration/impl/fricp.hpp>
1+
/* * 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/memory.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. * * \note FRICP uses its own robust correspondence mechanism based on the Welsch * function. The following inherited ICP settings have no effect: * - setMaxCorrespondenceDistance() 闁?FRICP controls outlier rejection via * the Welsch scale parameter instead. * - Correspondence estimators, rejectors, and reciprocal correspondences * are not used by this class. * - setEuclideanFitnessEpsilon() and setRotationEpsilon() are not evaluated. * * \note setMaximumIterations() controls the number of inner-loop iterations * per Welsch scale stage. The outer loop may run multiple stages as the * scale decays, so the total number of iterations can exceed this value. * * \note Input point clouds must not contain NaN or Inf values. Non-finite * points are not handled and will produce incorrect results. * * \code * pcl::FastRobustIterativeClosestPoint<PointT, PointT> reg; * reg.setInputSource (src); // src and tgt are clouds that must be created before * reg.setInputTarget (tgt); * // parameters may have to be tuned, depending on the point clouds * reg.setMaximumIterations (60); * 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 Ptr = shared_ptr<FastRobustIterativeClosestPoint<PointSource, PointTarget, Scalar>>; using ConstPtr = shared_ptr< const FastRobustIterativeClosestPoint<PointSource, PointTarget, Scalar>>; 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); /** \brief Set the multiplicative decay applied to the dynamic Welsch scale. * * Valid range is (0, 1]. A value of 0 or a very small positive number is * silently replaced by the default (0.5). 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, pcl::Correspondences* correspondences = nullptr) 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_ = RobustFunction::WELSCH; 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>

0 commit comments

Comments
 (0)