// Ceres Solver - A fast non-linear least squares minimizer | |
// Copyright 2019 Google Inc. All rights reserved. | |
// http://ceres-solver.org/ | |
// | |
// Redistribution and use in source and binary forms, with or without | |
// modification, are permitted provided that the following conditions are met: | |
// | |
// * Redistributions of source code must retain the above copyright notice, | |
// this list of conditions and the following disclaimer. | |
// * Redistributions in binary form must reproduce the above copyright notice, | |
// this list of conditions and the following disclaimer in the documentation | |
// and/or other materials provided with the distribution. | |
// * Neither the name of Google Inc. nor the names of its contributors may be | |
// used to endorse or promote products derived from this software without | |
// specific prior written permission. | |
// | |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
// POSSIBILITY OF SUCH DAMAGE. | |
// | |
// Author: keir@google.com (Keir Mierle) | |
// sameeragarwal@google.com (Sameer Agarwal) | |
namespace ceres { | |
// WARNING: LocalParameterizations are deprecated. They will be removed from | |
// Ceres Solver in version 2.2.0. Please use Manifolds instead. | |
// Purpose: Sometimes parameter blocks x can overparameterize a problem | |
// | |
// min f(x) | |
// x | |
// | |
// In that case it is desirable to choose a parameterization for the | |
// block itself to remove the null directions of the cost. More | |
// generally, if x lies on a manifold of a smaller dimension than the | |
// ambient space that it is embedded in, then it is numerically and | |
// computationally more effective to optimize it using a | |
// parameterization that lives in the tangent space of that manifold | |
// at each point. | |
// | |
// For example, a sphere in three dimensions is a 2 dimensional | |
// manifold, embedded in a three dimensional space. At each point on | |
// the sphere, the plane tangent to it defines a two dimensional | |
// tangent space. For a cost function defined on this sphere, given a | |
// point x, moving in the direction normal to the sphere at that point | |
// is not useful. Thus a better way to do a local optimization is to | |
// optimize over two dimensional vector delta in the tangent space at | |
// that point and then "move" to the point x + delta, where the move | |
// operation involves projecting back onto the sphere. Doing so | |
// removes a redundant dimension from the optimization, making it | |
// numerically more robust and efficient. | |
// | |
// More generally we can define a function | |
// | |
// x_plus_delta = Plus(x, delta), | |
// | |
// where x_plus_delta has the same size as x, and delta is of size | |
// less than or equal to x. The function Plus, generalizes the | |
// definition of vector addition. Thus it satisfies the identify | |
// | |
// Plus(x, 0) = x, for all x. | |
// | |
// A trivial version of Plus is when delta is of the same size as x | |
// and | |
// | |
// Plus(x, delta) = x + delta | |
// | |
// A more interesting case if x is two dimensional vector, and the | |
// user wishes to hold the first coordinate constant. Then, delta is a | |
// scalar and Plus is defined as | |
// | |
// Plus(x, delta) = x + [0] * delta | |
// [1] | |
// | |
// An example that occurs commonly in Structure from Motion problems | |
// is when camera rotations are parameterized using Quaternion. There, | |
// it is useful to only make updates orthogonal to that 4-vector | |
// defining the quaternion. One way to do this is to let delta be a 3 | |
// dimensional vector and define Plus to be | |
// | |
// Plus(x, delta) = [cos(|delta|), sin(|delta|) delta / |delta|] * x | |
// | |
// The multiplication between the two 4-vectors on the RHS is the | |
// standard quaternion product. | |
// | |
// Given f and a point x, optimizing f can now be restated as | |
// | |
// min f(Plus(x, delta)) | |
// delta | |
// | |
// Given a solution delta to this problem, the optimal value is then | |
// given by | |
// | |
// x* = Plus(x, delta) | |
// | |
// The class LocalParameterization defines the function Plus and its | |
// Jacobian which is needed to compute the Jacobian of f w.r.t delta. | |
class CERES_DEPRECATED_WITH_MSG( | |
"LocalParameterizations will be removed from the Ceres Solver API in " | |
"version 2.2.0. Use Manifolds instead.") | |
CERES_EXPORT LocalParameterization { | |
public: | |
virtual ~LocalParameterization(); | |
// Generalization of the addition operation, | |
// | |
// x_plus_delta = Plus(x, delta) | |
// | |
// with the condition that Plus(x, 0) = x. | |
// | |
virtual bool Plus(const double* x, | |
const double* delta, | |
double* x_plus_delta) const = 0; | |
// The jacobian of Plus(x, delta) w.r.t delta at delta = 0. | |
// | |
// jacobian is a row-major GlobalSize() x LocalSize() matrix. | |
virtual bool ComputeJacobian(const double* x, double* jacobian) const = 0; | |
// local_matrix = global_matrix * jacobian | |
// | |
// global_matrix is a num_rows x GlobalSize row major matrix. | |
// local_matrix is a num_rows x LocalSize row major matrix. | |
// jacobian(x) is the matrix returned by ComputeJacobian at x. | |
// | |
// This is only used by GradientProblem. For most normal uses, it is | |
// okay to use the default implementation. | |
virtual bool MultiplyByJacobian(const double* x, | |
const int num_rows, | |
const double* global_matrix, | |
double* local_matrix) const; | |
// Size of x. | |
virtual int GlobalSize() const = 0; | |
// Size of delta. | |
virtual int LocalSize() const = 0; | |
}; | |
// Some basic parameterizations | |
// Identity Parameterization: Plus(x, delta) = x + delta | |
class CERES_DEPRECATED_WITH_MSG("Use EuclideanManifold instead.") | |
CERES_EXPORT IdentityParameterization : public LocalParameterization { | |
public: | |
explicit IdentityParameterization(int size); | |
bool Plus(const double* x, | |
const double* delta, | |
double* x_plus_delta) const override; | |
bool ComputeJacobian(const double* x, double* jacobian) const override; | |
bool MultiplyByJacobian(const double* x, | |
const int num_cols, | |
const double* global_matrix, | |
double* local_matrix) const override; | |
int GlobalSize() const override { return size_; } | |
int LocalSize() const override { return size_; } | |
private: | |
const int size_; | |
}; | |
// Hold a subset of the parameters inside a parameter block constant. | |
class CERES_DEPRECATED_WITH_MSG("Use SubsetManifold instead.") | |
CERES_EXPORT SubsetParameterization : public LocalParameterization { | |
public: | |
explicit SubsetParameterization(int size, | |
const std::vector<int>& constant_parameters); | |
bool Plus(const double* x, | |
const double* delta, | |
double* x_plus_delta) const override; | |
bool ComputeJacobian(const double* x, double* jacobian) const override; | |
bool MultiplyByJacobian(const double* x, | |
const int num_cols, | |
const double* global_matrix, | |
double* local_matrix) const override; | |
int GlobalSize() const override { | |
return static_cast<int>(constancy_mask_.size()); | |
} | |
int LocalSize() const override { return local_size_; } | |
private: | |
const int local_size_; | |
std::vector<char> constancy_mask_; | |
}; | |
// Plus(x, delta) = [cos(|delta|), sin(|delta|) delta / |delta|] * x | |
// with * being the quaternion multiplication operator. Here we assume | |
// that the first element of the quaternion vector is the real (cos | |
// theta) part. | |
class CERES_DEPRECATED_WITH_MSG("Use QuaternionManifold instead.") | |
CERES_EXPORT QuaternionParameterization : public LocalParameterization { | |
public: | |
bool Plus(const double* x, | |
const double* delta, | |
double* x_plus_delta) const override; | |
bool ComputeJacobian(const double* x, double* jacobian) const override; | |
int GlobalSize() const override { return 4; } | |
int LocalSize() const override { return 3; } | |
}; | |
// Implements the quaternion local parameterization for Eigen's representation | |
// of the quaternion. Eigen uses a different internal memory layout for the | |
// elements of the quaternion than what is commonly used. Specifically, Eigen | |
// stores the elements in memory as [x, y, z, w] where the real part is last | |
// whereas it is typically stored first. Note, when creating an Eigen quaternion | |
// through the constructor the elements are accepted in w, x, y, z order. Since | |
// Ceres operates on parameter blocks which are raw double pointers this | |
// difference is important and requires a different parameterization. | |
// | |
// Plus(x, delta) = [sin(|delta|) delta / |delta|, cos(|delta|)] * x | |
// with * being the quaternion multiplication operator. | |
class CERES_DEPRECATED_WITH_MSG("Use EigenQuaternionManifold instead.") | |
CERES_EXPORT EigenQuaternionParameterization | |
: public ceres::LocalParameterization { | |
public: | |
bool Plus(const double* x, | |
const double* delta, | |
double* x_plus_delta) const override; | |
bool ComputeJacobian(const double* x, double* jacobian) const override; | |
int GlobalSize() const override { return 4; } | |
int LocalSize() const override { return 3; } | |
}; | |
// This provides a parameterization for homogeneous vectors which are commonly | |
// used in Structure from Motion problems. One example where they are used is | |
// in representing points whose triangulation is ill-conditioned. Here it is | |
// advantageous to use an over-parameterization since homogeneous vectors can | |
// represent points at infinity. | |
// | |
// The plus operator is defined as | |
// Plus(x, delta) = | |
// [sin(0.5 * |delta|) * delta / |delta|, cos(0.5 * |delta|)] * x | |
// | |
// with * defined as an operator which applies the update orthogonal to x to | |
// remain on the sphere. We assume that the last element of x is the scalar | |
// component. The size of the homogeneous vector is required to be greater than | |
// 1. | |
class CERES_DEPRECATED_WITH_MSG("Use SphereManifold instead.") CERES_EXPORT | |
HomogeneousVectorParameterization : public LocalParameterization { | |
public: | |
explicit HomogeneousVectorParameterization(int size); | |
bool Plus(const double* x, | |
const double* delta, | |
double* x_plus_delta) const override; | |
bool ComputeJacobian(const double* x, double* jacobian) const override; | |
int GlobalSize() const override { return size_; } | |
int LocalSize() const override { return size_ - 1; } | |
private: | |
const int size_; | |
}; | |
// This provides a parameterization for lines, where the line is | |
// over-parameterized by an origin point and a direction vector. So the | |
// parameter vector size needs to be two times the ambient space dimension, | |
// where the first half is interpreted as the origin point and the second half | |
// as the direction. | |
// | |
// The plus operator for the line direction is the same as for the | |
// HomogeneousVectorParameterization. The update of the origin point is | |
// perpendicular to the line direction before the update. | |
// | |
// This local parameterization is a special case of the affine Grassmannian | |
// manifold (see https://en.wikipedia.org/wiki/Affine_Grassmannian_(manifold)) | |
// for the case Graff_1(R^n). | |
template <int AmbientSpaceDimension> | |
class CERES_DEPRECATED_WITH_MSG("Use LineManifold instead.") | |
LineParameterization : public LocalParameterization { | |
public: | |
static_assert(AmbientSpaceDimension >= 2, | |
"The ambient space must be at least 2"); | |
bool Plus(const double* x, | |
const double* delta, | |
double* x_plus_delta) const override; | |
bool ComputeJacobian(const double* x, double* jacobian) const override; | |
int GlobalSize() const override { return 2 * AmbientSpaceDimension; } | |
int LocalSize() const override { return 2 * (AmbientSpaceDimension - 1); } | |
}; | |
// Construct a local parameterization by taking the Cartesian product | |
// of a number of other local parameterizations. This is useful, when | |
// a parameter block is the cartesian product of two or more | |
// manifolds. For example the parameters of a camera consist of a | |
// rotation and a translation, i.e., SO(3) x R^3. | |
// | |
// Example usage: | |
// | |
// ProductParameterization product_param(new QuaterionionParameterization(), | |
// new IdentityParameterization(3)); | |
// | |
// is the local parameterization for a rigid transformation, where the | |
// rotation is represented using a quaternion. | |
// | |
class CERES_DEPRECATED_WITH_MSG("Use ProductManifold instead.") | |
CERES_EXPORT ProductParameterization : public LocalParameterization { | |
public: | |
ProductParameterization(const ProductParameterization&) = delete; | |
ProductParameterization& operator=(const ProductParameterization&) = delete; | |
// | |
// NOTE: The constructor takes ownership of the input local | |
// parameterizations. | |
// | |
template <typename... LocalParams> | |
explicit ProductParameterization(LocalParams*... local_params) | |
: local_params_(sizeof...(LocalParams)) { | |
constexpr int kNumLocalParams = sizeof...(LocalParams); | |
static_assert(kNumLocalParams >= 2, | |
"At least two local parameterizations must be specified."); | |
using LocalParameterizationPtr = std::unique_ptr<LocalParameterization>; | |
// Wrap all raw pointers into std::unique_ptr for exception safety. | |
std::array<LocalParameterizationPtr, kNumLocalParams> local_params_array{ | |
LocalParameterizationPtr(local_params)...}; | |
// Initialize internal state. | |
for (int i = 0; i < kNumLocalParams; ++i) { | |
LocalParameterizationPtr& param = local_params_[i]; | |
param = std::move(local_params_array[i]); | |
buffer_size_ = | |
std::max(buffer_size_, param->LocalSize() * param->GlobalSize()); | |
global_size_ += param->GlobalSize(); | |
local_size_ += param->LocalSize(); | |
} | |
} | |
bool Plus(const double* x, | |
const double* delta, | |
double* x_plus_delta) const override; | |
bool ComputeJacobian(const double* x, double* jacobian) const override; | |
int GlobalSize() const override { return global_size_; } | |
int LocalSize() const override { return local_size_; } | |
private: | |
std::vector<std::unique_ptr<LocalParameterization>> local_params_; | |
int local_size_{0}; | |
int global_size_{0}; | |
int buffer_size_{0}; | |
}; | |
} // namespace ceres | |
// clang-format off | |
// clang-format on | |