pcl--第四节 采样一致性算法RANSAC

3 篇文章 0 订阅

RANSAC随机采样一致性算法简介

RANSAC是“RANdom SAmple Consensus”(随机抽样共识或采样一致性)的缩写,它是一种迭代方法,用于从包含异常值的一组数据中估计数学模型的参数。该算法由Fischler和Bolles于1981年发布。

RANSAC算法假定我们要查看的所有数据均由内部值和异常值组成。可以用带有一组特定参数值的模型来解释离群值,而离群值在任何情况下都不适合该模型。其过程可以从数据中估计所选模型的最佳参数。

RANSAC是一种随机参数估计算法。RANSAC 从样本中随机抽选出一个样本子集,使用最小方差估计算法对这个子集计算模型参数,然后计算所有样本与该模型的偏差,再使用一个预先设定好的阑值与偏差比较,当偏差小于闽值时,该样本点属于模型内样本点(inliers),文中简称局内点或内点,否则为模型外样本点(outliers).文中简称局外点或外点,记录下当前的 inliers 的个数,然后重复这一过程。每一次重复都记录当前最佳的模型参数,所谓最佳即是inliers 的个数最多此时对应的 inliers 个数为 best_ninliers。每次迭代的末尾都会根据期望的误差率best_ninliers总样本个数、当前迭代次数,计算一个迭代结束评判因子,据此决定是否迭代结束迭代结束后,最佳模型参数就是最终的模型参数估计值。

RANSAC理论上可以剔除 outliers 的影响,并得到全局最优的参数估计。但是RANSAC有两个问题首先在每次迭代中都要区分inliers和outlieres,因此需要事先设定阙值,当模型具有明显的物理意义时,这个阙值还比较容易设定,但是若模型比较抽象时,这个阙值就不那么容易设定了,而且固定值不适用于样本动态变化的应用;第二个问题是,RANSAC 的选代次数是运行期决定的,不能预知选代的确切次数(当然迭代次数的范围是可以预测的)。除此之外,RANSAC 只能从一个特定数据集中估计一个模型,当两个(或者更多个)模型存在时,RANSAC不能找到别的模型图a和b展示了 RANSAC算法在二维数据集中的简单应用。图a的图像形象地表示了一组既包含局内点又包含局外点的数据集。图 b的图像中所有的局外点都表示为红色,局内点表示为蓝色,蓝色线就是基于 RANSAC得到的结果,此例中我们尝试适应数据的模型就是一条线。

同理还可以拟合圆

 

PCL 中以随机采样一致性算法( RANSAC) 为核心,实现了五种类似于RANSAC的随机参数估计算法,例如随机采样一致性估计(RANSAC ) 、最大似然一致性估计 (MLESAC ) 、最小中值方差一致性估计 ( LMEDS )等,所有的估计参数算法都符合一致性准则。利用RANSAC可以实现点云分割,目前 PCL 中支持的几何模型分割有 空间平面、直线、二维或三维圆、圆球、锥体等 。 RANSAC的另一应用就是点云的配准对的剔除。 

LMedS最小中值方差估计算法

LMedS也是一种随机参数估计算法。LMedS也从样本中随机抽选出一个样本子集,使用最小方差估计算法对子集计算模型参数,然后计算所有样本与该模型的偏差。但是与 RANSAC不同的是,LMedS 记录的是所有样本中偏差值居中的那个样本的偏差,称为 Med 偏差(这也是 LMedS 中 Med 的由来以及本次计算得到的模型参数。由于这一变化,LMedS 不需要预先设定值来区分inliers 和outliers。重复前面的过程N次,从中N个 Med 偏差中挑选出最小的一个,其对应的模型参数就是最终的模型参数估计值。其中迭代次数 N 是由样本子集中样本的个数期望的模型误差、事先估计的样本中outliers 的比例所决定。
LMedS理论上也可以剔除 outliers 的影响并得到全局最优的参数估计而且克服了RANSAC的两个缺点(虽然 LMedS 也需要实现设定样本中 outliers 的比例 ,但这个数字比较容易设定。但是当 outliers 在样本中所占比例达到或超过50%时,LMedS就无能为力了!这与 LMedS每次代记录的是“Med”偏差值有关。

RANSAC随机采样原理

RANSAC从样本中随机抽选出一个样本子集,使用最小方差估计算法对这个子集计算模型参数,然后计算所有样本与该模型的偏差,再使用一个预先设定好的阈值与偏差比较,当偏差小于阈值时,该样本点属于模型内样本点 ( inliers),或称内部点、局内点或内点,否则为模型外样本点(outliers),或称外部点、局外点或外点,记录下当前的 inliers 的个数,然后重复这一过程。每一次重复都记录当前最佳的模型参数,所谓最佳即是inliers的个数最多 ,此时对应的inliers个数为 best_ninliers 。 每次迭代的末尾都会根据期望的误差率、 best_ninliers、总样本个数、当前迭代次数,计算一 个迭代结束评判因子,据此决定是否迭代结束。迭代结束后,最佳模型参数就是最终的模型参数估计值 。

RANSAC理论上可以剔除outliers的影响,并得到全局最优的参数估计。但是RANSAC 有两个问题,首先在每次迭代中都要区分 inliers 和 outlieres,因此需要事先设定阈值,当模型具有明显的物理意义时,这个阈值还比较容易设定,但是若模型比较抽象时,阈值就不那么容易设定了。而且固定阈值不适用于样本动态变化的应用;第二个问题是,RANSAC的迭代次数是运行期决定的,不能预知迭代的确切次数(当然迭代次数的范围是可以预测的)。除此之外, RANSAC 只能从一个特定数据集中估计一个模型,当两个(或者更多个)模型存在时,RANSAC 同时找到多个模型。

#include <iostream>
#include <thread>

#include <pcl/console/parse.h>
#include <pcl/point_cloud.h> // for PointCloud
#include <pcl/common/io.h> // for copyPointCloud
#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 <pcl/io/pcd_io.h>

using namespace std::chrono_literals;

pcl::visualization::PCLVisualizer::Ptr
simpleVis (pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud)
{
  // --------------------------------------------
  // -----Open 3D viewer and add point cloud-----
  // --------------------------------------------
  pcl::visualization::PCLVisualizer::Ptr 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);
}

int
main(int argc, char** argv)
{
  // initialize PointClouds
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PointCloud<pcl::PointXYZ>::Ptr final (new pcl::PointCloud<pcl::PointXYZ>);

  // populate our PointCloud with points
  cloud->width    = 500;
  cloud->height   = 1;
  cloud->is_dense = false;
  cloud->points.resize (cloud->width * cloud->height);
  for (pcl::index_t i = 0; i < static_cast<pcl::index_t>(cloud->size ()); ++i)
  {
    if (pcl::console::find_argument (argc, argv, "-s") >= 0 || pcl::console::find_argument (argc, argv, "-sf") >= 0)
    {
      (*cloud)[i].x = 1024 * rand () / (RAND_MAX + 1.0);
      (*cloud)[i].y = 1024 * rand () / (RAND_MAX + 1.0);
      if (i % 5 == 0)
        (*cloud)[i].z = 1024 * rand () / (RAND_MAX + 1.0);
      else if(i % 2 == 0)
        (*cloud)[i].z =  sqrt( 1 - ((*cloud)[i].x * (*cloud)[i].x)
                                      - ((*cloud)[i].y * (*cloud)[i].y));
      else
        (*cloud)[i].z =  - sqrt( 1 - ((*cloud)[i].x * (*cloud)[i].x)
                                        - ((*cloud)[i].y * (*cloud)[i].y));
    }
    else
    {
      (*cloud)[i].x = 1024 * rand () / (RAND_MAX + 1.0);
      (*cloud)[i].y = 1024 * rand () / (RAND_MAX + 1.0);
      if( i % 2 == 0)
        (*cloud)[i].z = 1024 * rand () / (RAND_MAX + 1.0);
      else
        (*cloud)[i].z = -1 * ((*cloud)[i].x + (*cloud)[i].y);
    }
  }

  pcl::PCDWriter writer;
  writer.write("data.pcd", *cloud);


  std::vector<int> inliers;

  // created RandomSampleConsensus object and compute the appropriated model
  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);
    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);
  }

  // copies all inliers of the model computed to another PointCloud
  pcl::copyPointCloud (*cloud, inliers, *final);
  writer.write("plane.pcd", *final);
  // creates the visualization object and adds either our original cloud or all of the inliers
  // depending on the command line arguments specified.
  pcl::visualization::PCLVisualizer::Ptr 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);
    std::this_thread::sleep_for(100ms);
  }
  return 0;
 }

我这边把例子数据进行了保存,然后可视化,结果如下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RANSACRandom Sample Consensus)是一种用于拟合模型的迭代方法,常用于点云数据的拟合。PCL(Point Cloud Library)是一个开源的点云处理库。 要使用RANSAC拟合点云数据,首先需要导入PCL库,并创建一个PointCloud对象来存储点云数据。然后,选择一个合适的模型(例如平面、直线等)来拟合点云数据。 下面是一个使用RANSAC拟合平面的示例代码: ```cpp #include <pcl/point_types.h> #include <pcl/sample_consensus/ransac.h> #include <pcl/sample_consensus/sac_model_plane.h> int main() { // 创建点云对象 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // 读取点云数据 pcl::io::loadPCDFile<pcl::PointXYZ>("input_cloud.pcd", *cloud); // 创建RANSAC对象 pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptr model(new pcl::SampleConsensusModelPlane<pcl::PointXYZ>(cloud)); pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(model); // 设置RANSAC参数 ransac.setDistanceThreshold(0.01); // 设置距离阈值,用于判断是否为内点 // 执行RANSAC拟合 ransac.computeModel(); // 获取拟合后的模型参数 Eigen::VectorXf model_coefficients; ransac.getModelCoefficients(model_coefficients); // 输出模型参数 std::cout << "Model coefficients: " << model_coefficients.transpose() << std::endl; return 0; } ``` 在上述代码中,我们首先读取了一个点云文件(input_cloud.pcd),然后创建了一个平面模型的RANSAC对象。接下来,我们设置了RANSAC的距离阈值,并执行了拟合过程。最后,我们获取了拟合后的模型参数,并输出到控制台。 这只是一个简单的示例,你可以根据具体需求修改代码来拟合不同的模型或调整参数。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值