Skip to content

Commit 2ad7624

Browse files
authored
Merge pull request #60 from MOLAorg/feat/censi3d-covariance
Feat: Censi3D covariance method
2 parents 691506c + 0258aaa commit 2ad7624

8 files changed

Lines changed: 747 additions & 56 deletions

File tree

mp2p_icp/include/mp2p_icp/Parameters.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#pragma once
1616

1717
#include <mp2p_icp/WeightParameters.h>
18+
#include <mp2p_icp/covariance.h>
1819
#include <mrpt/containers/yaml.h>
1920
#include <mrpt/core/bits_math.h> // DEG2RAD()
2021
#include <mrpt/serialization/CSerializable.h>
@@ -105,6 +106,11 @@ struct Parameters : public mrpt::serialization::CSerializable
105106

106107
/** @} */
107108

109+
/** Parameters for the post-optimization SE(3) covariance estimation
110+
* (see mp2p_icp::covariance). Loadable from the optional YAML map
111+
* block `covariance:` in the ICP pipeline file. */
112+
CovarianceParameters covariance_params;
113+
108114
void load_from(const mrpt::containers::yaml& p);
109115
void save_to(mrpt::containers::yaml& p) const;
110116
};

mp2p_icp/include/mp2p_icp/covariance.h

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,59 @@
2121

2222
#include <mp2p_icp/Pairings.h>
2323
#include <mrpt/math/CMatrixFixed.h>
24+
#include <mrpt/typemeta/TEnumType.h>
25+
26+
#include <cstdint>
2427

2528
namespace mp2p_icp
2629
{
2730
struct CovarianceParameters
2831
{
29-
// Finite difference deltas:
32+
/** Covariance estimation backend. */
33+
enum class Method : uint8_t
34+
{
35+
/** Inverse of the (whitened) Gauss-Newton Hessian, scaled by the
36+
* a-posteriori unit-weight variance chi^2/(m-n). Cheap but typically
37+
* optimistic, since it ignores correspondence and surface-mismatch
38+
* noise. */
39+
InverseHessian,
40+
41+
/** Censi-style sandwich H^{-1} M H^{-1}, with H = sum J_i^T J_i and
42+
* M = sum J_i^T Sigma_z_i J_i. For cov2cov pairings the per-pair
43+
* Sigma_z = inv(cov_inv) is used directly; for pt2pt without
44+
* per-pair noise, an isotropic Sigma_z = defaultPointSigma^2 * I
45+
* is assumed. Reference: Censi 2007, Prakhya 2015. */
46+
Censi3D,
47+
};
48+
49+
Method method = Method::InverseHessian;
50+
51+
/** For pt2pt pairings without per-pair Sigma in Censi3D path:
52+
* isotropic point-noise std-dev [m]. */
53+
double defaultPointSigma = 0.02;
54+
55+
/** Per-axis floor added to the resulting covariance diagonal. Stored as
56+
* std-dev for readability; squared internally. Useful to absorb
57+
* unmodelled errors and keep downstream filters numerically stable. */
58+
double floor_sigma_xyz = 0.0; ///< [m]
59+
double floor_sigma_angles = 0.0; ///< [rad]
60+
61+
// Finite difference deltas (only used by InverseHessian path):
3062
double finDif_xyz = 1e-7;
3163
double finDif_angles = 1e-7;
64+
65+
/** Loads the parameters from a YAML map node. All entries are optional;
66+
* unspecified fields keep their default values. Recognized keys:
67+
*
68+
* method: "InverseHessian" | "Censi3D"
69+
* defaultPointSigma: [m]
70+
* floor_sigma_xyz: [m]
71+
* floor_sigma_angles: [rad] (use floor_sigma_angles_deg for degrees)
72+
* floor_sigma_angles_deg: [deg] (alternative to the radian form)
73+
* finDif_xyz, finDif_angles
74+
*/
75+
void load_from(const mrpt::containers::yaml& p);
76+
void save_to(mrpt::containers::yaml& p) const;
3277
};
3378

3479
/** Covariance estimation methods for an ICP result.
@@ -40,3 +85,10 @@ mrpt::math::CMatrixDouble66 covariance(
4085
const CovarianceParameters& p);
4186

4287
} // namespace mp2p_icp
88+
89+
MRPT_ENUM_TYPE_BEGIN_NAMESPACE(mp2p_icp, mp2p_icp::CovarianceParameters::Method)
90+
MRPT_FILL_ENUM(CovarianceParameters::Method::InverseHessian);
91+
MRPT_FILL_ENUM_CUSTOM_NAME(CovarianceParameters::Method::InverseHessian, "InverseHessian");
92+
MRPT_FILL_ENUM(CovarianceParameters::Method::Censi3D);
93+
MRPT_FILL_ENUM_CUSTOM_NAME(CovarianceParameters::Method::Censi3D, "Censi3D");
94+
MRPT_ENUM_TYPE_END()

mp2p_icp/src/ICP.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,11 +397,13 @@ void ICP::align(
397397
result.optimalScale = state.currentSolution.optimalScale;
398398
result.finalPairings = std::move(state.currentPairings);
399399

400-
// Covariance:
401-
mp2p_icp::CovarianceParameters covParams;
400+
// Covariance of the estimated SE(3) registration:
401+
{
402+
mrpt::system::CTimeLoggerEntry tleCov(profiler_, "align.5b_covariance");
402403

403-
result.optimal_tf.cov =
404-
mp2p_icp::covariance(result.finalPairings, result.optimal_tf.mean, covParams);
404+
result.optimal_tf.cov =
405+
mp2p_icp::covariance(result.finalPairings, result.optimal_tf.mean, p.covariance_params);
406+
}
405407

406408
// Clean-up global map icp preparation:
407409
for (const auto& [layer, mmap] : pcGlobal.layers)

mp2p_icp/src/Parameters.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,18 @@ const bool MP2P_ICP_GENERATE_DEBUG_FILES =
2727
mrpt::get_env<bool>("MP2P_ICP_GENERATE_DEBUG_FILES", false);
2828

2929
// Implementation of the CSerializable virtual interface:
30-
uint8_t Parameters::serializeGetVersion() const { return 2; }
30+
uint8_t Parameters::serializeGetVersion() const { return 3; }
3131
void Parameters::serializeTo(mrpt::serialization::CArchive& out) const
3232
{
3333
out << maxIterations << minAbsStep_trans << minAbsStep_rot;
3434
out << generateDebugFiles << debugFileNameFormat;
3535
out << debugPrintIterationProgress;
3636
out << decimationDebugFiles;
3737
out << saveIterationDetails << decimationIterationDetails; // v2
38+
const uint8_t covMethod = static_cast<uint8_t>(covariance_params.method);
39+
out << covMethod << covariance_params.defaultPointSigma << covariance_params.floor_sigma_xyz
40+
<< covariance_params.floor_sigma_angles << covariance_params.finDif_xyz
41+
<< covariance_params.finDif_angles; // v3
3842
}
3943
void Parameters::serializeFrom(mrpt::serialization::CArchive& in, uint8_t version)
4044
{
@@ -45,12 +49,27 @@ void Parameters::serializeFrom(mrpt::serialization::CArchive& in, uint8_t versio
4549
case 0:
4650
case 1:
4751
case 2:
52+
case 3:
4853
{
4954
in >> maxIterations >> minAbsStep_trans >> minAbsStep_rot;
5055
in >> generateDebugFiles >> debugFileNameFormat;
5156
in >> debugPrintIterationProgress;
52-
if (version >= 1) in >> decimationDebugFiles;
53-
if (version >= 2) in >> saveIterationDetails >> decimationIterationDetails;
57+
if (version >= 1)
58+
{
59+
in >> decimationDebugFiles;
60+
}
61+
if (version >= 2)
62+
{
63+
in >> saveIterationDetails >> decimationIterationDetails;
64+
}
65+
if (version >= 3)
66+
{
67+
uint8_t covMethod = 0;
68+
in >> covMethod >> covariance_params.defaultPointSigma >>
69+
covariance_params.floor_sigma_xyz >> covariance_params.floor_sigma_angles >>
70+
covariance_params.finDif_xyz >> covariance_params.finDif_angles;
71+
covariance_params.method = static_cast<CovarianceParameters::Method>(covMethod);
72+
}
5473
}
5574
break;
5675
default:
@@ -92,6 +111,11 @@ void Parameters::load_from(const mrpt::containers::yaml& p)
92111
}
93112
}
94113

114+
if (p.has("covariance"))
115+
{
116+
covariance_params.load_from(p["covariance"]);
117+
}
118+
95119
generateDebugFiles = generateDebugFiles || MP2P_ICP_GENERATE_DEBUG_FILES;
96120
}
97121

@@ -106,4 +130,8 @@ void Parameters::save_to(mrpt::containers::yaml& p) const
106130
MCP_SAVE(p, decimationDebugFiles);
107131
MCP_SAVE(p, saveIterationDetails);
108132
MCP_SAVE(p, decimationIterationDetails);
133+
134+
mrpt::containers::yaml covYaml = mrpt::containers::yaml::Map();
135+
covariance_params.save_to(covYaml);
136+
p["covariance"] = covYaml;
109137
}

0 commit comments

Comments
 (0)