|
Packit |
ea1746 |
// Ceres Solver - A fast non-linear least squares minimizer
|
|
Packit |
ea1746 |
// Copyright 2015 Google Inc. All rights reserved.
|
|
Packit |
ea1746 |
// http://ceres-solver.org/
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// Redistribution and use in source and binary forms, with or without
|
|
Packit |
ea1746 |
// modification, are permitted provided that the following conditions are met:
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// * Redistributions of source code must retain the above copyright notice,
|
|
Packit |
ea1746 |
// this list of conditions and the following disclaimer.
|
|
Packit |
ea1746 |
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
Packit |
ea1746 |
// this list of conditions and the following disclaimer in the documentation
|
|
Packit |
ea1746 |
// and/or other materials provided with the distribution.
|
|
Packit |
ea1746 |
// * Neither the name of Google Inc. nor the names of its contributors may be
|
|
Packit |
ea1746 |
// used to endorse or promote products derived from this software without
|
|
Packit |
ea1746 |
// specific prior written permission.
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
ea1746 |
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
ea1746 |
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
ea1746 |
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
Packit |
ea1746 |
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
Packit |
ea1746 |
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
Packit |
ea1746 |
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit |
ea1746 |
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit |
ea1746 |
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
ea1746 |
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit |
ea1746 |
// POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
|
Packit |
ea1746 |
// dgossow@google.com (David Gossow)
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#ifndef CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
|
|
Packit |
ea1746 |
#define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#include <numeric>
|
|
Packit |
ea1746 |
#include <vector>
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#include "ceres/dynamic_cost_function.h"
|
|
Packit |
ea1746 |
#include "ceres/internal/fixed_array.h"
|
|
Packit |
ea1746 |
#include "ceres/internal/port.h"
|
|
Packit |
ea1746 |
#include "ceres/internal/scoped_ptr.h"
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
namespace ceres {
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
// DynamicCostFunctionToFunctor allows users to use CostFunction
|
|
Packit |
ea1746 |
// objects in templated functors which are to be used for automatic
|
|
Packit |
ea1746 |
// differentiation. It works similar to CostFunctionToFunctor, with the
|
|
Packit |
ea1746 |
// difference that it allows you to wrap a cost function with dynamic numbers
|
|
Packit |
ea1746 |
// of parameters and residuals.
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// For example, let us assume that
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// class IntrinsicProjection : public CostFunction {
|
|
Packit |
ea1746 |
// public:
|
|
Packit |
ea1746 |
// IntrinsicProjection(const double* observation);
|
|
Packit |
ea1746 |
// virtual bool Evaluate(double const* const* parameters,
|
|
Packit |
ea1746 |
// double* residuals,
|
|
Packit |
ea1746 |
// double** jacobians) const;
|
|
Packit |
ea1746 |
// };
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// is a cost function that implements the projection of a point in its
|
|
Packit |
ea1746 |
// local coordinate system onto its image plane and subtracts it from
|
|
Packit |
ea1746 |
// the observed point projection. It can compute its residual and
|
|
Packit |
ea1746 |
// either via analytic or numerical differentiation can compute its
|
|
Packit |
ea1746 |
// jacobians. The intrinsics are passed in as parameters[0] and the point as
|
|
Packit |
ea1746 |
// parameters[1].
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// Now we would like to compose the action of this CostFunction with
|
|
Packit |
ea1746 |
// the action of camera extrinsics, i.e., rotation and
|
|
Packit |
ea1746 |
// translation. Say we have a templated function
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// template<typename T>
|
|
Packit |
ea1746 |
// void RotateAndTranslatePoint(double const* const* parameters,
|
|
Packit |
ea1746 |
// double* residuals);
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// Then we can now do the following,
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// struct CameraProjection {
|
|
Packit |
ea1746 |
// CameraProjection(const double* observation)
|
|
Packit |
ea1746 |
// : intrinsic_projection_.(new IntrinsicProjection(observation)) {
|
|
Packit |
ea1746 |
// }
|
|
Packit |
ea1746 |
// template <typename T>
|
|
Packit |
ea1746 |
// bool operator()(T const* const* parameters,
|
|
Packit |
ea1746 |
// T* residual) const {
|
|
Packit |
ea1746 |
// const T* rotation = parameters[0];
|
|
Packit |
ea1746 |
// const T* translation = parameters[1];
|
|
Packit |
ea1746 |
// const T* intrinsics = parameters[2];
|
|
Packit |
ea1746 |
// const T* point = parameters[3];
|
|
Packit |
ea1746 |
// T transformed_point[3];
|
|
Packit |
ea1746 |
// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// // Note that we call intrinsic_projection_, just like it was
|
|
Packit |
ea1746 |
// // any other templated functor.
|
|
Packit |
ea1746 |
// const T* projection_parameters[2];
|
|
Packit |
ea1746 |
// projection_parameters[0] = intrinsics;
|
|
Packit |
ea1746 |
// projection_parameters[1] = transformed_point;
|
|
Packit |
ea1746 |
// return intrinsic_projection_(projection_parameters, residual);
|
|
Packit |
ea1746 |
// }
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// private:
|
|
Packit |
ea1746 |
// DynamicCostFunctionToFunctor intrinsic_projection_;
|
|
Packit |
ea1746 |
// };
|
|
Packit |
ea1746 |
class DynamicCostFunctionToFunctor {
|
|
Packit |
ea1746 |
public:
|
|
Packit |
ea1746 |
// Takes ownership of cost_function.
|
|
Packit |
ea1746 |
explicit DynamicCostFunctionToFunctor(CostFunction* cost_function)
|
|
Packit |
ea1746 |
: cost_function_(cost_function) {
|
|
Packit |
ea1746 |
CHECK_NOTNULL(cost_function);
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
bool operator()(double const* const* parameters, double* residuals) const {
|
|
Packit |
ea1746 |
return cost_function_->Evaluate(parameters, residuals, NULL);
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
template <typename JetT>
|
|
Packit |
ea1746 |
bool operator()(JetT const* const* inputs, JetT* output) const {
|
|
Packit |
ea1746 |
const std::vector<int32>& parameter_block_sizes =
|
|
Packit |
ea1746 |
cost_function_->parameter_block_sizes();
|
|
Packit |
ea1746 |
const int num_parameter_blocks =
|
|
Packit |
ea1746 |
static_cast<int>(parameter_block_sizes.size());
|
|
Packit |
ea1746 |
const int num_residuals = cost_function_->num_residuals();
|
|
Packit |
ea1746 |
const int num_parameters = std::accumulate(parameter_block_sizes.begin(),
|
|
Packit |
ea1746 |
parameter_block_sizes.end(), 0);
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
internal::FixedArray<double> parameters(num_parameters);
|
|
Packit |
ea1746 |
internal::FixedArray<double*> parameter_blocks(num_parameter_blocks);
|
|
Packit |
ea1746 |
internal::FixedArray<double> jacobians(num_residuals * num_parameters);
|
|
Packit |
ea1746 |
internal::FixedArray<double*> jacobian_blocks(num_parameter_blocks);
|
|
Packit |
ea1746 |
internal::FixedArray<double> residuals(num_residuals);
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
// Build a set of arrays to get the residuals and jacobians from
|
|
Packit |
ea1746 |
// the CostFunction wrapped by this functor.
|
|
Packit |
ea1746 |
double* parameter_ptr = parameters.get();
|
|
Packit |
ea1746 |
double* jacobian_ptr = jacobians.get();
|
|
Packit |
ea1746 |
for (int i = 0; i < num_parameter_blocks; ++i) {
|
|
Packit |
ea1746 |
parameter_blocks[i] = parameter_ptr;
|
|
Packit |
ea1746 |
jacobian_blocks[i] = jacobian_ptr;
|
|
Packit |
ea1746 |
for (int j = 0; j < parameter_block_sizes[i]; ++j) {
|
|
Packit |
ea1746 |
*parameter_ptr++ = inputs[i][j].a;
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
jacobian_ptr += num_residuals * parameter_block_sizes[i];
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
if (!cost_function_->Evaluate(parameter_blocks.get(),
|
|
Packit |
ea1746 |
residuals.get(),
|
|
Packit |
ea1746 |
jacobian_blocks.get())) {
|
|
Packit |
ea1746 |
return false;
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
// Now that we have the incoming Jets, which are carrying the
|
|
Packit |
ea1746 |
// partial derivatives of each of the inputs w.r.t to some other
|
|
Packit |
ea1746 |
// underlying parameters. The derivative of the outputs of the
|
|
Packit |
ea1746 |
// cost function w.r.t to the same underlying parameters can now
|
|
Packit |
ea1746 |
// be computed by applying the chain rule.
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// d output[i] d output[i] d input[j]
|
|
Packit |
ea1746 |
// -------------- = sum_j ----------- * ------------
|
|
Packit |
ea1746 |
// d parameter[k] d input[j] d parameter[k]
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// d input[j]
|
|
Packit |
ea1746 |
// -------------- = inputs[j], so
|
|
Packit |
ea1746 |
// d parameter[k]
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// outputJet[i] = sum_k jacobian[i][k] * inputJet[k]
|
|
Packit |
ea1746 |
//
|
|
Packit |
ea1746 |
// The following loop, iterates over the residuals, computing one
|
|
Packit |
ea1746 |
// output jet at a time.
|
|
Packit |
ea1746 |
for (int i = 0; i < num_residuals; ++i) {
|
|
Packit |
ea1746 |
output[i].a = residuals[i];
|
|
Packit |
ea1746 |
output[i].v.setZero();
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
for (int j = 0; j < num_parameter_blocks; ++j) {
|
|
Packit |
ea1746 |
const int32 block_size = parameter_block_sizes[j];
|
|
Packit |
ea1746 |
for (int k = 0; k < parameter_block_sizes[j]; ++k) {
|
|
Packit |
ea1746 |
output[i].v +=
|
|
Packit |
ea1746 |
jacobian_blocks[j][i * block_size + k] * inputs[j][k].v;
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
return true;
|
|
Packit |
ea1746 |
}
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
private:
|
|
Packit |
ea1746 |
internal::scoped_ptr<CostFunction> cost_function_;
|
|
Packit |
ea1746 |
};
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
} // namespace ceres
|
|
Packit |
ea1746 |
|
|
Packit |
ea1746 |
#endif // CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
|