interpolated_grid.hpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * Copyright 2016 The Cartographer Authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef CARTOGRAPHER_MAPPING_INTERNAL_3D_SCAN_MATCHING_INTERPOLATED_GRID_H_
  17. #define CARTOGRAPHER_MAPPING_INTERNAL_3D_SCAN_MATCHING_INTERPOLATED_GRID_H_
  18. #include <cmath>
  19. #include "hybrid_grid.hpp"
  20. // Interpolates between HybridGrid voxels. We use the tricubic
  21. // interpolation which interpolates the values and has vanishing derivative at
  22. // these points.
  23. //
  24. // This class is templated to work with the autodiff that Ceres provides.
  25. // For this reason, it is also important that the interpolation scheme be
  26. // continuously differentiable.
  27. template <class HybridGridType>
  28. class InterpolatedGrid {
  29. public:
  30. explicit InterpolatedGrid(const HybridGridType& hybrid_grid)
  31. : hybrid_grid_(hybrid_grid) {}
  32. InterpolatedGrid(const InterpolatedGrid<HybridGridType>&) = delete;
  33. InterpolatedGrid& operator=(const InterpolatedGrid<HybridGridType>&) = delete;
  34. // Returns the interpolated value at (x, y, z) of the HybridGrid
  35. // used to perform the interpolation.
  36. //
  37. // This is a piecewise, continuously differentiable function. We use the
  38. // scalar part of Jet parameters to select our interval below. It is the
  39. // tensor product volume of piecewise cubic polynomials that interpolate
  40. // the values, and have vanishing derivative at the interval boundaries.
  41. template <typename T>
  42. T GetInterpolatedValue(const T& x, const T& y, const T& z) const {
  43. double x1, y1, z1, x2, y2, z2;
  44. ComputeInterpolationDataPoints(x, y, z, &x1, &y1, &z1, &x2, &y2, &z2);
  45. const Eigen::Array3i index1 =
  46. hybrid_grid_.GetCellIndex(Eigen::Vector3f(x1, y1, z1));
  47. const double q111 = GetValue(hybrid_grid_, index1);
  48. const double q112 =
  49. GetValue(hybrid_grid_, index1 + Eigen::Array3i(0, 0, 1));
  50. const double q121 =
  51. GetValue(hybrid_grid_, index1 + Eigen::Array3i(0, 1, 0));
  52. const double q122 =
  53. GetValue(hybrid_grid_, index1 + Eigen::Array3i(0, 1, 1));
  54. const double q211 =
  55. GetValue(hybrid_grid_, index1 + Eigen::Array3i(1, 0, 0));
  56. const double q212 =
  57. GetValue(hybrid_grid_, index1 + Eigen::Array3i(1, 0, 1));
  58. const double q221 =
  59. GetValue(hybrid_grid_, index1 + Eigen::Array3i(1, 1, 0));
  60. const double q222 =
  61. GetValue(hybrid_grid_, index1 + Eigen::Array3i(1, 1, 1));
  62. const T normalized_x = (x - x1) / (x2 - x1);
  63. const T normalized_y = (y - y1) / (y2 - y1);
  64. const T normalized_z = (z - z1) / (z2 - z1);
  65. // Compute pow(..., 2) and pow(..., 3). Using pow() here is very expensive.
  66. const T normalized_xx = normalized_x * normalized_x;
  67. const T normalized_xxx = normalized_x * normalized_xx;
  68. const T normalized_yy = normalized_y * normalized_y;
  69. const T normalized_yyy = normalized_y * normalized_yy;
  70. const T normalized_zz = normalized_z * normalized_z;
  71. const T normalized_zzz = normalized_z * normalized_zz;
  72. // We first interpolate in z, then y, then x. All 7 times this uses the same
  73. // scheme: A * (2t^3 - 3t^2 + 1) + B * (-2t^3 + 3t^2).
  74. // The first polynomial is 1 at t=0, 0 at t=1, the second polynomial is 0
  75. // at t=0, 1 at t=1. Both polynomials have derivative zero at t=0 and t=1.
  76. const T q11 = (q111 - q112) * normalized_zzz * 2. +
  77. (q112 - q111) * normalized_zz * 3. + q111;
  78. const T q12 = (q121 - q122) * normalized_zzz * 2. +
  79. (q122 - q121) * normalized_zz * 3. + q121;
  80. const T q21 = (q211 - q212) * normalized_zzz * 2. +
  81. (q212 - q211) * normalized_zz * 3. + q211;
  82. const T q22 = (q221 - q222) * normalized_zzz * 2. +
  83. (q222 - q221) * normalized_zz * 3. + q221;
  84. const T q1 = (q11 - q12) * normalized_yyy * 2. +
  85. (q12 - q11) * normalized_yy * 3. + q11;
  86. const T q2 = (q21 - q22) * normalized_yyy * 2. +
  87. (q22 - q21) * normalized_yy * 3. + q21;
  88. return (q1 - q2) * normalized_xxx * 2. + (q2 - q1) * normalized_xx * 3. +
  89. q1;
  90. }
  91. private:
  92. template <typename T>
  93. void ComputeInterpolationDataPoints(const T& x, const T& y, const T& z,
  94. double* x1, double* y1, double* z1,
  95. double* x2, double* y2,
  96. double* z2) const {
  97. const Eigen::Vector3f lower = CenterOfLowerVoxel(x, y, z);
  98. *x1 = lower.x();
  99. *y1 = lower.y();
  100. *z1 = lower.z();
  101. *x2 = lower.x() + hybrid_grid_.resolution();
  102. *y2 = lower.y() + hybrid_grid_.resolution();
  103. *z2 = lower.z() + hybrid_grid_.resolution();
  104. }
  105. // Center of the next lower voxel, i.e., not necessarily the voxel containing
  106. // (x, y, z). For each dimension, the largest voxel index so that the
  107. // corresponding center is at most the given coordinate.
  108. Eigen::Vector3f CenterOfLowerVoxel(const double x, const double y,
  109. const double z) const {
  110. // Center of the cell containing (x, y, z).
  111. Eigen::Vector3f center = hybrid_grid_.GetCenterOfCell(
  112. hybrid_grid_.GetCellIndex(Eigen::Vector3f(x, y, z)));
  113. // Move to the next lower voxel center.
  114. if (center.x() > x) {
  115. center.x() -= hybrid_grid_.resolution();
  116. }
  117. if (center.y() > y) {
  118. center.y() -= hybrid_grid_.resolution();
  119. }
  120. if (center.z() > z) {
  121. center.z() -= hybrid_grid_.resolution();
  122. }
  123. return center;
  124. }
  125. // Uses the scalar part of a Ceres Jet.
  126. template <typename T>
  127. Eigen::Vector3f CenterOfLowerVoxel(const T& jet_x, const T& jet_y,
  128. const T& jet_z) const {
  129. return CenterOfLowerVoxel(jet_x.a, jet_y.a, jet_z.a);
  130. }
  131. static float GetValue(const HybridGrid& probability_grid,
  132. const Eigen::Array3i& index) {
  133. return probability_grid.GetProbability(index);
  134. }
  135. const HybridGridType& hybrid_grid_;
  136. };
  137. using InterpolatedProbabilityGrid = InterpolatedGrid<HybridGrid>;
  138. #endif // CARTOGRAPHER_MAPPING_INTERNAL_3D_SCAN_MATCHING_INTERPOLATED_GRID_H_