1. 程式人生 > >[PCL]5 ICP演算法進行點雲匹配

[PCL]5 ICP演算法進行點雲匹配

但是將對應點剔除這塊和ICP演算法的關係還是沒有理解。

RANSAC演算法可以實現點雲剔除,但是ICP演算法通過穩健性的演算法實現匹配,似乎不進行對應點剔除。是不是把全域性的點雲匹配方法和區域性點雲匹配方法搞混了?

ICP演算法可以通過三種方式處理噪聲、部分重疊的問題:剔除、權重、Trimmed方法和穩健估計方法。下面分析一下PCL中關於ICP演算法的實現。

首先是IterativeClosestPoint模板類繼承自Registration模板類。

檢視icp.h中的定義:

template <typename PointSource, typename PointTarget, typename Scalar = float
> class IterativeClosestPoint : public Registration<PointSource, PointTarget, Scalar>

檢視registration.h中的定義:

 template <typename PointSource, typename PointTarget, typename Scalar = float>
  class Registration : public PCLBase<PointSource>

同樣的IterativeClosestPointNonLinear 繼承自IterativeClosestPoint,檢視icp_nl.h

  template <typename PointSource, typename PointTarget, typename Scalar = float> class IterativeClosestPointNonLinear : public IterativeClosestPoint<PointSource, PointTarget, Scalar> 

下面重點說明IterativeClosestPoint模板類。匹配的關鍵方法Align在Registration中實現。

 1 template <typename PointSource, typename PointTarget, typename Scalar> inline void
2 pcl::Registration<PointSource, PointTarget, Scalar>::align (PointCloudSource &output, const Matrix4& guess) 3 { 4 if (!initCompute ()) 5 return; 6 7 // Resize the output dataset 8 if (output.points.size () != indices_->size ()) 9 output.points.resize (indices_->size ()); 10 // Copy the header 11 output.header = input_->header; 12 // Check if the output will be computed for all points or only a subset 13 if (indices_->size () != input_->points.size ()) 14 { 15 output.width = static_cast<uint32_t> (indices_->size ()); 16 output.height = 1; 17 } 18 else 19 { 20 output.width = static_cast<uint32_t> (input_->width); 21 output.height = input_->height; 22 } 23 output.is_dense = input_->is_dense; 24 25 // Copy the point data to output 26 for (size_t i = 0; i < indices_->size (); ++i) 27 output.points[i] = input_->points[(*indices_)[i]]; 28 29 // Set the internal point representation of choice unless otherwise noted 30 if (point_representation_ && !force_no_recompute_) 31 tree_->setPointRepresentation (point_representation_); 32 33 // Perform the actual transformation computation 34 converged_ = false; 35 final_transformation_ = transformation_ = previous_transformation_ = Matrix4::Identity (); 36 37 // Right before we estimate the transformation, we set all the point.data[3] values to 1 to aid the rigid 38 // transformation 39 for (size_t i = 0; i < indices_->size (); ++i) 40 output.points[i].data[3] = 1.0; 41 42 computeTransformation (output, guess); 43 44 deinitCompute (); 45 }

重點關注computeTransformation虛方法。顯然IterativeClosestPoint過載了基類這個方法。

 virtual void computeTransformation (PointCloudSource &output, const Matrix4& guess) = 0; 

程式碼如下:

  1 template <typename PointSource, typename PointTarget, typename Scalar> void
  2 pcl::IterativeClosestPoint<PointSource, PointTarget, Scalar>::computeTransformation (
  3     PointCloudSource &output, const Matrix4 &guess)
  4 {
  5   // Point cloud containing the correspondences of each point in <input, indices>
  6   PointCloudSourcePtr input_transformed (new PointCloudSource);
  7 
  8   nr_iterations_ = 0;
  9   converged_ = false;
 10 
 11   // Initialise final transformation to the guessed one
 12   final_transformation_ = guess;
 13 
 14   // If the guessed transformation is non identity
 15   if (guess != Matrix4::Identity ())
 16   {
 17     input_transformed->resize (input_->size ());
 18      // Apply guessed transformation prior to search for neighbours
 19     transformCloud (*input_, *input_transformed, guess);
 20   }
 21   else
 22     *input_transformed = *input_;
 23  
 24   transformation_ = Matrix4::Identity ();
 25 
 26   // Make blobs if necessary
 27   determineRequiredBlobData ();
 28   PCLPointCloud2::Ptr target_blob (new PCLPointCloud2);
 29   if (need_target_blob_)
 30     pcl::toPCLPointCloud2 (*target_, *target_blob);
 31 
 32   // Pass in the default target for the Correspondence Estimation/Rejection code
 33   correspondence_estimation_->setInputTarget (target_);
 34   if (correspondence_estimation_->requiresTargetNormals ())
 35     correspondence_estimation_->setTargetNormals (target_blob);
 36   // Correspondence Rejectors need a binary blob
 37   for (size_t i = 0; i < correspondence_rejectors_.size (); ++i)
 38   {
 39     registration::CorrespondenceRejector::Ptr& rej = correspondence_rejectors_[i];
 40     if (rej->requiresTargetPoints ())
 41       rej->setTargetPoints (target_blob);
 42     if (rej->requiresTargetNormals () && target_has_normals_)
 43       rej->setTargetNormals (target_blob);
 44   }
 45 
 46   convergence_criteria_->setMaximumIterations (max_iterations_);
 47   convergence_criteria_->setRelativeMSE (euclidean_fitness_epsilon_);
 48   convergence_criteria_->setTranslationThreshold (transformation_epsilon_);
 49   convergence_criteria_->setRotationThreshold (1.0 - transformation_epsilon_);
 50 
 51   // Repeat until convergence
 52   do
 53   {
 54     // Get blob data if needed
 55     PCLPointCloud2::Ptr input_transformed_blob;
 56     if (need_source_blob_)
 57     {
 58       input_transformed_blob.reset (new PCLPointCloud2);
 59       toPCLPointCloud2 (*input_transformed, *input_transformed_blob);
 60     }
 61     // Save the previously estimated transformation
 62     previous_transformation_ = transformation_;
 63 
 64     // Set the source each iteration, to ensure the dirty flag is updated
 65     correspondence_estimation_->setInputSource (input_transformed);
 66     if (correspondence_estimation_->requiresSourceNormals ())
 67       correspondence_estimation_->setSourceNormals (input_transformed_blob);
 68     // Estimate correspondences
 69     if (use_reciprocal_correspondence_)
 70       correspondence_estimation_->determineReciprocalCorrespondences (*correspondences_, corr_dist_threshold_);
 71     else
 72       correspondence_estimation_->determineCorrespondences (*correspondences_, corr_dist_threshold_);
 73 
 74     //if (correspondence_rejectors_.empty ())
 75     CorrespondencesPtr temp_correspondences (new Correspondences (*correspondences_));
 76     for (size_t i = 0; i < correspondence_rejectors_.size (); ++i)
 77     {
 78       registration::CorrespondenceRejector::Ptr& rej = correspondence_rejectors_[i];
 79       PCL_DEBUG ("Applying a correspondence rejector method: %s.\n", rej->getClassName ().c_str ());
 80       if (rej->requiresSourcePoints ())
 81         rej->setSourcePoints (input_transformed_blob);
 82       if (rej->requiresSourceNormals () && source_has_normals_)
 83         rej->setSourceNormals (input_transformed_blob);
 84       rej->setInputCorrespondences (temp_correspondences);
 85       rej->getCorrespondences (*correspondences_);
 86       // Modify input for the next iteration
 87       if (i < correspondence_rejectors_.size () - 1)
 88         *temp_correspondences = *correspondences_;
 89     }
 90 
 91     size_t cnt = correspondences_->size ();
 92     // Check whether we have enough correspondences
 93     if (static_cast<int> (cnt) < min_number_correspondences_)
 94     {
 95       PCL_ERROR ("[pcl::%s::computeTransformation] Not enough correspondences found. Relax your threshold parameters.\n", getClassName ().c_str ());
 96       convergence_criteria_->setConvergenceState(pcl::registration::DefaultConvergenceCriteria<Scalar>::CONVERGENCE_CRITERIA_NO_CORRESPONDENCES);
 97       converged_ = false;
 98       break;
 99     }
100 
101     // Estimate the transform
102     transformation_estimation_->estimateRigidTransformation (*input_transformed, *target_, *correspondences_, transformation_);
103 
104     // Tranform the data
105     transformCloud (*input_transformed, *input_transformed, transformation_);
106 
107     // Obtain the final transformation    
108     final_transformation_ = transformation_ * final_transformation_;
109 
110     ++nr_iterations_;
111 
112     // Update the vizualization of icp convergence
113     //if (update_visualizer_ != 0)
114     //  update_visualizer_(output, source_indices_good, *target_, target_indices_good );
115 
116     converged_ = static_cast<bool> ((*convergence_criteria_));
117   }
118   while (!converged_);
119 
120   // Transform the input cloud using the final transformation
121   PCL_DEBUG ("Transformation is:\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n", 
122       final_transformation_ (0, 0), final_transformation_ (0, 1), final_transformation_ (0, 2), final_transformation_ (0, 3),
123       final_transformation_ (1, 0), final_transformation_ (1, 1), final_transformation_ (1, 2), final_transformation_ (1, 3),
124       final_transformation_ (2, 0), final_transformation_ (2, 1), final_transformation_ (2, 2), final_transformation_ (2, 3),
125       final_transformation_ (3, 0), final_transformation_ (3, 1), final_transformation_ (3, 2), final_transformation_ (3, 3));
126 
127   // Copy all the values
128   output = *input_;
129   // Transform the XYZ + normals
130   transformCloud (*input_, output, final_transformation_);
131 }

該方法的主體是一個do-while迴圈。這裡要說三個內容:correspondence_estimation_ 、correspondence_rejectors_ 和 convergence_criteria_ 。

三個變數的作用分別是查詢最近點,剔除錯誤的對應點,收斂準則。因為是do-while迴圈,因此收斂準則的作用是跳出迴圈。

transformation_estimation_是求解ICP的具體演算法:

 1 transformation_estimation_->estimateRigidTransformation (*input_transformed, *target_, *correspondences_, transformation_); 

檢視類圖可以知道包括SVD奇異值分解演算法,檢視transformation_estimation_svd.hpp中的TransformationEstimationSVD類的estimateRigidTransformation 方法:

template <typename PointSource, typename PointTarget, typename Scalar> inline void
pcl::registration::TransformationEstimationSVD<PointSource, PointTarget, Scalar>::estimateRigidTransformation (
    ConstCloudIterator<PointSource>& source_it,
    ConstCloudIterator<PointTarget>& target_it,
    Matrix4 &transformation_matrix) const

其中通過呼叫下面的程式碼實現了SVD求解,具體方法內部實現時通過Eigen3實現的。需要具體檢視,可以借鑑。

  transformation_matrix = pcl::umeyama (cloud_src, cloud_tgt, false); 

相關推薦

[PCL]5 ICP演算法進行匹配

但是將對應點剔除這塊和ICP演算法的關係還是沒有理解。 RANSAC演算法可以實現點雲剔除,但是ICP演算法通過穩健性的演算法實現匹配,似乎不進行對應點剔除。是不是把全域性的點雲匹配方法和區域性點雲匹配方法搞混了? ICP演算法可以通過三種方式處理噪聲、部分重疊的問題:剔除、權重、Trimmed方法和

匹配ICP演算法概述

Iterative Closest Point (ICP) [1][2][3] is an algorithm employed to minimize the difference between two clouds of points. 點雲匹配分類法(1)

PCL使用VoxelGrid filter對進行下采樣

#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #includ

PCL: Registration模組之IterativeClosestPoint配準

ICP匹配,中文應該叫臨近點迭代吧,是計算機圖形學中的一個非常有用的演算法,尤其是在三維重建點雲配準中有著極其重要的地位,此外在SLAM等移動機器人導航等領域也有著很大的用武之地。 經過了十多年的發展ICP也有著很多的變種,今天我們首先熟悉下最基本的ICP匹配演算法,PCL中的實現與參考文獻中的

PCL配置以及簡單的顯示

       從開始配置點雲加上前段時間的論文開題,已經花費了我快一個月的時間,都說萬事開頭難!是真的難,我甚至想過換方向~開個玩笑,雖然沒有對點雲瞭解多少,但感覺這個方向還是很有發展前途的。下面說一下我個人的點雲配置。        之前嘗試過VS的各種版本,VS2017

PCL庫看三維依賴的相關知識

       第一次使用PCL庫還是2017年,當時為了提取火線(火場包絡線:凹包),因為凸包雖然很簡單,但是不符合實際火場分佈的情況,於是查詢到了PCL可以實現,於是熬了幾個夜,走馬觀花的安裝、測試最終參考程式碼實現了想要的功能,但是PCL真的是連一知半

雙邊濾波演算法資料處理時的應用

雙邊濾波演算法在點雲資料處理時的應用 簡介(摘自百科) 雙邊濾波(Bilateral filter)是一種非線性的濾波方法,是結合影象的空間鄰近度和畫素值相似度的一種折中處理,同時考慮空域資訊和灰度相似性,達到保邊去噪的目的。具有簡單、非迭代、區域性的特點 。雙邊濾波器的好處是可以做

深度學習演算法分割-PointNet(五)

大家好,今天給大家介紹下cvpr2017 一篇文章Pointnet 語義分割,該網路基於tensorflow 寫的,非常輕巧方便,但是文章和程式碼有一定出入,在訓練過程中出現過擬合現象,大概訓練了10個小時多.1    需要準備的東東(1) Ubuntu 16.04  GTX1060 6G(2) CUDA 安

PCL求取三維模型每曲率

最近在做有關實驗需要計算模型曲率,但是網上找了一圈也沒找到滿意的資料。最後發現PCL庫可以很方便的求取模型中每一個點的曲率,但是我們要想將PCL庫求得的曲率資料應用到自己的專案中需要將PCL庫與我們的專案進行結合,並且在PCL求出曲率後存放在自己的結構體中,這樣才能得到更適合

基於PCL的三維重建——的濾波處理

在獲取點雲資料時 ,由於裝置精度,操作者經驗環境因素帶來的影響,以及電磁波的衍射特性,被測物體表面性質變化和資料拼接配準操作過程的影響,點雲資料中講不可避免的出現一些噪聲。在點雲處理流程中濾波處理作為預處理的第一步,對後續的影響比較大,只有在濾波預處理中將噪聲點 ,離群點,

在vs2013中執行PCL(用來處理等三維操作)程式

      有的同學一開始學習PCL的時候,會去看PCL中文官網或者《點雲庫PCL學習教程》(朱德海)這書,首先我建議多去看英文官網,裡面的教程比較新,內容豐富。       另外,教程裡面PCL程式

PCL重新整理顯示變化的

在標頭檔案中,定義了: int m_colorInc;//演示紅色分量不斷增長。這是增長步長。 在cpp檔案中,剛開始,在檔案最上面,開啟一個3D視窗,如下面程式碼所示。 // PCLDemoDlg.cpp : 實現檔案 // #include "stdafx.h"

深度學習演算法分割-Pointnet++(一)

   在過去的這些年裡,對二維影象已經有了大量深入的研究,並且有著長足的發展。它在分類任務上取得了極好的結果主要得益於一下兩個關鍵因素:1.卷積神經網路。2.資料 - 大量影象資料可用。   但是對於3D點雲,資料正在迅速增長。大有從2D向3D發展的趨勢,比如在opencv中就已經慢慢包含了3D點雲的處理的相

PCL庫:ICP演算法

轉自:https://www.cnblogs.com/21207-iHome/p/6034462.html  ICP(Iterative Closest Point迭代最近點)演算法是一種點集對點集配準方法。在VTK、PCL、MRPT、MeshLab等C++庫或軟體中都有實現,可以參見維基百科中

PCL庫:ICP演算法(講解很好帶有圖,作者研究很深入)

@ 冬木遠景我有試過這樣改,可它又報另一個錯誤,"1>c:\program files\pcl 1.6.0\3rdparty\eigen\include\eigen\src/Core/Matrix.h(294): error C2338: YOU_MIXED_DIFFERENT_NUMERIC_TYPE

pcl處理之pca演算法

2018年11月08日 19:10:20 weixin_41825780 閱讀數:2 標籤: pcl

Kinect-Fusion ICP演算法構建帶法向量金字塔

主要步驟: 1、構建帶法向量的點雲金字塔,ICP執行時先對金字塔高層的點雲進行匹配,再往下層走,即從粗匹配到精匹配的過程,加快收斂速度; 2、找兩點雲的匹配點; 3、構造目標函式,並且最小化目標函式獲得轉換矩陣; 4、判斷目標函式的大小是否小於所設定的閾值,或者迭代次數是否

PCL庫學習&VS2010(X64)》Part 51 PTDV0.2迭代加密三角網演算法V0.2

《PCL點雲庫學習&VS2010(X64)》Part 51 PTDV0.2迭代加密三角網演算法V0.2 1、利用實際點雲測試初級版本的漸進加密三角網演算法: 1、獲取最低點 2、構建初始三角網 3、更新最低點 4、更新三角

PCL 3D-NDT演算法配準

本節我們將介紹如何使用正態分佈變換演算法來確定兩個大型點雲(都超過100,000個點)之間的剛體變換。正態分佈變換演算法是一個配准算法,它應用於三維點的統計模型,使用標準最優化技術來確定兩個點雲間的最優的匹配,因為其在配準過程中不利用對應點的特徵計算和匹配,所以

應用Fast ICP進行集或曲面配準 演算法解析

1. ICP演算法的一些網路資源 2. 經典ICP演算法的步驟 3. fast ICP演算法 ICP(Iterative closest points)演算法是點集配準的經典演算法,演算法基本原理是在A method for registration of 3-D sh