2012-04-30 23:09:08 -07:00
|
|
|
// Ceres Solver - A fast non-linear least squares minimizer
|
2019-12-02 13:52:31 -08:00
|
|
|
// Copyright 2019 Google Inc. All rights reserved.
|
2015-03-17 22:30:16 -07:00
|
|
|
// http://ceres-solver.org/
|
2012-04-30 23:09:08 -07:00
|
|
|
//
|
|
|
|
|
// 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_
|
|
|
|
|
|
2019-04-19 13:36:37 +02:00
|
|
|
#include <array>
|
|
|
|
|
#include <memory>
|
2012-04-30 23:09:08 -07:00
|
|
|
#include <vector>
|
2019-07-13 11:19:27 +02:00
|
|
|
|
2014-05-19 08:21:00 +02:00
|
|
|
#include "ceres/internal/disable_warnings.h"
|
2019-04-19 13:36:37 +02:00
|
|
|
#include "ceres/internal/port.h"
|
2012-04-30 23:09:08 -07:00
|
|
|
|
|
|
|
|
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
|
2018-09-20 22:52:39 +08:00
|
|
|
// removes a redundant dimension from the optimization, making it
|
2012-04-30 23:09:08 -07:00
|
|
|
// 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.
|
2014-04-23 22:13:37 +02:00
|
|
|
class CERES_EXPORT LocalParameterization {
|
2012-04-30 23:09:08 -07:00
|
|
|
public:
|
2014-09-06 21:13:48 -07:00
|
|
|
virtual ~LocalParameterization();
|
2012-04-30 23:09:08 -07:00
|
|
|
|
|
|
|
|
// 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.
|
2014-09-06 21:13:48 -07:00
|
|
|
//
|
|
|
|
|
// jacobian is a row-major GlobalSize() x LocalSize() matrix.
|
2012-04-30 23:09:08 -07:00
|
|
|
virtual bool ComputeJacobian(const double* x, double* jacobian) const = 0;
|
|
|
|
|
|
2014-09-06 21:13:48 -07:00
|
|
|
// 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;
|
|
|
|
|
|
2012-04-30 23:09:08 -07:00
|
|
|
// 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
|
2014-04-23 22:13:37 +02:00
|
|
|
class CERES_EXPORT IdentityParameterization : public LocalParameterization {
|
2012-04-30 23:09:08 -07:00
|
|
|
public:
|
|
|
|
|
explicit IdentityParameterization(int size);
|
|
|
|
|
virtual ~IdentityParameterization() {}
|
2019-07-13 11:19:27 +02:00
|
|
|
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_; }
|
2012-04-30 23:09:08 -07:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const int size_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Hold a subset of the parameters inside a parameter block constant.
|
2014-04-23 22:13:37 +02:00
|
|
|
class CERES_EXPORT SubsetParameterization : public LocalParameterization {
|
2012-04-30 23:09:08 -07:00
|
|
|
public:
|
|
|
|
|
explicit SubsetParameterization(int size,
|
2014-12-17 07:35:09 -08:00
|
|
|
const std::vector<int>& constant_parameters);
|
2012-04-30 23:09:08 -07:00
|
|
|
virtual ~SubsetParameterization() {}
|
2019-07-13 11:19:27 +02:00
|
|
|
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 {
|
2014-05-09 16:27:03 -07:00
|
|
|
return static_cast<int>(constancy_mask_.size());
|
|
|
|
|
}
|
2019-07-13 11:19:27 +02:00
|
|
|
int LocalSize() const override { return local_size_; }
|
2012-04-30 23:09:08 -07:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const int local_size_;
|
2015-08-20 14:21:30 -04:00
|
|
|
std::vector<char> constancy_mask_;
|
2012-04-30 23:09:08 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 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.
|
2014-04-23 22:13:37 +02:00
|
|
|
class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
|
2012-04-30 23:09:08 -07:00
|
|
|
public:
|
|
|
|
|
virtual ~QuaternionParameterization() {}
|
2019-07-13 11:19:27 +02:00
|
|
|
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; }
|
2012-04-30 23:09:08 -07:00
|
|
|
};
|
|
|
|
|
|
2016-08-17 13:39:05 -07:00
|
|
|
// 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.
|
2017-02-15 11:01:27 -08:00
|
|
|
class CERES_EXPORT EigenQuaternionParameterization
|
|
|
|
|
: public ceres::LocalParameterization {
|
2016-08-17 13:39:05 -07:00
|
|
|
public:
|
|
|
|
|
virtual ~EigenQuaternionParameterization() {}
|
2019-07-13 11:19:27 +02:00
|
|
|
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; }
|
2016-08-17 13:39:05 -07:00
|
|
|
};
|
2015-03-03 15:04:47 -08:00
|
|
|
|
|
|
|
|
// 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.
|
2019-07-13 11:19:27 +02:00
|
|
|
class CERES_EXPORT HomogeneousVectorParameterization
|
|
|
|
|
: public LocalParameterization {
|
2015-03-03 15:04:47 -08:00
|
|
|
public:
|
|
|
|
|
explicit HomogeneousVectorParameterization(int size);
|
|
|
|
|
virtual ~HomogeneousVectorParameterization() {}
|
2019-07-13 11:19:27 +02:00
|
|
|
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; }
|
2015-03-03 15:04:47 -08:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const int size_;
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-12 19:39:47 -07:00
|
|
|
// 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_EXPORT ProductParameterization : public LocalParameterization {
|
|
|
|
|
public:
|
2019-05-28 17:46:44 +08:00
|
|
|
ProductParameterization(const ProductParameterization&) = delete;
|
|
|
|
|
ProductParameterization& operator=(const ProductParameterization&) = delete;
|
2015-07-12 19:39:47 -07:00
|
|
|
//
|
2019-04-19 13:36:37 +02:00
|
|
|
// NOTE: The constructor takes ownership of the input local
|
2015-07-12 19:39:47 -07:00
|
|
|
// parameterizations.
|
|
|
|
|
//
|
2019-04-19 13:36:37 +02:00
|
|
|
template <typename... LocalParams>
|
|
|
|
|
ProductParameterization(LocalParams*... local_params)
|
|
|
|
|
: local_params_(sizeof...(LocalParams)),
|
|
|
|
|
local_size_{0},
|
|
|
|
|
global_size_{0},
|
|
|
|
|
buffer_size_{0} {
|
|
|
|
|
constexpr int kNumLocalParams = sizeof...(LocalParams);
|
|
|
|
|
static_assert(kNumLocalParams >= 2,
|
|
|
|
|
"At least two local parameterizations must be specified.");
|
|
|
|
|
|
|
|
|
|
using LocalParameterizationPtr = std::unique_ptr<LocalParameterization>;
|
2015-07-12 19:39:47 -07:00
|
|
|
|
2019-04-19 13:36:37 +02:00
|
|
|
// Wrap all raw pointers into std::unique_ptr for exception safety.
|
|
|
|
|
std::array<LocalParameterizationPtr, kNumLocalParams> local_params_array{
|
|
|
|
|
LocalParameterizationPtr(local_params)...};
|
2015-07-12 19:39:47 -07:00
|
|
|
|
2019-04-19 13:36:37 +02:00
|
|
|
// 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();
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-07-12 19:39:47 -07:00
|
|
|
|
2019-07-13 11:19:27 +02:00
|
|
|
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_; }
|
2015-07-12 19:39:47 -07:00
|
|
|
|
|
|
|
|
private:
|
2019-04-19 13:36:37 +02:00
|
|
|
std::vector<std::unique_ptr<LocalParameterization>> local_params_;
|
2015-07-12 19:39:47 -07:00
|
|
|
int local_size_;
|
|
|
|
|
int global_size_;
|
|
|
|
|
int buffer_size_;
|
|
|
|
|
};
|
|
|
|
|
|
2012-04-30 23:09:08 -07:00
|
|
|
} // namespace ceres
|
|
|
|
|
|
2014-05-19 08:21:00 +02:00
|
|
|
#include "ceres/internal/reenable_warnings.h"
|
|
|
|
|
|
2012-04-30 23:09:08 -07:00
|
|
|
#endif // CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
|