// Ceres Solver - A fast non-linear least squares minimizer // Copyright 2015 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) #ifndef CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_ #define CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_ #include #include "ceres/internal/port.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/internal/disable_warnings.h" namespace ceres { // 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 redundent 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 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 g 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_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_EXPORT IdentityParameterization : public LocalParameterization { public: explicit IdentityParameterization(int size); virtual ~IdentityParameterization() {} virtual bool Plus(const double* x, const double* delta, double* x_plus_delta) const; virtual bool ComputeJacobian(const double* x, double* jacobian) const; virtual bool MultiplyByJacobian(const double* x, const int num_cols, const double* global_matrix, double* local_matrix) const; virtual int GlobalSize() const { return size_; } virtual int LocalSize() const { return size_; } private: const int size_; }; // Hold a subset of the parameters inside a parameter block constant. class CERES_EXPORT SubsetParameterization : public LocalParameterization { public: explicit SubsetParameterization(int size, const std::vector& constant_parameters); virtual ~SubsetParameterization() {} virtual bool Plus(const double* x, const double* delta, double* x_plus_delta) const; virtual bool ComputeJacobian(const double* x, double* jacobian) const; virtual bool MultiplyByJacobian(const double* x, const int num_cols, const double* global_matrix, double* local_matrix) const; virtual int GlobalSize() const { return static_cast(constancy_mask_.size()); } virtual int LocalSize() const { return local_size_; } private: const int local_size_; std::vector 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_EXPORT QuaternionParameterization : public LocalParameterization { public: virtual ~QuaternionParameterization() {} virtual bool Plus(const double* x, const double* delta, double* x_plus_delta) const; virtual bool ComputeJacobian(const double* x, double* jacobian) const; virtual int GlobalSize() const { return 4; } virtual int LocalSize() const { return 3; } }; // This provides a parameterization for homogeneous vectors which are commonly // used in Structure for 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_EXPORT HomogeneousVectorParameterization : public LocalParameterization { public: explicit HomogeneousVectorParameterization(int size); virtual ~HomogeneousVectorParameterization() {} virtual bool Plus(const double* x, const double* delta, double* x_plus_delta) const; virtual bool ComputeJacobian(const double* x, double* jacobian) const; virtual int GlobalSize() const { return size_; } virtual int LocalSize() const { return size_ - 1; } private: const int size_; }; // 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. // // Currently this class supports taking the cartesian product of up to // four local parameterizations. // // 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_EXPORT ProductParameterization : public LocalParameterization { public: // // NOTE: All the constructors take ownership of the input local // parameterizations. // ProductParameterization(LocalParameterization* local_param1, LocalParameterization* local_param2); ProductParameterization(LocalParameterization* local_param1, LocalParameterization* local_param2, LocalParameterization* local_param3); ProductParameterization(LocalParameterization* local_param1, LocalParameterization* local_param2, LocalParameterization* local_param3, LocalParameterization* local_param4); virtual ~ProductParameterization(); virtual bool Plus(const double* x, const double* delta, double* x_plus_delta) const; virtual bool ComputeJacobian(const double* x, double* jacobian) const; virtual int GlobalSize() const { return global_size_; } virtual int LocalSize() const { return local_size_; } private: void Init(); std::vector local_params_; int local_size_; int global_size_; int buffer_size_; }; } // namespace ceres #include "ceres/internal/reenable_warnings.h" #endif // CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_