1. 程式人生 > 實用技巧 >PCL——(10)PCL中使用隨機取樣一致性模型

PCL——(10)PCL中使用隨機取樣一致性模型

@目錄


在計算機視覺領域廣泛的使用各種不同的取樣一致性引數估計演算法用於排除錯誤的樣本,樣本不同對應的應用不同,例如剔除錯誤的配準點對,分割出處在模型上的點集,PCL中以隨機取樣一致性演算法(RANSAC)為核心,同時實現了五種類似與隨機取樣一致形演算法的隨機引數估計演算法,例如隨機取樣一致性演算法(RANSAC)最大似然一致性演算法(MLESAC),最小中值方差一致性演算法(LMEDS)等,所有估計引數演算法都符合一致性原則。在PCL中設計的取樣一致性演算法的應用主要就是對點雲進行分割,根據設定的不同的幾個模型,估計對應的幾何引數模型的引數,在一定容許的範圍內分割出在模型上的點雲。

一、RANSAC隨機取樣一致性演算法的介紹

RANSAC是“RANdom SAmple Consensus(隨機抽樣一致)”的縮寫。它可以從一組包含“局外點”的觀測資料集中,通過迭代方式估計數學模型的引數。它是一種不確定的演算法——它有一定的概率得出一個合理的結果;為了提高概率必須提高迭代次數。

數 據分兩種:有效資料(inliers)和無效資料(outliers)。偏差不大的資料稱為有效資料,偏差大的資料是無效資料。如果有效資料佔大多數,無 效資料只是少量時,我們可以通過最小二乘法或類似的方法來確定模型的引數和誤差;如果無效資料很多(比如超過了50%的資料都是無效資料),最小二乘法就 失效了,我們需要新的演算法

一個簡單的例子是從一組觀測資料中找出合適的2維直線。假設觀測資料中包含局內點和局外點,其中局內點近似的被直線所通過,而局外點遠離於直線。簡單的最 小二乘法不能找到適應於局內點的直線,原因是最小二乘法儘量去適應包括局外點在內的所有點。相反,RANSAC能得出一個僅僅用局內點計算出模型,並且概 率還足夠高。但是,RANSAC並不能保證結果一定正確,為了保證演算法有足夠高的合理概率,我們必須小心的選擇演算法的引數。


左圖:包含很多局外點的資料集 . 右圖:RANSAC找到的直線(局外點並不影響結果)

詳細介紹可以檢視我的另一篇博文。

二、最小中值法(LMedS)

三、PCL中使用隨機取樣一致性模型

#include <iostream>
#include <pcl/console/parse.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_plane.h>
#include <pcl/sample_consensus/sac_model_sphere.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>

boost::shared_ptr<pcl::visualization::PCLVisualizer>
simpleVis (pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud)
{
  // --------------------------------------------
  // -----Open 3D viewer and add point cloud-----
  // --------------------------------------------
  boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
  viewer->setBackgroundColor (0, 0, 0);
  viewer->addPointCloud<pcl::PointXYZ> (cloud, "sample cloud");
  viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");
  //viewer->addCoordinateSystem (1.0, "global");
  viewer->initCameraParameters ();
  return (viewer);
}
/******************************************************************************************************************
 對點雲進行初始化,並對其中一個點雲填充點雲資料作為處理前的的原始點雲,其中大部分點雲資料是基於設定的圓球和平面模型計算
  而得到的座標值作為局內點,有1/5的點雲資料是被隨機放置的作為局外點。
 *****************************************************************************************************************/
int
main(int argc, char** argv)
{
  // 初始化點雲物件
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);  //儲存源點雲
  pcl::PointCloud<pcl::PointXYZ>::Ptr final (new pcl::PointCloud<pcl::PointXYZ>);   //儲存提取的局內點

  // 填充點雲資料
  cloud->width    = 500;                 //填充點雲數目
   cloud->height   = 1;                     //無序點雲
  cloud->is_dense = false;
  cloud->points.resize (cloud->width * cloud->height);
  for (size_t i = 0; i < cloud->points.size (); ++i)
  {
    if (pcl::console::find_argument (argc, argv, "-s") >= 0 || pcl::console::find_argument (argc, argv, "-sf") >= 0)
    {
//根據命令列引數用x^2+y^2+Z^2=1設定一部分點雲資料,此時點雲組成1/4個球體作為內點
      cloud->points[i].x = 1024 * rand () / (RAND_MAX + 1.0);
      cloud->points[i].y = 1024 * rand () / (RAND_MAX + 1.0);
      if (i % 5 == 0)
        cloud->points[i].z = 1024 * rand () / (RAND_MAX + 1.0);   //此處對應的點為局外點
      else if(i % 2 == 0)
        cloud->points[i].z =  sqrt( 1 - (cloud->points[i].x * cloud->points[i].x)
                                      - (cloud->points[i].y * cloud->points[i].y));
      else
        cloud->points[i].z =  - sqrt( 1 - (cloud->points[i].x * cloud->points[i].x)
                                        - (cloud->points[i].y * cloud->points[i].y));
    }
    else
    { //用x+y+z=1設定一部分點雲資料,此時地拿雲組成的菱形平面作為內點
      cloud->points[i].x = 1024 * rand () / (RAND_MAX + 1.0);
      cloud->points[i].y = 1024 * rand () / (RAND_MAX + 1.0);
      if( i % 2 == 0)
        cloud->points[i].z = 1024 * rand () / (RAND_MAX + 1.0);   //對應的局外點
      else
        cloud->points[i].z = -1 * (cloud->points[i].x + cloud->points[i].y);
    }
  }

  std::vector<int> inliers;  //儲存局內點集合的點的索引的向量

  //建立隨機取樣一致性物件
  pcl::SampleConsensusModelSphere<pcl::PointXYZ>::Ptr
    model_s(new pcl::SampleConsensusModelSphere<pcl::PointXYZ> (cloud));    //針對球模型的物件
  pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptr
    model_p (new pcl::SampleConsensusModelPlane<pcl::PointXYZ> (cloud));   //針對平面模型的物件
  if(pcl::console::find_argument (argc, argv, "-f") >= 0)
  {  //根據命令列引數,來隨機估算對應平面模型,並存儲估計的局內點
    pcl::RandomSampleConsensus<pcl::PointXYZ> ransac (model_p);
    ransac.setDistanceThreshold (.01);    //與平面距離小於0.01 的點稱為局內點考慮
    ransac.computeModel();                   //執行隨機引數估計
    ransac.getInliers(inliers);                 //儲存估計所得的局內點
  }
  else if (pcl::console::find_argument (argc, argv, "-sf") >= 0 )
  { 
   //根據命令列引數  來隨機估算對應的圓球模型,儲存估計的內點
    pcl::RandomSampleConsensus<pcl::PointXYZ> ransac (model_s);
    ransac.setDistanceThreshold (.01);
    ransac.computeModel();
    ransac.getInliers(inliers);
  }

  // 複製估算模型的所有的局內點到final中
  pcl::copyPointCloud<pcl::PointXYZ>(*cloud, inliers, *final);

  // 建立視覺化物件並加入原始點雲或者所有的局內點

  boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;
  if (pcl::console::find_argument (argc, argv, "-f") >= 0 || pcl::console::find_argument (argc, argv, "-sf") >= 0)
    viewer = simpleVis(final);
  else
    viewer = simpleVis(cloud);
  while (!viewer->wasStopped ())
  {
    viewer->spinOnce (100);
    boost::this_thread::sleep (boost::posix_time::microseconds (100000));
  }
  return 0;
 }

四、Sample_consensus模型支援的幾何模型

  1. SACMODEL_PLANE - used to determine plane models. The four coefficients of the plane are its Hessian Normal form: [normal_x normal_y normal_z d]
  2. SACMODEL_LINE - used to determine line models. The six coefficients of the line are given by a point on the line and the direction of the line as: [point_on_line.x point_on_line.y point_on_line.z line_direction.x line_direction.y line_direction.z]
  3. SACMODEL_CIRCLE2D - used to determine 2D circles in a plane. The circle's three coefficients are given by its center and radius as: [center.x center.y radius]
  4. SACMODEL_CIRCLE3D - used to determine 3D circles in a plane. The circle's seven coefficients are given by its center, radius and normal as: [center.x, center.y, center.z, radius, normal.x, normal.y, normal.z]
  5. SACMODEL_SPHERE - used to determine sphere models. The four coefficients of the sphere are given by its 3D center and radius as: [center.x center.y center.z radius]
  6. SACMODEL_CYLINDER - used to determine cylinder models. The seven coefficients of the cylinder are given by a point on its axis, the axis direction, and a radius, as: [point_on_axis.x point_on_axis.y point_on_axis.z axis_direction.x axis_direction.y axis_direction.z radius]
  7. SACMODEL_CONE - used to determine cone models. The seven coefficients of the cone are given by a point of its apex, the axis direction and the opening angle, as: [apex.x, apex.y, apex.z, axis_direction.x, axis_direction.y, axis_direction.z, opening_angle]
  8. SACMODEL_TORUS - not implemented yet
  9. SACMODEL_PARALLEL_LINE - a model for determining a line parallel with a given axis, within a maximum specified angular deviation. The line coefficients are similar to SACMODEL_LINE .
  10. SACMODEL_PERPENDICULAR_PLANE - a model for determining a plane perpendicular to an user-specified axis, within a maximum specified angular deviation. The plane coefficients are similar to SACMODEL_PLANE .
  11. SACMODEL_PARALLEL_LINES - not implemented yet
  12. SACMODEL_NORMAL_PLANE - a model for determining plane models using an additional constraint: the surface normals at each inlier point has to be parallel to the surface normal of the output plane, within a maximum specified angular deviation. The plane coefficients are similar to SACMODEL_PLANE .
  13. SACMODEL_PARALLEL_PLANE - a model for determining a plane parallel to an user-specified axis, within a maximum specified angular deviation. SACMODEL_PLANE .
  14. SACMODEL_NORMAL_PARALLEL_PLANE defines a model for 3D plane segmentation using additional surface normal constraints. The plane must lie parallel to a user-specified axis. SACMODEL_NORMAL_PARALLEL_PLANE therefore is equivalent to SACMODEL_NORMAL_PLANE + SACMODEL_PARALLEL_PLANE. The plane coefficients are similar to SACMODEL_PLANE .