gtsam
Loading...
Searching...
No Matches
SelfCalibrationFactor.h
Go to the documentation of this file.
1/* ----------------------------------------------------------------------------
2 * GTSAM Copyright 2010-2024, Georgia Tech Research Corporation,
3 * Atlanta, Georgia 30332-0415
4 * All Rights Reserved
5 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
6 * See LICENSE for the license information
7 * -------------------------------------------------------------------------- */
8
15
16#pragma once
17
18#include <gtsam/base/Matrix.h>
19#include <gtsam/base/Vector.h>
23
24#include <Eigen/Core>
25#include <Eigen/SVD>
26
27#include <array>
28#include <cmath>
29
30namespace gtsam {
31
37inline Eigen::Vector4d fetzer_d(const Eigen::Vector3d& ai,
38 const Eigen::Vector3d& bi,
39 const Eigen::Vector3d& aj,
40 const Eigen::Vector3d& bj, int u, int v) {
41 Eigen::Vector4d d;
42 d(0) = ai(u) * aj(v) - ai(v) * aj(u);
43 d(1) = ai(u) * bj(v) - ai(v) * bj(u);
44 d(2) = bi(u) * aj(v) - bi(v) * aj(u);
45 d(3) = bi(u) * bj(v) - bi(v) * bj(u);
46 return d;
47}
48
57inline std::array<Eigen::Vector4d, 3> fetzer_ds(const Eigen::Matrix3d& G) {
58 Eigen::JacobiSVD<Eigen::Matrix3d> svd(
59 G, Eigen::ComputeFullU | Eigen::ComputeFullV);
60 const Eigen::Vector3d s = svd.singularValues();
61
62 const Eigen::Vector3d v_0 = svd.matrixV().col(0);
63 const Eigen::Vector3d v_1 = svd.matrixV().col(1);
64 const Eigen::Vector3d u_0 = svd.matrixU().col(0);
65 const Eigen::Vector3d u_1 = svd.matrixU().col(1);
66
67 const Eigen::Vector3d ai(
68 s(0) * s(0) * (v_0(0) * v_0(0) + v_0(1) * v_0(1)),
69 s(0) * s(1) * (v_0(0) * v_1(0) + v_0(1) * v_1(1)),
70 s(1) * s(1) * (v_1(0) * v_1(0) + v_1(1) * v_1(1)));
71
72 const Eigen::Vector3d aj(u_1(0) * u_1(0) + u_1(1) * u_1(1),
73 -(u_0(0) * u_1(0) + u_0(1) * u_1(1)),
74 u_0(0) * u_0(0) + u_0(1) * u_0(1));
75
76 const Eigen::Vector3d bi(s(0) * s(0) * v_0(2) * v_0(2),
77 s(0) * s(1) * v_0(2) * v_1(2),
78 s(1) * s(1) * v_1(2) * v_1(2));
79
80 const Eigen::Vector3d bj(u_1(2) * u_1(2), -(u_0(2) * u_1(2)),
81 u_0(2) * u_0(2));
82
83 std::array<Eigen::Vector4d, 3> ds;
84 ds[0] = fetzer_d(ai, bi, aj, bj, 1, 0); // d_01
85 ds[1] = fetzer_d(ai, bi, aj, bj, 0, 2); // d_02 (unused in residual)
86 ds[2] = fetzer_d(ai, bi, aj, bj, 2, 1); // d_12
87 return ds;
88}
89
107 : public NoiseModelFactorT<Vector2, double, double> {
108 public:
110 using This = SelfCalibrationFactor;
111
112 private:
113 // Residual coefficients, precomputed from G = K_j^T F K_i in the constructor. They are a
114 // function of F and the principal points only (not the focals), so they stay fixed for the
115 // edge — the focal dependence is entirely in evaluateError.
116 Eigen::Vector4d d_01_;
117 Eigen::Vector4d d_12_;
118
119 public:
129 SelfCalibrationFactor(Key fi_key, Key fj_key, const Matrix3& F, const Vector2& pp_i,
130 const Vector2& pp_j, const SharedNoiseModel& model = nullptr)
131 : Base(model ? model : noiseModel::Unit::Create(2), fi_key, fj_key) {
132 // Fold the principal points into G = K_j^T F K_i, leaving the focals out. K_j (the
133 // transposed side) is F's left index, matching the convention x_j^T F x_i = 0.
134 Matrix3 Ki = Matrix3::Identity();
135 Ki(0, 2) = pp_i(0);
136 Ki(1, 2) = pp_i(1);
137
138 Matrix3 Kj = Matrix3::Identity();
139 Kj(0, 2) = pp_j(0);
140 Kj(1, 2) = pp_j(1);
141
142 const Matrix3 G = Kj.transpose() * F * Ki;
143 const std::array<Eigen::Vector4d, 3> ds = fetzer_ds(G);
144 d_01_ = ds[0];
145 d_12_ = ds[2];
146 }
147
149 Vector2 evaluateError(const double& fi, const double& fj,
150 OptionalMatrixType H1 = nullptr,
151 OptionalMatrixType H2 = nullptr) const override {
152 // Floor the focal magnitude so a (near-)zero focal can't divide to inf/NaN; for any
153 // realistic focal this is identical to the raw input.
154 constexpr double kMinFocal = 1e-6;
155 const double fi0 =
156 std::abs(fi) < kMinFocal ? std::copysign(kMinFocal, fi) : fi;
157 const double fj0 =
158 std::abs(fj) < kMinFocal ? std::copysign(kMinFocal, fj) : fj;
159 const double fi2 = fi0 * fi0;
160 const double fj2 = fj0 * fj0;
161
162 const Eigen::Vector4d& a = d_01_;
163 const Eigen::Vector4d& b = d_12_;
164
165 double di = a(0) * fj2 + a(1);
166 double dj = b(0) * fi2 + b(2);
167 // Floor the denominators so a rank-deficient F keeps K0/K1 finite.
168 constexpr double kMinDenom = 1e-12;
169 if (std::abs(di) < kMinDenom) di = std::copysign(kMinDenom, di);
170 if (std::abs(dj) < kMinDenom) dj = std::copysign(kMinDenom, dj);
171
172 const double ni = a(2) * fj2 + a(3);
173 const double nj = b(1) * fi2 + b(3);
174
175 const double K0 = -ni / di; // f_i^2 implied by the f_j side
176 const double K1 = -nj / dj; // f_j^2 implied by the f_i side
177
178 const double r0 = (fi2 - K0) / fi2;
179 const double r1 = (fj2 - K1) / fj2;
180
181 if (H1) {
182 H1->resize(2, 1);
183 (*H1)(0, 0) = 2.0 * (1.0 - r0) / fi0;
184 (*H1)(1, 0) = (2.0 * fi0 / fj2) * (b(1) * dj - b(0) * nj) / (dj * dj);
185 }
186 if (H2) {
187 H2->resize(2, 1);
188 (*H2)(0, 0) = (2.0 * fj0 / fi2) * (a(2) * di - a(0) * ni) / (di * di);
189 (*H2)(1, 0) = 2.0 * (1.0 - r1) / fj0;
190 }
191
192 return Vector{{r0, r1}};
193 }
194};
195
196} // namespace gtsam
typedef and functions to augment Eigen's MatrixXd
typedef and functions to augment Eigen's VectorXd
Base class for noise model factors with N variables.
Non-linear factor base classes.
Global functions in a separate testing namespace.
Definition chartTesting.h:28
Matrix * OptionalMatrixType
This typedef will be used everywhere boost::optional<Matrix&> reference was used previously.
Definition NonlinearFactor.h:57
Eigen::Vector4d fetzer_d(const Eigen::Vector3d &ai, const Eigen::Vector3d &bi, const Eigen::Vector3d &aj, const Eigen::Vector3d &bj, int u, int v)
Build one 4-vector of bilinear coefficients from two pairs of 3-vectors, picking rows (u,...
Definition SelfCalibrationFactor.h:37
void svd(const Matrix &A, Matrix &U, Vector &S, Matrix &V)
SVD computes economy SVD A=U*S*V'.
Definition Matrix.cpp:557
noiseModel::Base::shared_ptr SharedNoiseModel
Aliases.
Definition NoiseModel.h:846
std::uint64_t Key
Integer nonlinear key type.
Definition types.h:43
std::array< Eigen::Vector4d, 3 > fetzer_ds(const Eigen::Matrix3d &G)
Precompute the Fetzer coefficient vectors from G = K_j^T F K_i.
Definition SelfCalibrationFactor.h:57
All noise models live in the noiseModel namespace.
Definition LossFunctions.cpp:33
NoiseModelFactorT()
Definition NoiseModelFactorN.h:257
SelfCalibrationFactor(Key fi_key, Key fj_key, const Matrix3 &F, const Vector2 &pp_i, const Vector2 &pp_j, const SharedNoiseModel &model=nullptr)
Definition SelfCalibrationFactor.h:129
Vector2 evaluateError(const double &fi, const double &fj, OptionalMatrixType H1=nullptr, OptionalMatrixType H2=nullptr) const override
2-vector essential-matrix deviation; Jacobians are 2x1 each.
Definition SelfCalibrationFactor.h:149