cost_function_to_functor.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Ceres Solver - A fast non-linear least squares minimizer
  2. // Copyright 2019 Google Inc. All rights reserved.
  3. // http://ceres-solver.org/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Google Inc. nor the names of its contributors may be
  14. // used to endorse or promote products derived from this software without
  15. // specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. // POSSIBILITY OF SUCH DAMAGE.
  28. //
  29. // Author: sameeragarwal@google.com (Sameer Agarwal)
  30. //
  31. // CostFunctionToFunctor is an adapter class that allows users to use
  32. // SizedCostFunction objects in templated functors which are to be used for
  33. // automatic differentiation. This allows the user to seamlessly mix
  34. // analytic, numeric and automatic differentiation.
  35. //
  36. // For example, let us assume that
  37. //
  38. // class IntrinsicProjection : public SizedCostFunction<2, 5, 3> {
  39. // public:
  40. // IntrinsicProjection(const double* observation);
  41. // bool Evaluate(double const* const* parameters,
  42. // double* residuals,
  43. // double** jacobians) const override;
  44. // };
  45. //
  46. // is a cost function that implements the projection of a point in its
  47. // local coordinate system onto its image plane and subtracts it from
  48. // the observed point projection. It can compute its residual and
  49. // jacobians either via analytic or numerical differentiation.
  50. //
  51. // Now we would like to compose the action of this CostFunction with
  52. // the action of camera extrinsics, i.e., rotation and
  53. // translation. Say we have a templated function
  54. //
  55. // template<typename T>
  56. // void RotateAndTranslatePoint(const T* rotation,
  57. // const T* translation,
  58. // const T* point,
  59. // T* result);
  60. //
  61. // Then we can now do the following,
  62. //
  63. // struct CameraProjection {
  64. // CameraProjection(const double* observation)
  65. // : intrinsic_projection_(new IntrinsicProjection(observation)) {
  66. // }
  67. // template <typename T>
  68. // bool operator()(const T* rotation,
  69. // const T* translation,
  70. // const T* intrinsics,
  71. // const T* point,
  72. // T* residual) const {
  73. // T transformed_point[3];
  74. // RotateAndTranslatePoint(rotation, translation, point, transformed_point);
  75. //
  76. // // Note that we call intrinsic_projection_, just like it was
  77. // // any other templated functor.
  78. //
  79. // return intrinsic_projection_(intrinsics, transformed_point, residual);
  80. // }
  81. //
  82. // private:
  83. // CostFunctionToFunctor<2,5,3> intrinsic_projection_;
  84. // };
  85. #ifndef CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
  86. #define CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
  87. #include <cstdint>
  88. #include <numeric>
  89. #include <tuple>
  90. #include <utility>
  91. #include <vector>
  92. #include "ceres/cost_function.h"
  93. #include "ceres/dynamic_cost_function_to_functor.h"
  94. #include "ceres/internal/export.h"
  95. #include "ceres/internal/fixed_array.h"
  96. #include "ceres/internal/parameter_dims.h"
  97. #include "ceres/types.h"
  98. #include "glog/logging.h"
  99. namespace ceres {
  100. template <int kNumResiduals, int... Ns>
  101. class CostFunctionToFunctor {
  102. public:
  103. // Takes ownership of cost_function.
  104. explicit CostFunctionToFunctor(CostFunction* cost_function)
  105. : cost_functor_(cost_function) {
  106. CHECK(cost_function != nullptr);
  107. CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC);
  108. const std::vector<int32_t>& parameter_block_sizes =
  109. cost_function->parameter_block_sizes();
  110. const int num_parameter_blocks = ParameterDims::kNumParameterBlocks;
  111. CHECK_EQ(static_cast<int>(parameter_block_sizes.size()),
  112. num_parameter_blocks);
  113. if (parameter_block_sizes.size() == num_parameter_blocks) {
  114. for (int block = 0; block < num_parameter_blocks; ++block) {
  115. CHECK_EQ(ParameterDims::GetDim(block), parameter_block_sizes[block])
  116. << "Parameter block size mismatch. The specified static parameter "
  117. "block dimension does not match the one from the cost function.";
  118. }
  119. }
  120. CHECK_EQ(accumulate(
  121. parameter_block_sizes.begin(), parameter_block_sizes.end(), 0),
  122. ParameterDims::kNumParameters);
  123. }
  124. template <typename T, typename... Ts>
  125. bool operator()(const T* p1, Ts*... ps) const {
  126. // Add one because of residual block.
  127. static_assert(sizeof...(Ts) + 1 == ParameterDims::kNumParameterBlocks + 1,
  128. "Invalid number of parameter blocks specified.");
  129. auto params = std::make_tuple(p1, ps...);
  130. // Extract residual pointer from params. The residual pointer is the
  131. // last pointer.
  132. constexpr int kResidualIndex = ParameterDims::kNumParameterBlocks;
  133. T* residuals = std::get<kResidualIndex>(params);
  134. // Extract parameter block pointers from params.
  135. using Indices =
  136. std::make_integer_sequence<int, ParameterDims::kNumParameterBlocks>;
  137. std::array<const T*, ParameterDims::kNumParameterBlocks> parameter_blocks =
  138. GetParameterPointers<T>(params, Indices());
  139. return cost_functor_(parameter_blocks.data(), residuals);
  140. }
  141. private:
  142. using ParameterDims = internal::StaticParameterDims<Ns...>;
  143. template <typename T, typename Tuple, int... Indices>
  144. static std::array<const T*, ParameterDims::kNumParameterBlocks>
  145. GetParameterPointers(const Tuple& paramPointers,
  146. std::integer_sequence<int, Indices...>) {
  147. return std::array<const T*, ParameterDims::kNumParameterBlocks>{
  148. {std::get<Indices>(paramPointers)...}};
  149. }
  150. DynamicCostFunctionToFunctor cost_functor_;
  151. };
  152. } // namespace ceres
  153. #endif // CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_