ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

PCL - ICP代碼研讀(二 ) - Registration架構

2021-10-02 23:33:11  阅读:615  来源: 互联网

标签:target epsilon 架構 brief PCL 代碼 threshold transformation cloud


PCL - ICP代碼研讀(二 ) - Registration架構

前言

PCL庫中,所有校正算法都繼承自Registration這個類別。本篇便是介紹此類別的主要架構。

using

/** \brief @b Registration represents the base registration class for general purpose,
 * ICP-like methods. \author Radu B. Rusu, Michael Dixon \ingroup registration
 */
template <typename PointSource, typename PointTarget, typename Scalar = float>
class Registration : public PCLBase<PointSource> {
public:

定義Matrix4為4*4矩陣,ICP算法中用到的轉換矩陣就屬於這個型別:

  using Matrix4 = Eigen::Matrix<Scalar, 4, 4>;

因為PCLBase已經定義了deinitCompute,input_,indices_,這裡用了using表示沿用PCLBase中的定義。

參考改變成員的訪問權限,此處using的另外一個作用為:將原來是PCLBaseprotected成員的導入Registrationpublic權限區塊。

  //Registration有自己定義的initCompute
  // using PCLBase<PointSource>::initCompute;
  using PCLBase<PointSource>::deinitCompute;
  using PCLBase<PointSource>::input_;
  using PCLBase<PointSource>::indices_;

其餘皆是用using來定義名稱,方便後續使用。

  using Ptr = shared_ptr<Registration<PointSource, PointTarget, Scalar>>;
  using ConstPtr = shared_ptr<const Registration<PointSource, PointTarget, Scalar>>;

  using CorrespondenceRejectorPtr = pcl::registration::CorrespondenceRejector::Ptr;
  using KdTree = pcl::search::KdTree<PointTarget>;
  using KdTreePtr = typename KdTree::Ptr;

  using KdTreeReciprocal = pcl::search::KdTree<PointSource>;
  using KdTreeReciprocalPtr = typename KdTreeReciprocal::Ptr;

  using PointCloudSource = pcl::PointCloud<PointSource>;
  using PointCloudSourcePtr = typename PointCloudSource::Ptr;
  using PointCloudSourceConstPtr = typename PointCloudSource::ConstPtr;

  using PointCloudTarget = pcl::PointCloud<PointTarget>;
  using PointCloudTargetPtr = typename PointCloudTarget::Ptr;
  using PointCloudTargetConstPtr = typename PointCloudTarget::ConstPtr;

  //?
  using PointRepresentationConstPtr = typename KdTree::PointRepresentationConstPtr;

  using TransformationEstimation = typename pcl::registration::
      TransformationEstimation<PointSource, PointTarget, Scalar>;
  using TransformationEstimationPtr = typename TransformationEstimation::Ptr;
  using TransformationEstimationConstPtr = typename TransformationEstimation::ConstPtr;

  using CorrespondenceEstimation =
      pcl::registration::CorrespondenceEstimationBase<PointSource, PointTarget, Scalar>;
  using CorrespondenceEstimationPtr = typename CorrespondenceEstimation::Ptr;
  using CorrespondenceEstimationConstPtr = typename CorrespondenceEstimation::ConstPtr;

  /** \brief The callback signature to the function updating intermediate source point
   * cloud position during it's registration to the target point cloud. \param[in]
   * cloud_src - the point cloud which will be updated to match target \param[in]
   * indices_src - a selector of points in cloud_src \param[in] cloud_tgt - the point
   * cloud we want to register against \param[in] indices_tgt - a selector of points in
   * cloud_tgt
   */
  using UpdateVisualizerCallbackSignature = void(const pcl::PointCloud<PointSource>&,
                                                 const pcl::Indices&,
                                                 const pcl::PointCloud<PointTarget>&,
                                                 const pcl::Indices&);

public函數

constructor和destructor

  /** \brief Empty constructor. */
  Registration()
  : tree_(new KdTree)
  , tree_reciprocal_(new KdTreeReciprocal)
  , nr_iterations_(0)
  , max_iterations_(10)
  , ransac_iterations_(0)
  , target_()
  , final_transformation_(Matrix4::Identity())
  , transformation_(Matrix4::Identity())
  , previous_transformation_(Matrix4::Identity())
  , transformation_epsilon_(0.0)
  , transformation_rotation_epsilon_(0.0)
  //兩次迭代中平均(歐式)距離小於euclidean_fitness_epsilon_才會被認為收斂
  , euclidean_fitness_epsilon_(-std::numeric_limits<double>::max())
  // 原始點雲中和目標點雲中的點的距離要小於corr_dist_threshold_才會被當成配對點
  // 在determineCorrespondences.h中會先將max_distance做平方再與kdtree得到的距離做比較,
  // 所以這裡才會加sqrt
  , corr_dist_threshold_(std::sqrt(std::numeric_limits<double>::max()))
  , inlier_threshold_(0.05)
  , converged_(false)
  , min_number_correspondences_(3)
  , correspondences_(new Correspondences)
  , transformation_estimation_()
  , correspondence_estimation_()
  , target_cloud_updated_(true)
  , source_cloud_updated_(true)
  , force_no_recompute_(false)
  , force_no_recompute_reciprocal_(false)
  , point_representation_()
  {}

  /** \brief destructor. */
  ~Registration() {}

setter和getter

以下這些函數用於對成員變數進行存取或賦值。

  /** \brief Provide a pointer to the transformation estimation object.
   * (e.g., SVD, point to plane etc.)
   *
   * \param[in] te is the pointer to the corresponding transformation estimation object
   *
   * Code example:
   *
   * \code
   * TransformationEstimationPointToPlaneLLS<PointXYZ, PointXYZ>::Ptr trans_lls
   *   (new TransformationEstimationPointToPlaneLLS<PointXYZ, PointXYZ>);
   * icp.setTransformationEstimation (trans_lls);
   * // or...
   * TransformationEstimationSVD<PointXYZ, PointXYZ>::Ptr trans_svd
   *   (new TransformationEstimationSVD<PointXYZ, PointXYZ>);
   * icp.setTransformationEstimation (trans_svd);
   * \endcode
   */
  void
  setTransformationEstimation(const TransformationEstimationPtr& te)
  {
    transformation_estimation_ = te;
  }

  /** \brief Provide a pointer to the correspondence estimation object.
   * (e.g., regular, reciprocal, normal shooting etc.)
   *
   * \param[in] ce is the pointer to the corresponding correspondence estimation object
   *
   * Code example:
   *
   * \code
   * CorrespondenceEstimation<PointXYZ, PointXYZ>::Ptr
   *   ce (new CorrespondenceEstimation<PointXYZ, PointXYZ>);
   * ce->setInputSource (source);
   * ce->setInputTarget (target);
   * icp.setCorrespondenceEstimation (ce);
   * // or...
   * CorrespondenceEstimationNormalShooting<PointNormal, PointNormal, PointNormal>::Ptr
   *   cens (new CorrespondenceEstimationNormalShooting<PointNormal, PointNormal>);
   * ce->setInputSource (source);
   * ce->setInputTarget (target);
   * ce->setSourceNormals (source);
   * ce->setTargetNormals (target);
   * icp.setCorrespondenceEstimation (cens);
   * \endcode
   */
  void
  setCorrespondenceEstimation(const CorrespondenceEstimationPtr& ce)
  {
    correspondence_estimation_ = ce;
  }

  /** \brief Provide a pointer to the input source
   * (e.g., the point cloud that we want to align to the target)
   *
   * \param[in] cloud the input point cloud source
   */
  virtual void
  setInputSource(const PointCloudSourceConstPtr& cloud);

  /** \brief Get a pointer to the input point cloud dataset target. */
  inline PointCloudSourceConstPtr const
  getInputSource()
  {
    return (input_);
  }

  /** \brief Provide a pointer to the input target (e.g., the point cloud that we want
   * to align the input source to) \param[in] cloud the input point cloud target
   */
  virtual inline void
  setInputTarget(const PointCloudTargetConstPtr& cloud);

  /** \brief Get a pointer to the input point cloud dataset target. */
  inline PointCloudTargetConstPtr const
  getInputTarget()
  {
    return (target_);
  }

  /** \brief Provide a pointer to the search object used to find correspondences in
   * the target cloud.
   * \param[in] tree a pointer to the spatial search object.
   * \param[in] force_no_recompute If set to true, this tree will NEVER be
   * recomputed, regardless of calls to setInputTarget. Only use if you are
   * confident that the tree will be set correctly.
   */
  // force_no_recompute_是指用於在target點雲裡搜索的tree_不會再被更新
  inline void
  setSearchMethodTarget(const KdTreePtr& tree, bool force_no_recompute = false)
  {
    tree_ = tree;
    force_no_recompute_ = force_no_recompute;
    // Since we just set a new tree, we need to check for updates
    // 代表在initCompute函數中需要重新計算tree_
    target_cloud_updated_ = true;
  }

  /** \brief Get a pointer to the search method used to find correspondences in the
   * target cloud. */
  inline KdTreePtr
  getSearchMethodTarget() const
  {
    return (tree_);
  }

  /** \brief Provide a pointer to the search object used to find correspondences in
   * the source cloud (usually used by reciprocal correspondence finding).
   * \param[in] tree a pointer to the spatial search object.
   * \param[in] force_no_recompute If set to true, this tree will NEVER be
   * recomputed, regardless of calls to setInputSource. Only use if you are
   * extremely confident that the tree will be set correctly.
   */
  // force_no_recompute_reciprocal_是指用於在source點雲裡搜索的tree_reciprocal_不會再被更新
  inline void
  setSearchMethodSource(const KdTreeReciprocalPtr& tree,
                        bool force_no_recompute = false)
  {
    tree_reciprocal_ = tree;
    force_no_recompute_reciprocal_ = force_no_recompute;
    // Since we just set a new tree, we need to check for updates
    source_cloud_updated_ = true;
  }

  /** \brief Get a pointer to the search method used to find correspondences in the
   * source cloud. */
  inline KdTreeReciprocalPtr
  getSearchMethodSource() const
  {
    return (tree_reciprocal_);
  }

  /** \brief Get the final transformation matrix estimated by the registration method.
   */
  inline Matrix4
  getFinalTransformation()
  {
    return (final_transformation_);
  }

  /** \brief Get the last incremental transformation matrix estimated by the
   * registration method. */
  // 注意transformation_指的是每次迭代算出來的更新量(增量)
  inline Matrix4
  getLastIncrementalTransformation()
  {
    return (transformation_);
  }

  /** \brief Set the maximum number of iterations the internal optimization should run
   * for. \param[in] nr_iterations the maximum number of iterations the internal
   * optimization should run for
   */
  inline void
  setMaximumIterations(int nr_iterations)
  {
    max_iterations_ = nr_iterations;
  }

  /** \brief Get the maximum number of iterations the internal optimization should run
   * for, as set by the user. */
  inline int
  getMaximumIterations()
  {
    return (max_iterations_);
  }

  /** \brief Set the number of iterations RANSAC should run for.
   * \param[in] ransac_iterations is the number of iterations RANSAC should run for
   */
  // 這個函數應該很有用
  inline void
  setRANSACIterations(int ransac_iterations)
  {
    ransac_iterations_ = ransac_iterations;
  }

  /** \brief Get the number of iterations RANSAC should run for, as set by the user. */
  inline double
  getRANSACIterations()
  {
    return (ransac_iterations_);
  }

  /** \brief Set the inlier distance threshold for the internal RANSAC outlier rejection
   * loop.
   *
   * The method considers a point to be an inlier, if the distance between the target
   * data index and the transformed source index is smaller than the given inlier
   * distance threshold. The value is set by default to 0.05m. \param[in]
   * inlier_threshold the inlier distance threshold for the internal RANSAC outlier
   * rejection loop
   */
  // 距離小於等於inlier_threshold的點對才會被當成是RANSAC的inlier
  inline void
  setRANSACOutlierRejectionThreshold(double inlier_threshold)
  {
    inlier_threshold_ = inlier_threshold;
  }

  /** \brief Get the inlier distance threshold for the internal outlier rejection loop
   * as set by the user. */
  inline double
  getRANSACOutlierRejectionThreshold()
  {
    return (inlier_threshold_);
  }

  /** \brief Set the maximum distance threshold between two correspondent points in
   * source <-> target. If the distance is larger than this threshold, the points will
   * be ignored in the alignment process. \param[in] distance_threshold the maximum
   * distance threshold between a point and its nearest neighbor correspondent in order
   * to be considered in the alignment process
   */
  // 原始點雲中和目標點雲中的點的距離要小於corr_dist_threshold_才會被當成配對點
  inline void
  setMaxCorrespondenceDistance(double distance_threshold)
  {
    corr_dist_threshold_ = distance_threshold;
  }

  /** \brief Get the maximum distance threshold between two correspondent points in
   * source <-> target. If the distance is larger than this threshold, the points will
   * be ignored in the alignment process.
   */
  inline double
  getMaxCorrespondenceDistance()
  {
    return (corr_dist_threshold_);
  }

  /** \brief Set the transformation epsilon (maximum allowable translation squared
   * difference between two consecutive transformations) in order for an optimization to
   * be considered as having converged to the final solution. \param[in] epsilon the
   * transformation epsilon in order for an optimization to be considered as having
   * converged to the final solution.
   */
  //?
  // "平移"(看注釋是這樣說的)程度(距離平方)要小於transformation_epsilon_算法才會被認為收斂
  inline void
  setTransformationEpsilon(double epsilon)
  {
    transformation_epsilon_ = epsilon;
  }

  /** \brief Get the transformation epsilon (maximum allowable translation squared
   * difference between two consecutive transformations) as set by the user.
   */
  inline double
  getTransformationEpsilon()
  {
    return (transformation_epsilon_);
  }

  /** \brief Set the transformation rotation epsilon (maximum allowable rotation
   * difference between two consecutive transformations) in order for an optimization to
   * be considered as having converged to the final solution. \param[in] epsilon the
   * transformation rotation epsilon in order for an optimization to be considered as
   * having converged to the final solution (epsilon is the cos(angle) in a axis-angle
   * representation).
   */
  // 旋轉程度(角軸法cos(angle))要小於transformation_rotation_epsilon_算法才會被認為收斂
  inline void
  setTransformationRotationEpsilon(double epsilon)
  {
    transformation_rotation_epsilon_ = epsilon;
  }

  /** \brief Get the transformation rotation epsilon (maximum allowable difference
   * between two consecutive transformations) as set by the user (epsilon is the
   * cos(angle) in a axis-angle representation).
   */
  inline double
  getTransformationRotationEpsilon()
  {
    return (transformation_rotation_epsilon_);
  }

  /** \brief Set the maximum allowed Euclidean error between two consecutive steps in
   * the ICP loop, before the algorithm is considered to have converged. The error is
   * estimated as the sum of the differences between correspondences in an Euclidean
   * sense, divided by the number of correspondences. \param[in] epsilon the maximum
   * allowed distance error before the algorithm will be considered to have converged
   */
  // 兩次迭代中平均(歐式)距離小於euclidean_fitness_epsilon_才會被認為收斂
  // 它的用法是convergence_criteria_->setRelativeMSE(euclidean_fitness_epsilon_);?
  inline void
  setEuclideanFitnessEpsilon(double epsilon)
  {
    euclidean_fitness_epsilon_ = epsilon;
  }

  /** \brief Get the maximum allowed distance error before the algorithm will be
   * considered to have converged, as set by the user. See \ref
   * setEuclideanFitnessEpsilon
   */
  inline double
  getEuclideanFitnessEpsilon()
  {
    return (euclidean_fitness_epsilon_);
  }

  /** \brief Provide a boost shared pointer to the PointRepresentation to be used when
   * comparing points \param[in] point_representation the PointRepresentation to be used
   * by the k-D tree
   */
  // ?
  inline void
  setPointRepresentation(const PointRepresentationConstPtr& point_representation)
  {
    point_representation_ = point_representation;
  }

registerVisualizationCallback

用於可視化的函數,尚未深入研究。

  /** \brief Register the user callback function which will be called from registration
   * thread in order to update point cloud obtained after each iteration \param[in]
   * visualizerCallback reference of the user callback function
   */
  inline bool
  registerVisualizationCallback(
      std::function<UpdateVisualizerCallbackSignature>& visualizerCallback)
  {
    if (visualizerCallback) {
      update_visualizer_ = visualizerCallback;
      return (true);
    }
    return (false);
  }

getFitnessScore

用於計算兩個向量或點雲間的mse(mean squared error)。

  /** \brief Obtain the Euclidean fitness score (e.g., mean of squared distances from
   * the source to the target) \param[in] max_range maximum allowable distance between a
   * point and its correspondence in the target (default: double::max)
   */
  // mean square error,注意不是rmse
  inline double
  getFitnessScore(double max_range = std::numeric_limits<double>::max());

  /** \brief Obtain the Euclidean fitness score (e.g., mean of squared distances from
   * the source to the target) from two sets of correspondence distances (distances
   * between source and target points) \param[in] distances_a the first set of distances
   * between correspondences \param[in] distances_b the second set of distances between
   * correspondences
   */
  // 計算兩個向量的mse?
  inline double
  getFitnessScore(const std::vector<float>& distances_a,
                  const std::vector<float>& distances_b);

hasConverged

回傳converged_成員變數,表示校正算法是否收斂。

  /** \brief Return the state of convergence after the last align run */
  inline bool
  hasConverged() const
  {
    return (converged_);
  }

align

align函數用於估計兩點雲間的轉矩矩陣(final_transformation_),並同時對輸入點雲input_做轉換,將結果儲存至output這個點雲中。

  /** \brief Call the registration algorithm which estimates the transformation and
   * returns the transformed source (input) as \a output. \param[out] output the
   * resultant input transformed point cloud dataset
   */
  // 注意傳入的點雲ouput會被修改對齊
  inline void
  align(PointCloudSource& output);

  /** \brief Call the registration algorithm which estimates the transformation and
   * returns the transformed source (input) as \a output. \param[out] output the
   * resultant input transformed point cloud dataset \param[in] guess the initial gross
   * estimation of the transformation
   */
  inline void
  align(PointCloudSource& output, const Matrix4& guess);

getClassName

protected成員變數reg_name_的getter。

  /** \brief Abstract class get name method. */
  inline const std::string&
  getClassName() const
  {
    return (reg_name_);
  }

initCompute和initComputeReciprocal

initCompute用於更新tree_target_cloud_updated_correspondence_estimation_

initComputeReciprocal是source版本的initCompute,用於更新tree_reciprocal_source_cloud_updated_

  /** \brief Internal computation initialization. */
  bool
  initCompute();

  /** \brief Internal computation when reciprocal lookup is needed */
  bool
  initComputeReciprocal();

CorrespondenceRejector相關函數

以下幾個函數用於管理std::vector<CorrespondenceRejectorPtr>型別的成員函數correspondence_rejectors_

getCorrespondenceRejectorscorrespondence_rejectors_的getter。

addCorrespondenceRejectorremoveCorrespondenceRejectorclearCorrespondenceRejectors分別用於新增,刪除和清空。

  /** \brief Add a new correspondence rejector to the list
   * \param[in] rejector the new correspondence rejector to concatenate
   *
   * Code example:
   *
   * \code
   * CorrespondenceRejectorDistance rej;
   * rej.setInputCloud<PointXYZ> (keypoints_src);
   * rej.setInputTarget<PointXYZ> (keypoints_tgt);
   * rej.setMaximumDistance (1);
   * rej.setInputCorrespondences (all_correspondences);
   *
   * // or...
   *
   * \endcode
   */
  inline void
  addCorrespondenceRejector(const CorrespondenceRejectorPtr& rejector)
  {
    correspondence_rejectors_.push_back(rejector);
  }

  /** \brief Get the list of correspondence rejectors. */
  inline std::vector<CorrespondenceRejectorPtr>
  getCorrespondenceRejectors()
  {
    return (correspondence_rejectors_);
  }

  /** \brief Remove the i-th correspondence rejector in the list
   * \param[in] i the position of the correspondence rejector in the list to remove
   */
  inline bool
  removeCorrespondenceRejector(unsigned int i)
  {
    if (i >= correspondence_rejectors_.size())
      return (false);
    correspondence_rejectors_.erase(correspondence_rejectors_.begin() + i);
    return (true);
  }

  /** \brief Clear the list of correspondence rejectors. */
  inline void
  clearCorrespondenceRejectors()
  {
    correspondence_rejectors_.clear();
  }

protected成員變數

ICP算法三步驟類似,這裡的成員變數依功能一樣可以分為三大類(和其他)。

配對相關:

  • corr_dist_threshold_:原始點雲中和目標點雲中的點距離要小於這個數值才會被當成配對點

  • inlier_threshold_:在做校正算法前可以選擇先做RANSAC來大致估計兩點雲的轉換矩陣。距離小於inlier_threshold_的配對才會被RANSAC認為是inlier。(ICP算法沒有用到)

  • min_number_correspondences_:需要最少min_number_correspondences_組配對才能開始估計轉換矩陣,預設值為3

  • correspondences_:ICP算法第一步驟所估計出來,兩點雲間的配對

  • correspondence_estimation_:用於估計兩點雲間的配對,是一個CorrespondenceEstimationPtr類型的指標

  • correspondence_rejectors_:多個用於拒絕配對的rejector所組成的向量

轉換矩陣估計相關:

  • final_transformation_:校正算法估計出來最終的轉換矩陣
  • transformation_:ICP算法會進行多次迭代,transformation_代表該次迭代所估計出來的轉換矩陣
  • previous_transformation_:前次迭代所估計出來的轉換矩陣
  • transformation_estimation_:用於估計兩點雲間的轉換矩陣,是一個TransformationEstimationPtr類型的指標

收斂判斷相關:

  • transformation_epsilon_:對應到default_convergence_criteria.h中的translation_threshold_。如果連續幾次迭代的平移幅度皆小於這個值,便認為算法收斂
  • transformation_rotation_epsilon_:對應到default_convergence_criteria.h中的rotation_threshold_。如果連續幾次迭代的旋轉幅度皆小於這個值,便認為算法收斂
  • euclidean_fitness_epsilon_:對應到default_convergence_criteria.h中的mse_threshold_relative_。如果連續幾次迭代當次mse與前次mse差值與前次mse的比值皆小於這個值,便認為算法收斂
  • converged_:記錄校正算法收斂與否

用於最近鄰搜索:

  • tree_:用於在target點雲中進行搜索
  • tree_reciprocal_:用於在source點雲中進行搜索
  • target_cloud_updated_:如果設為true,表示target_點雲有被更新,等會必須更新target點雲的kdtree
  • source_cloud_updated_:如果設為true,表示input_點雲有被更新,等會必須更新source點雲的kdtree
  • force_no_recompute_:如果設為true,表示不論target_點雲是否被更新,都不更新target點雲的kdtree
  • force_no_recompute_reciprocal_:如果設為true,表示不論input_點雲是否被更新,都不更新source點雲的kdtree

迭代次數:

  • nr_iterations_:目前跑了幾次迭代
  • max_iterations_:人為設置的最大迭代次數
  • ransac_iterations_:要跑幾次RANSAC(ICP算法沒有用到)

其他:

  • target_:目標點雲

  • reg_name_:校正算法的名稱

  • update_visualizer_:用於可視化

  /** \brief The registration method name. */
  std::string reg_name_;

  /** \brief A pointer to the spatial search object. */
  KdTreePtr tree_;

  /** \brief A pointer to the spatial search object of the source. */
  KdTreeReciprocalPtr tree_reciprocal_;

  /** \brief The number of iterations the internal optimization ran for (used
   * internally). */
  // 目前跑了幾次迭代
  int nr_iterations_;

  /** \brief The maximum number of iterations the internal optimization should run for.
   * The default value is 10.
   */
  int max_iterations_;

  /** \brief The number of iterations RANSAC should run for. */
  // 要跑幾次RANSAC
  int ransac_iterations_;

  /** \brief The input point cloud dataset target. */
  PointCloudTargetConstPtr target_;

  /** \brief The final transformation matrix estimated by the registration method after
   * N iterations. */
  Matrix4 final_transformation_;

  /** \brief The transformation matrix estimated by the registration method. */
  // 該次迭代算出來的轉換矩陣
  Matrix4 transformation_;

  /** \brief The previous transformation matrix estimated by the registration method
   * (used internally). */
  // 前次迭代算出來的轉換矩陣
  Matrix4 previous_transformation_;

  /** \brief The maximum difference between two consecutive transformations in order to
   * consider convergence (user defined).
   */
  // 兩次迭代間的轉換程度要小於這個值才會被認為是收斂
  double transformation_epsilon_;

  /** \brief The maximum rotation difference between two consecutive transformations in
   * order to consider convergence (user defined).
   */
  // 兩次迭代間的旋轉程度要小於這個值才會被認為是收斂
  double transformation_rotation_epsilon_;

  /** \brief The maximum allowed Euclidean error between two consecutive steps in the
   * ICP loop, before the algorithm is considered to have converged. The error is
   * estimated as the sum of the differences between correspondences in an Euclidean
   * sense, divided by the number of correspondences.
   */
  // 注釋說是平均距離?, 但是它的用法卻是convergence_criteria_->setRelativeMSE(euclidean_fitness_epsilon_)?
  double euclidean_fitness_epsilon_;

  /** \brief The maximum distance threshold between two correspondent points in source
   * <-> target. If the distance is larger than this threshold, the points will be
   * ignored in the alignment process.
   */
  // 兩個點雲間的兩點,距離要小於corr_dist_threshold_,才會被認為是一組配對
  double corr_dist_threshold_;

  /** \brief The inlier distance threshold for the internal RANSAC outlier rejection
   * loop. The method considers a point to be an inlier, if the distance between the
   * target data index and the transformed source index is smaller than the given inlier
   * distance threshold. The default value is 0.05.
   */
  // 距離小於inlier_threshold_才會被RANSAC認為是inlier
  double inlier_threshold_;

  /** \brief Holds internal convergence state, given user parameters. */
  bool converged_;

  /** \brief The minimum number of correspondences that the algorithm needs before
   * attempting to estimate the transformation. The default value is 3.
   */
  // 需要最少min_number_correspondences_組配對才能開始估計轉換矩陣,預設值為3
  int min_number_correspondences_;

  /** \brief The set of correspondences determined at this ICP step. */
  CorrespondencesPtr correspondences_;

  /** \brief A TransformationEstimation object, used to calculate the 4x4 rigid
   * transformation. */
  // 用於計算轉換矩陣
  TransformationEstimationPtr transformation_estimation_;

  /** \brief A CorrespondenceEstimation object, used to estimate correspondences between
   * the source and the target cloud. */
  CorrespondenceEstimationPtr correspondence_estimation_;

  /** \brief The list of correspondence rejectors to use. */
  std::vector<CorrespondenceRejectorPtr> correspondence_rejectors_;

  /** \brief Variable that stores whether we have a new target cloud, meaning we need to
   * pre-process it again. This way, we avoid rebuilding the kd-tree for the target
   * cloud every time the determineCorrespondences () method is called. */
  // 用於決定是否要更新target cloud的kdtree
  bool target_cloud_updated_;
  /** \brief Variable that stores whether we have a new source cloud, meaning we need to
   * pre-process it again. This way, we avoid rebuilding the reciprocal kd-tree for the
   * source cloud every time the determineCorrespondences () method is called. */
  // 用於決定是否要更新source cloud的kdtree
  bool source_cloud_updated_;
  /** \brief A flag which, if set, means the tree operating on the target cloud
   * will never be recomputed*/
  // 如果設為true,目標點雲的kdtree就不會重算
  bool force_no_recompute_;

  /** \brief A flag which, if set, means the tree operating on the source cloud
   * will never be recomputed*/
  // 如果設為true,source點雲的kdtree就不會重算
  bool force_no_recompute_reciprocal_;

  /** \brief Callback function to update intermediate source point cloud position during
   * it's registration to the target point cloud.
   */
  std::function<UpdateVisualizerCallbackSignature> update_visualizer_;

protected成員函數

searchForNeighbors

pcl::search::KdTree::nearestKSearch的wrapper,固定只查找一個最近鄰。

  /** \brief Search for the closest nearest neighbor of a given point.
   * \param cloud the point cloud dataset to use for nearest neighbor search
   * \param index the index of the query point
   * \param indices the resultant vector of indices representing the k-nearest neighbors
   * \param distances the resultant distances from the query point to the k-nearest
   * neighbors
   */
  // KdTree::nearestKSearch的wrapper,返回true或false
  inline bool
  searchForNeighbors(const PointCloudSource& cloud,
                     int index,
                     pcl::Indices& indices,
                     std::vector<float>& distances)
  {
    int k = tree_->nearestKSearch(cloud, index, 1, indices, distances);
    if (k == 0)
      return (false);
    return (true);
  }

computeTransformation

computeTransformation是一個純虛擬函數(子類別必須實作此函數),用於計算final_transformation_並更新output

  /** \brief Abstract transformation computation method with initial guess */
  virtual void
  computeTransformation(PointCloudSource& output, const Matrix4& guess) = 0;

private

point_representation_

目前與point_representation_相關的代碼還沒看明白。

  /** \brief The point representation used (internal). */
  // ?
  PointRepresentationConstPtr point_representation_;

setInputCloud

這個函數似乎是個deprecated的函數,已經不被建議只用。

  /**
   * \brief Remove from public API in favor of \ref setInputSource
   *
   * Still gives the correct result (with a warning)
   */
  void
  setInputCloud(const PointCloudSourceConstPtr& cloud) override
  {
    PCL_WARN("[pcl::registration::Registration] setInputCloud is deprecated."
             "Please use setInputSource instead.\n");
    setInputSource(cloud);
  }

标签:target,epsilon,架構,brief,PCL,代碼,threshold,transformation,cloud
来源: https://blog.csdn.net/keineahnung2345/article/details/120590438

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有