Cartographer源码阅读3D-前端匹配

Cartographer源码阅读3D-前端匹配

暴力匹配:RealTimeCorrelativeScanMatcher3D

暴力搜索计算匹配得分,取得最高分对应的位姿。

class RealTimeCorrelativeScanMatcher3D {
 public:
  explicit RealTimeCorrelativeScanMatcher3D(
      const scan_matching::proto::RealTimeCorrelativeScanMatcherOptions&
          options);

  RealTimeCorrelativeScanMatcher3D(const RealTimeCorrelativeScanMatcher3D&) =
      delete;
  RealTimeCorrelativeScanMatcher3D& operator=(
      const RealTimeCorrelativeScanMatcher3D&) = delete;

  // Aligns 'point_cloud' within the 'hybrid_grid' given an
  // 'initial_pose_estimate' then updates 'pose_estimate' with the result and
  // returns the score.
  // 传进来的都是高分辨率的网格和高分辨率点云
  float Match(const transform::Rigid3d& initial_pose_estimate,
              const sensor::PointCloud& point_cloud,
              const HybridGrid& hybrid_grid,
              transform::Rigid3d* pose_estimate) const;

 private:
  // 生成所有可能解的位姿:x  *y *z * rx * ry * rz个
  std::vector<transform::Rigid3f> GenerateExhaustiveSearchTransforms(
      float resolution, const sensor::PointCloud& point_cloud) const;
  // 打分
  float ScoreCandidate(const HybridGrid& hybrid_grid,
                       const sensor::PointCloud& transformed_point_cloud,
                       const transform::Rigid3f& transform) const;

  const proto::RealTimeCorrelativeScanMatcherOptions options_;
};
// 入口函数
float RealTimeCorrelativeScanMatcher3D::Match(
    const transform::Rigid3d& initial_pose_estimate,
    const sensor::PointCloud& point_cloud, const HybridGrid& hybrid_grid,
    transform::Rigid3d* pose_estimate) const {
  CHECK_NOTNULL(pose_estimate);
  float best_score = -1.f;
  // 生成所有候选解,并遍历所有的候选解(位姿增量)
  for (const transform::Rigid3f& transform : GenerateExhaustiveSearchTransforms(
           hybrid_grid.resolution(), point_cloud)) {
    // 生成候选解(需要乘以位姿)
    const transform::Rigid3f candidate =
        initial_pose_estimate.cast<float>() * transform;
    // 针对该候选解打分
    const float score = ScoreCandidate(
        hybrid_grid, sensor::TransformPointCloud(point_cloud, candidate),
        transform);
    // 最高分迭代
    if (score > best_score) {
      best_score = score;
      *pose_estimate = candidate.cast<double>();
    }
  }
  return best_score;
}

// 生成候选解增量
std::vector<transform::Rigid3f>
RealTimeCorrelativeScanMatcher3D::GenerateExhaustiveSearchTransforms(
    const float resolution, const sensor::PointCloud& point_cloud) const {
  std::vector<transform::Rigid3f> result;
  // 获取线搜索框搜索范围
  const int linear_window_size =
      common::RoundToInt(options_.linear_search_window() / resolution);
  // We set this value to something on the order of resolution to make sure that
  // the std::acos() below is defined.
  // 得到最大的测距
  float max_scan_range = 3.f * resolution;
  for (const Eigen::Vector3f& point : point_cloud) {
    const float range = point.norm();
    max_scan_range = std::max(range, max_scan_range);
  }
  const float kSafetyMargin = 1.f - 1e-3f;
  // 计算最小角度搜索增量,计算方法和2D相同
  const float angular_step_size =
      kSafetyMargin * std::acos(1.f - common::Pow2(resolution) /
                                          (2.f * common::Pow2(max_scan_range)));
  // 计算角度搜索框搜索范围
  const int angular_window_size =
      common::RoundToInt(options_.angular_search_window() / angular_step_size);
  for (int z = -linear_window_size; z <= linear_window_size; ++z) {
    for (int y = -linear_window_size; y <= linear_window_size; ++y) {
      for (int x = -linear_window_size; x <= linear_window_size; ++x) {
        for (int rz = -angular_window_size; rz <= angular_window_size; ++rz) {
          for (int ry = -angular_window_size; ry <= angular_window_size; ++ry) {
            for (int rx = -angular_window_size; rx <= angular_window_size;
                 ++rx) {
              const Eigen::Vector3f angle_axis(rx * angular_step_size,
                                               ry * angular_step_size,
                                               rz * angular_step_size);
              // 生成候选解增量
              result.emplace_back(
                  Eigen::Vector3f(x * resolution, y * resolution,
                                  z * resolution),
                  transform::AngleAxisVectorToRotationQuaternion(angle_axis));
            }
          }
        }
      }
    }
  }
  return result;
}
// 打分
float RealTimeCorrelativeScanMatcher3D::ScoreCandidate(
    const HybridGrid& hybrid_grid,
    const sensor::PointCloud& transformed_point_cloud,
    const transform::Rigid3f& transform) const {
  float score = 0.f;
  // 暴力计算每个点的得分总和
  for (const Eigen::Vector3f& point : transformed_point_cloud) {
    score += hybrid_grid.GetProbability(hybrid_grid.GetCellIndex(point));
  }
  // 得到平均分
  score /= static_cast<float>(transformed_point_cloud.size());
  const float angle = transform::GetAngle(transform);
  // 得分乘以权重,权重函数怎么来的,仍未清楚,或许是随意取的
  score *=
      std::exp(-common::Pow2(transform.translation().norm() *
                                 options_.translation_delta_cost_weight() +
                             angle * options_.rotation_delta_cost_weight()));
  CHECK_GT(score, 0.f);
  return score;
}

CeresScanMatcher3D

和2D基本一致,但是多了2个分辨率的地图。

class CeresScanMatcher3D {
 public:
  explicit CeresScanMatcher3D(const proto::CeresScanMatcherOptions3D& options);

  CeresScanMatcher3D(const CeresScanMatcher3D&) = delete;
  CeresScanMatcher3D& operator=(const CeresScanMatcher3D&) = delete;

  // Aligns 'point_clouds' within the 'hybrid_grids' given an
  // 'initial_pose_estimate' and returns a 'pose_estimate' and the solver
  // 'summary'.
  void Match(const Eigen::Vector3d& target_translation,
             const transform::Rigid3d& initial_pose_estimate,
             const std::vector<PointCloudAndHybridGridPointers>&
                 point_clouds_and_hybrid_grids,
             transform::Rigid3d* pose_estimate,
             ceres::Solver::Summary* summary);

 private:
  const proto::CeresScanMatcherOptions3D options_;
  ceres::Solver::Options ceres_solver_options_;
};

void CeresScanMatcher3D::Match(
    const Eigen::Vector3d& target_translation,
    const transform::Rigid3d& initial_pose_estimate,
    const std::vector<PointCloudAndHybridGridPointers>&
        point_clouds_and_hybrid_grids,
    transform::Rigid3d* const pose_estimate,
    ceres::Solver::Summary* const summary) {
  ceres::Problem problem;
  optimization::CeresPose ceres_pose(
      initial_pose_estimate, nullptr /* translation_parameterization */,
      options_.only_optimize_yaw()
          // 只优化Yawl角
          ? std::unique_ptr<ceres::LocalParameterization>(
                common::make_unique<ceres::AutoDiffLocalParameterization<
                    YawOnlyQuaternionPlus, 4, 1>>())
          // 优化所有的角度
          : std::unique_ptr<ceres::LocalParameterization>(
                common::make_unique<ceres::QuaternionParameterization>()),
      &problem);

  CHECK_EQ(options_.occupied_space_weight_size(),
           point_clouds_and_hybrid_grids.size());
  // 针对高低分辨率地图,分别添加点的匹配残差
  for (size_t i = 0; i != point_clouds_and_hybrid_grids.size(); ++i) {
    CHECK_GT(options_.occupied_space_weight(i), 0.);
    const sensor::PointCloud& point_cloud =
        *point_clouds_and_hybrid_grids[i].first;
    const HybridGrid& hybrid_grid = *point_clouds_and_hybrid_grids[i].second;
    problem.AddResidualBlock(
        OccupiedSpaceCostFunction3D::CreateAutoDiffCostFunction(
            // 高低分辨率地图的匹配权重来自设置参数,并且同一分辨率地图的每个点的权重一样,因为残差是平方的,所以要开根号呀
            options_.occupied_space_weight(i) /
                std::sqrt(static_cast<double>(point_cloud.size())),
            point_cloud, hybrid_grid),
        nullptr /* loss function */, ceres_pose.translation(),
        ceres_pose.rotation());
  }
  CHECK_GT(options_.translation_weight(), 0.);
  // 添加平移残差
  problem.AddResidualBlock(
      TranslationDeltaCostFunctor3D::CreateAutoDiffCostFunction(
          options_.translation_weight(), target_translation),
      nullptr /* loss function */, ceres_pose.translation());
  CHECK_GT(options_.rotation_weight(), 0.);
  // 添加旋转残差
  problem.AddResidualBlock(
      RotationDeltaCostFunctor3D::CreateAutoDiffCostFunction(
          options_.rotation_weight(), initial_pose_estimate.rotation()),
      nullptr /* loss function */, ceres_pose.rotation());

  ceres::Solve(ceres_solver_options_, &problem, summary);

  *pose_estimate = ceres_pose.ToRigid();
}

点云残差:

class OccupiedSpaceCostFunction3D {
 public:
  static ceres::CostFunction* CreateAutoDiffCostFunction(
      const double scaling_factor, const sensor::PointCloud& point_cloud,
      const mapping::HybridGrid& hybrid_grid) {
    return new ceres::AutoDiffCostFunction<
        OccupiedSpaceCostFunction3D, ceres::DYNAMIC /* residuals */,
        3 /* translation variables */, 4 /* rotation variables */>(
        new OccupiedSpaceCostFunction3D(scaling_factor, point_cloud,
                                        hybrid_grid),
        point_cloud.size());
  }

  template <typename T>
  bool operator()(const T* const translation, const T* const rotation,
                  T* const residual) const {
    const transform::Rigid3<T> transform(
        Eigen::Map<const Eigen::Matrix<T, 3, 1>>(translation),
        Eigen::Quaternion<T>(rotation[0], rotation[1], rotation[2],
                             rotation[3]));
    return Evaluate(transform, residual);
  }

 private:
  OccupiedSpaceCostFunction3D(const double scaling_factor,
                              const sensor::PointCloud& point_cloud,
                              const mapping::HybridGrid& hybrid_grid)
      : scaling_factor_(scaling_factor),
        point_cloud_(point_cloud),
        // 插值网格的构造
        interpolated_grid_(hybrid_grid) {}

  OccupiedSpaceCostFunction3D(const OccupiedSpaceCostFunction3D&) = delete;
  OccupiedSpaceCostFunction3D& operator=(const OccupiedSpaceCostFunction3D&) =
      delete;

  template <typename T>
  bool Evaluate(const transform::Rigid3<T>& transform,
                T* const residual) const {
    for (size_t i = 0; i < point_cloud_.size(); ++i) {
      // 转到网格坐标系下
      const Eigen::Matrix<T, 3, 1> world =
          transform * point_cloud_[i].cast<T>();
      // 插值得到概率
      const T probability =
          interpolated_grid_.GetProbability(world[0], world[1], world[2]);
      // 构建残差
      residual[i] = scaling_factor_ * (1. - probability);
    }
    return true;
  }

  const double scaling_factor_;
  const sensor::PointCloud& point_cloud_;
  // 用作插值的网格 和 2D有所不同
  const InterpolatedGrid interpolated_grid_;
};


class InterpolatedGrid {
 public:
  // 构造函数中将网格数据传进来
  explicit InterpolatedGrid(const HybridGrid& hybrid_grid)
      : hybrid_grid_(hybrid_grid) {}

  InterpolatedGrid(const InterpolatedGrid&) = delete;
  InterpolatedGrid& operator=(const InterpolatedGrid&) = delete;

  // Returns the interpolated probability at (x, y, z) of the HybridGrid
  // used to perform the interpolation.
  //
  // This is a piecewise, continuously differentiable function. We use the
  // scalar part of Jet parameters to select our interval below. It is the
  // tensor product volume of piecewise cubic polynomials that interpolate
  // the values, and have vanishing derivative at the interval boundaries.
  template <typename T>
  T GetProbability(const T& x, const T& y, const T& z) const {
    double x1, y1, z1, x2, y2, z2;
    ComputeInterpolationDataPoints(x, y, z, &x1, &y1, &z1, &x2, &y2, &z2);
    // 获取低的voxel的index
    const Eigen::Array3i index1 =
        hybrid_grid_.GetCellIndex(Eigen::Vector3f(x1, y1, z1));
    // 获取低的voxel的概率
    const double q111 = hybrid_grid_.GetProbability(index1);
    // 获取其附近8个voxel的概率,该8个voxel肯定包含坐标点xyz
    const double q112 =
        hybrid_grid_.GetProbability(index1 + Eigen::Array3i(0, 0, 1));
    const double q121 =
        hybrid_grid_.GetProbability(index1 + Eigen::Array3i(0, 1, 0));
    const double q122 =
        hybrid_grid_.GetProbability(index1 + Eigen::Array3i(0, 1, 1));
    const double q211 =
        hybrid_grid_.GetProbability(index1 + Eigen::Array3i(1, 0, 0));
    const double q212 =
        hybrid_grid_.GetProbability(index1 + Eigen::Array3i(1, 0, 1));
    const double q221 =
        hybrid_grid_.GetProbability(index1 + Eigen::Array3i(1, 1, 0));
    const double q222 =
        hybrid_grid_.GetProbability(index1 + Eigen::Array3i(1, 1, 1));

    const T normalized_x = (x - x1) / (x2 - x1);
    const T normalized_y = (y - y1) / (y2 - y1);
    const T normalized_z = (z - z1) / (z2 - z1);

    // Compute pow(..., 2) and pow(..., 3). Using pow() here is very expensive.
    const T normalized_xx = normalized_x * normalized_x;
    const T normalized_xxx = normalized_x * normalized_xx;
    const T normalized_yy = normalized_y * normalized_y;
    const T normalized_yyy = normalized_y * normalized_yy;
    const T normalized_zz = normalized_z * normalized_z;
    const T normalized_zzz = normalized_z * normalized_zz;
    // 双三次插值,该公式如下
    // We first interpolate in z, then y, then x. All 7 times this uses the same
    // scheme: A * (2t^3 - 3t^2 + 1) + B * (-2t^3 + 3t^2).
    // The first polynomial is 1 at t=0, 0 at t=1, the second polynomial is 0
    // at t=0, 1 at t=1. Both polynomials have derivative zero at t=0 and t=1.
    const T q11 = (q111 - q112) * normalized_zzz * 2. +
                  (q112 - q111) * normalized_zz * 3. + q111;
    const T q12 = (q121 - q122) * normalized_zzz * 2. +
                  (q122 - q121) * normalized_zz * 3. + q121;
    const T q21 = (q211 - q212) * normalized_zzz * 2. +
                  (q212 - q211) * normalized_zz * 3. + q211;
    const T q22 = (q221 - q222) * normalized_zzz * 2. +
                  (q222 - q221) * normalized_zz * 3. + q221;
    const T q1 = (q11 - q12) * normalized_yyy * 2. +
                 (q12 - q11) * normalized_yy * 3. + q11;
    const T q2 = (q21 - q22) * normalized_yyy * 2. +
                 (q22 - q21) * normalized_yy * 3. + q21;
    return (q1 - q2) * normalized_xxx * 2. + (q2 - q1) * normalized_xx * 3. +
           q1;
  }

 private:
  // 计算相邻的两个voxel的中心点
  template <typename T>
  void ComputeInterpolationDataPoints(const T& x, const T& y, const T& z,
                                      double* x1, double* y1, double* z1,
                                      double* x2, double* y2,
                                      double* z2) const {
    const Eigen::Vector3f lower = CenterOfLowerVoxel(x, y, z);
    *x1 = lower.x();
    *y1 = lower.y();
    *z1 = lower.z();
    *x2 = lower.x() + hybrid_grid_.resolution();
    *y2 = lower.y() + hybrid_grid_.resolution();
    *z2 = lower.z() + hybrid_grid_.resolution();
  }

  // Center of the next lower voxel, i.e., not necessarily the voxel containing
  // (x, y, z). For each dimension, the largest voxel index so that the
  // corresponding center is at most the given coordinate.
  // 计算下一个的voxel的中心点,必须保证center的xyz是小于xyz的
  Eigen::Vector3f CenterOfLowerVoxel(const double x, const double y,
                                     const double z) const {
    // Center of the cell containing (x, y, z).
    Eigen::Vector3f center = hybrid_grid_.GetCenterOfCell(
        hybrid_grid_.GetCellIndex(Eigen::Vector3f(x, y, z)));
    // Move to the next lower voxel center.
    if (center.x() > x) {
      center.x() -= hybrid_grid_.resolution();
    }
    if (center.y() > y) {
      center.y() -= hybrid_grid_.resolution();
    }
    if (center.z() > z) {
      center.z() -= hybrid_grid_.resolution();
    }
    return center;
  }

  // Uses the scalar part of a Ceres Jet.
  template <typename T>
  Eigen::Vector3f CenterOfLowerVoxel(const T& jet_x, const T& jet_y,
                                     const T& jet_z) const {
    return CenterOfLowerVoxel(jet_x.a, jet_y.a, jet_z.a);
  }

  const HybridGrid& hybrid_grid_;
};

3D平移残差:

class TranslationDeltaCostFunctor3D {
 public:
  static ceres::CostFunction* CreateAutoDiffCostFunction(
      const double scaling_factor, const Eigen::Vector3d& target_translation) {
    return new ceres::AutoDiffCostFunction<TranslationDeltaCostFunctor3D,
                                           3 /* residuals */,
                                           3 /* translation variables */>(
        new TranslationDeltaCostFunctor3D(scaling_factor, target_translation));
  }
  // 平移直接作差
  template <typename T>
  bool operator()(const T* const translation, T* residual) const {
    residual[0] = scaling_factor_ * (translation[0] - x_);
    residual[1] = scaling_factor_ * (translation[1] - y_);
    residual[2] = scaling_factor_ * (translation[2] - z_);
    return true;
  }

 private:
  // Constructs a new TranslationDeltaCostFunctor3D from the given
  // 'target_translation'.
  explicit TranslationDeltaCostFunctor3D(
      const double scaling_factor, const Eigen::Vector3d& target_translation)
      : scaling_factor_(scaling_factor),
        x_(target_translation.x()),
        y_(target_translation.y()),
        z_(target_translation.z()) {}

  TranslationDeltaCostFunctor3D(const TranslationDeltaCostFunctor3D&) = delete;
  TranslationDeltaCostFunctor3D& operator=(
      const TranslationDeltaCostFunctor3D&) = delete;

  const double scaling_factor_;
  const double x_;
  const double y_;
  const double z_;
};

3D旋转残差:

class RotationDeltaCostFunctor3D {
 public:
  static ceres::CostFunction* CreateAutoDiffCostFunction(
      const double scaling_factor, const Eigen::Quaterniond& target_rotation) {
    return new ceres::AutoDiffCostFunction<RotationDeltaCostFunctor3D,
                                           3 /* residuals */,
                                           4 /* rotation variables */>(
        new RotationDeltaCostFunctor3D(scaling_factor, target_rotation));
  }
  // 旋转得到三个角,并作差
  template <typename T>
  bool operator()(const T* const rotation_quaternion, T* residual) const {
    std::array<T, 4> delta;
    common::QuaternionProduct(target_rotation_inverse_, rotation_quaternion,
                              delta.data());
    // Will compute the squared norm of the imaginary component of the delta
    // quaternion which is sin(phi/2)^2.
    residual[0] = scaling_factor_ * delta[1];
    residual[1] = scaling_factor_ * delta[2];
    residual[2] = scaling_factor_ * delta[3];
    return true;
  }

 private:
  // Constructs a new RotationDeltaCostFunctor3D from the given
  // 'target_rotation'.
  explicit RotationDeltaCostFunctor3D(const double scaling_factor,
                                      const Eigen::Quaterniond& target_rotation)
      : scaling_factor_(scaling_factor) {
    // 四元数共轭即为逆(四元数模长为1)
    target_rotation_inverse_[0] = target_rotation.w();
    target_rotation_inverse_[1] = -target_rotation.x();
    target_rotation_inverse_[2] = -target_rotation.y();
    target_rotation_inverse_[3] = -target_rotation.z();
  }

  RotationDeltaCostFunctor3D(const RotationDeltaCostFunctor3D&) = delete;
  RotationDeltaCostFunctor3D& operator=(const RotationDeltaCostFunctor3D&) =
      delete;

  const double scaling_factor_;
  double target_rotation_inverse_[4];
};
// 四元数相乘
template <typename T>
inline void QuaternionProduct(const double* const z, const T* const w,
                              T* const zw) {
  zw[0] = z[0] * w[0] - z[1] * w[1] - z[2] * w[2] - z[3] * w[3];
  zw[1] = z[0] * w[1] + z[1] * w[0] + z[2] * w[3] - z[3] * w[2];
  zw[2] = z[0] * w[2] - z[1] * w[3] + z[2] * w[0] + z[3] * w[1];
  zw[3] = z[0] * w[3] + z[1] * w[2] - z[2] * w[1] + z[3] * w[0];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值