Files
ceres-solver/include/ceres/cost_function_to_functor.h
T

172 lines
6.7 KiB
C++
Raw Normal View History

2013-01-13 22:14:12 -08: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.
// http://ceres-solver.org/
2013-01-13 22:14:12 -08: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: sameeragarwal@google.com (Sameer Agarwal)
//
// CostFunctionToFunctor is an adapter class that allows users to use
2015-06-16 14:10:56 -07:00
// SizedCostFunction objects in templated functors which are to be used for
2018-10-15 20:03:16 +02:00
// automatic differentiation. This allows the user to seamlessly mix
2013-01-13 22:14:12 -08:00
// analytic, numeric and automatic differentiation.
//
// For example, let us assume that
//
// class IntrinsicProjection : public SizedCostFunction<2, 5, 3> {
// public:
2015-06-16 14:10:56 -07:00
// IntrinsicProjection(const double* observation);
// bool Evaluate(double const* const* parameters,
// double* residuals,
// double** jacobians) const override;
2013-01-13 22:14:12 -08:00
// };
//
// is a cost function that implements the projection of a point in its
// local coordinate system onto its image plane and subtracts it from
// the observed point projection. It can compute its residual and
// jacobians either via analytic or numerical differentiation.
2013-01-13 22:14:12 -08:00
//
// Now we would like to compose the action of this CostFunction with
// the action of camera extrinsics, i.e., rotation and
// translation. Say we have a templated function
//
// template<typename T>
// void RotateAndTranslatePoint(const T* rotation,
// const T* translation,
// const T* point,
// T* result);
//
// Then we can now do the following,
//
// struct CameraProjection {
2015-06-16 14:10:56 -07:00
// CameraProjection(const double* observation)
// : intrinsic_projection_(new IntrinsicProjection(observation)) {
2013-01-13 22:14:12 -08:00
// }
// template <typename T>
// bool operator()(const T* rotation,
// const T* translation,
// const T* intrinsics,
// const T* point,
// T* residual) const {
2013-01-13 22:14:12 -08:00
// T transformed_point[3];
// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
//
// // Note that we call intrinsic_projection_, just like it was
// // any other templated functor.
//
2015-06-16 14:10:56 -07:00
// return intrinsic_projection_(intrinsics, transformed_point, residual);
2013-02-20 01:39:03 -08:00
// }
2013-01-13 22:14:12 -08:00
//
// private:
2015-06-16 14:10:56 -07:00
// CostFunctionToFunctor<2,5,3> intrinsic_projection_;
2013-01-13 22:14:12 -08:00
// };
#ifndef CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
#define CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
2018-08-08 04:27:24 -07:00
#include <cstdint>
2018-10-15 20:03:16 +02:00
#include <numeric>
#include <tuple>
#include <utility>
2013-01-13 22:14:12 -08:00
#include <vector>
#include "ceres/cost_function.h"
2015-06-16 14:10:56 -07:00
#include "ceres/dynamic_cost_function_to_functor.h"
2022-02-07 23:43:19 +01:00
#include "ceres/internal/export.h"
2013-01-13 22:14:12 -08:00
#include "ceres/internal/fixed_array.h"
2018-10-15 20:03:16 +02:00
#include "ceres/internal/parameter_dims.h"
2018-08-08 04:27:24 -07:00
#include "ceres/types.h"
#include "glog/logging.h"
2013-01-13 22:14:12 -08:00
namespace ceres {
2018-10-15 20:03:16 +02:00
template <int kNumResiduals, int... Ns>
2013-01-13 22:14:12 -08:00
class CostFunctionToFunctor {
public:
2015-06-16 14:10:56 -07:00
// Takes ownership of cost_function.
2013-02-20 01:39:03 -08:00
explicit CostFunctionToFunctor(CostFunction* cost_function)
2015-06-16 14:10:56 -07:00
: cost_functor_(cost_function) {
2018-08-27 07:12:43 -07:00
CHECK(cost_function != nullptr);
CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC);
2013-01-13 22:14:12 -08:00
2018-08-08 04:27:24 -07:00
const std::vector<int32_t>& parameter_block_sizes =
2013-02-20 01:39:03 -08:00
cost_function->parameter_block_sizes();
2018-10-15 20:03:16 +02:00
const int num_parameter_blocks = ParameterDims::kNumParameterBlocks;
2016-08-31 18:40:57 +02:00
CHECK_EQ(static_cast<int>(parameter_block_sizes.size()),
num_parameter_blocks);
2013-01-13 22:14:12 -08:00
2018-10-15 20:03:16 +02:00
if (parameter_block_sizes.size() == num_parameter_blocks) {
for (int block = 0; block < num_parameter_blocks; ++block) {
CHECK_EQ(ParameterDims::GetDim(block), parameter_block_sizes[block])
2022-04-24 19:07:37 -07:00
<< "Parameter block size mismatch. The specified static parameter "
2018-10-15 20:03:16 +02:00
"block dimension does not match the one from the cost function.";
}
}
2013-02-20 01:39:03 -08:00
2019-12-02 13:52:31 -08:00
CHECK_EQ(accumulate(
parameter_block_sizes.begin(), parameter_block_sizes.end(), 0),
2018-10-15 20:03:16 +02:00
ParameterDims::kNumParameters);
2013-01-13 22:14:12 -08:00
}
2018-10-15 20:03:16 +02:00
template <typename T, typename... Ts>
bool operator()(const T* p1, Ts*... ps) const {
// Add one because of residual block.
static_assert(sizeof...(Ts) + 1 == ParameterDims::kNumParameterBlocks + 1,
"Invalid number of parameter blocks specified.");
2013-01-13 22:14:12 -08:00
2018-10-15 20:03:16 +02:00
auto params = std::make_tuple(p1, ps...);
2013-01-13 22:14:12 -08:00
2018-10-15 20:03:16 +02:00
// Extract residual pointer from params. The residual pointer is the
// last pointer.
constexpr int kResidualIndex = ParameterDims::kNumParameterBlocks;
T* residuals = std::get<kResidualIndex>(params);
2013-01-13 22:14:12 -08:00
2018-10-15 20:03:16 +02:00
// Extract parameter block pointers from params.
using Indices =
2020-09-06 21:04:24 +02:00
std::make_integer_sequence<int, ParameterDims::kNumParameterBlocks>;
2018-10-15 20:03:16 +02:00
std::array<const T*, ParameterDims::kNumParameterBlocks> parameter_blocks =
GetParameterPointers<T>(params, Indices());
2013-01-13 22:14:12 -08:00
2018-10-15 20:03:16 +02:00
return cost_functor_(parameter_blocks.data(), residuals);
2013-01-13 22:14:12 -08:00
}
2018-10-15 20:03:16 +02:00
private:
using ParameterDims = internal::StaticParameterDims<Ns...>;
2013-01-13 22:14:12 -08:00
2018-10-15 20:03:16 +02:00
template <typename T, typename Tuple, int... Indices>
static std::array<const T*, ParameterDims::kNumParameterBlocks>
GetParameterPointers(const Tuple& paramPointers,
std::integer_sequence<int, Indices...>) {
2018-10-15 20:03:16 +02:00
return std::array<const T*, ParameterDims::kNumParameterBlocks>{
{std::get<Indices>(paramPointers)...}};
2013-01-13 22:14:12 -08:00
}
2015-06-16 14:10:56 -07:00
DynamicCostFunctionToFunctor cost_functor_;
2013-01-13 22:14:12 -08:00
};
} // namespace ceres
#endif // CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_