// -*- C++ -*- /* Copyright (c) 2008 University of North Carolina at Chapel Hill This file is part of SSBA (Simple Sparse Bundle Adjustment). SSBA is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SSBA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SSBA. If not, see . */ #ifndef V3D_METRICBUNDLE_H #define V3D_METRICBUNDLE_H # if defined(V3DLIB_ENABLE_SUITESPARSE) #include "Math/v3d_optimization.h" #include "Math/v3d_linear.h" #include "Math/v3d_linear_utils.h" #include "Geometry/v3d_cameramatrix.h" #include "Geometry/v3d_distortion.h" namespace V3D { // This structure provides some helper functions common to all metric BAs struct MetricBundleOptimizerBase : public SparseLevenbergOptimizer { typedef SparseLevenbergOptimizer Base; MetricBundleOptimizerBase(double inlierThreshold, vector& cams, vector& Xs, vector const& measurements, vector const& corrspondingView, vector const& corrspondingPoint, int nAddParamsA, int nParamsC) : SparseLevenbergOptimizer(2, cams.size(), 6+nAddParamsA, Xs.size(), 3, nParamsC, corrspondingView, corrspondingPoint), _cams(cams), _Xs(Xs), _measurements(measurements), _savedTranslations(cams.size()), _savedRotations(cams.size()), _savedXs(Xs.size()), _inlierThreshold(inlierThreshold), _cachedParamLength(0.0) { // Since we assume that BA does not alter the inputs too much, // we compute the overall length of the parameter vector in advance // and return that value as the result of getParameterLength(). for (int i = _nNonvaryingA; i < _nParametersA; ++i) { _cachedParamLength += sqrNorm_L2(_cams[i].getTranslation()); _cachedParamLength += 3.0; // Assume eye(3) for R. } for (int j = _nNonvaryingB; j < _nParametersB; ++j) _cachedParamLength += sqrNorm_L2(_Xs[j]); _cachedParamLength = sqrt(_cachedParamLength); } // Huber robust cost function. virtual void fillWeights(VectorArray const& residual, Vector& w) { for (unsigned int k = 0; k < w.size(); ++k) { Vector const& r = residual[k]; double const e = norm_L2(r); w[k] = (e < _inlierThreshold) ? 1.0 : sqrt(_inlierThreshold / e); } // end for (k) } virtual double getParameterLength() const { return _cachedParamLength; } virtual void updateParametersA(VectorArray const& deltaAi); virtual void updateParametersB(VectorArray const& deltaBj); virtual void updateParametersC(Vector const& deltaC) { (void)deltaC; } virtual void saveAllParameters() { for (int i = _nNonvaryingA; i < _nParametersA; ++i) { _savedTranslations[i] = _cams[i].getTranslation(); _savedRotations[i] = _cams[i].getRotation(); } _savedXs = _Xs; } virtual void restoreAllParameters() { for (int i = _nNonvaryingA; i < _nParametersA; ++i) { _cams[i].setTranslation(_savedTranslations[i]); _cams[i].setRotation(_savedRotations[i]); } _Xs = _savedXs; } protected: typedef InlineMatrix Matrix3x6d; void poseDerivatives(int i, int j, Vector3d& XX, Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const; vector& _cams; vector& _Xs; vector const& _measurements; vector _savedTranslations; vector _savedRotations; vector _savedXs; double const _inlierThreshold; double _cachedParamLength; }; // end struct MetricBundleOptimizerBase struct StdMetricBundleOptimizer : public MetricBundleOptimizerBase { typedef MetricBundleOptimizerBase Base; StdMetricBundleOptimizer(double inlierThreshold, vector& cams, vector& Xs, vector const& measurements, vector const& corrspondingView, vector const& corrspondingPoint) : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements, corrspondingView, corrspondingPoint, 0, 0) { } virtual void evalResidual(VectorArray& e) { for (unsigned int k = 0; k < e.count(); ++k) { int const i = _correspondingParamA[k]; int const j = _correspondingParamB[k]; Vector2d const q = _cams[i].projectPoint(_Xs[j]); e[k][0] = q[0] - _measurements[k][0]; e[k][1] = q[1] - _measurements[k][1]; } } virtual void fillJacobians(Matrix& Ak, Matrix& Bk, Matrix& Ck, int i, int j, int k); }; // end struct StdMetricBundleOptimizer //---------------------------------------------------------------------- enum { FULL_BUNDLE_METRIC = 0, FULL_BUNDLE_FOCAL_LENGTH = 1, // f FULL_BUNDLE_FOCAL_LENGTH_PP = 2, // f, cx, cy FULL_BUNDLE_RADIAL = 3, // f, cx, cy, k1, k2 FULL_BUNDLE_RADIAL_TANGENTIAL = 4 // f, cx, cy, k1, k2, p1, p2 }; struct CommonInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase { static int globalParamDimensionFromMode(int mode) { switch (mode) { case FULL_BUNDLE_METRIC: return 0; case FULL_BUNDLE_FOCAL_LENGTH: return 1; case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3; case FULL_BUNDLE_RADIAL: return 5; case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7; } return 0; } typedef MetricBundleOptimizerBase Base; CommonInternalsMetricBundleOptimizer(int mode, double inlierThreshold, Matrix3x3d& K, StdDistortionFunction& distortion, vector& cams, vector& Xs, vector const& measurements, vector const& corrspondingView, vector const& corrspondingPoint) : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements, corrspondingView, corrspondingPoint, 0, globalParamDimensionFromMode(mode)), _mode(mode), _K(K), _distortion(distortion) { _cachedAspectRatio = K[1][1] / K[0][0]; } Vector2d projectPoint(Vector3d const& X, int i) const { Vector3d const XX = _cams[i].transformPointIntoCameraSpace(X); Vector2d p; p[0] = XX[0] / XX[2]; p[1] = XX[1] / XX[2]; p = _distortion(p); Vector2d res; res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2]; res[1] = _K[1][1] * p[1] + _K[1][2]; return res; } virtual void evalResidual(VectorArray& e) { for (unsigned int k = 0; k < e.count(); ++k) { int const i = _correspondingParamA[k]; int const j = _correspondingParamB[k]; Vector2d const q = this->projectPoint(_Xs[j], i); e[k][0] = q[0] - _measurements[k][0]; e[k][1] = q[1] - _measurements[k][1]; } } virtual void fillJacobians(Matrix& Ak, Matrix& Bk, Matrix& Ck, int i, int j, int k); virtual void updateParametersC(Vector const& deltaC); virtual void saveAllParameters() { Base::saveAllParameters(); _savedK = _K; _savedDistortion = _distortion; } virtual void restoreAllParameters() { Base::restoreAllParameters(); _K = _savedK; _distortion = _savedDistortion; } protected: int _mode; Matrix3x3d& _K; StdDistortionFunction& _distortion; Matrix3x3d _savedK; StdDistortionFunction _savedDistortion; double _cachedAspectRatio; }; // end struct CommonInternalsMetricBundleOptimizer //---------------------------------------------------------------------- struct VaryingInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase { static int extParamDimensionFromMode(int mode) { switch (mode) { case FULL_BUNDLE_METRIC: return 0; case FULL_BUNDLE_FOCAL_LENGTH: return 1; case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3; case FULL_BUNDLE_RADIAL: return 5; case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7; } return 0; } typedef MetricBundleOptimizerBase Base; VaryingInternalsMetricBundleOptimizer(int mode, double inlierThreshold, std::vector& distortions, vector& cams, vector& Xs, vector const& measurements, vector const& corrspondingView, vector const& corrspondingPoint) : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements, corrspondingView, corrspondingPoint, extParamDimensionFromMode(mode), 0), _mode(mode), _distortions(distortions), _savedKs(cams.size()), _savedDistortions(cams.size()) { } Vector2d projectPoint(Vector3d const& X, int i) const { return _cams[i].projectPoint(_distortions[i], X); } virtual void evalResidual(VectorArray& e) { for (unsigned int k = 0; k < e.count(); ++k) { int const i = _correspondingParamA[k]; int const j = _correspondingParamB[k]; Vector2d const q = this->projectPoint(_Xs[j], i); e[k][0] = q[0] - _measurements[k][0]; e[k][1] = q[1] - _measurements[k][1]; } } virtual void fillJacobians(Matrix& Ak, Matrix& Bk, Matrix& Ck, int i, int j, int k); virtual void updateParametersA(VectorArray const& deltaAi); virtual void saveAllParameters() { Base::saveAllParameters(); for (int i = _nNonvaryingA; i < _nParametersA; ++i) _savedKs[i] = _cams[i].getIntrinsic(); std::copy(_distortions.begin(), _distortions.end(), _savedDistortions.begin()); } virtual void restoreAllParameters() { Base::restoreAllParameters(); for (int i = _nNonvaryingA; i < _nParametersA; ++i) _cams[i].setIntrinsic(_savedKs[i]); std::copy(_savedDistortions.begin(), _savedDistortions.end(), _distortions.begin()); } protected: int _mode; std::vector& _distortions; std::vector _savedKs; std::vector _savedDistortions; }; // end struct VaryingInternalsMetricBundleOptimizer } // end namespace V3D # endif #endif