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


    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 同时找到多个模型。

    1. #include
    2. #include
    3. #include
    4. #include // for PointCloud
    5. #include // for copyPointCloud
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. using namespace std::chrono_literals;
    13. pcl::visualization::PCLVisualizer::Ptr
    14. simpleVis (pcl::PointCloud::ConstPtr cloud)
    15. {
    16. // --------------------------------------------
    17. // -----Open 3D viewer and add point cloud-----
    18. // --------------------------------------------
    19. pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
    20. viewer->setBackgroundColor (0, 0, 0);
    21. viewer->addPointCloud (cloud, "sample cloud");
    22. viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");
    23. //viewer->addCoordinateSystem (1.0, "global");
    24. viewer->initCameraParameters ();
    25. return (viewer);
    26. }
    27. int
    28. main(int argc, char** argv)
    29. {
    30. // initialize PointClouds
    31. pcl::PointCloud::Ptr cloud (new pcl::PointCloud);
    32. pcl::PointCloud::Ptr final (new pcl::PointCloud);
    33. // populate our PointCloud with points
    34. cloud->width = 500;
    35. cloud->height = 1;
    36. cloud->is_dense = false;
    37. cloud->points.resize (cloud->width * cloud->height);
    38. for (pcl::index_t i = 0; i < static_castindex_t>(cloud->size ()); ++i)
    39. {
    40. if (pcl::console::find_argument (argc, argv, "-s") >= 0 || pcl::console::find_argument (argc, argv, "-sf") >= 0)
    41. {
    42. (*cloud)[i].x = 1024 * rand () / (RAND_MAX + 1.0);
    43. (*cloud)[i].y = 1024 * rand () / (RAND_MAX + 1.0);
    44. if (i % 5 == 0)
    45. (*cloud)[i].z = 1024 * rand () / (RAND_MAX + 1.0);
    46. else if(i % 2 == 0)
    47. (*cloud)[i].z = sqrt( 1 - ((*cloud)[i].x * (*cloud)[i].x)
    48. - ((*cloud)[i].y * (*cloud)[i].y));
    49. else
    50. (*cloud)[i].z = - sqrt( 1 - ((*cloud)[i].x * (*cloud)[i].x)
    51. - ((*cloud)[i].y * (*cloud)[i].y));
    52. }
    53. else
    54. {
    55. (*cloud)[i].x = 1024 * rand () / (RAND_MAX + 1.0);
    56. (*cloud)[i].y = 1024 * rand () / (RAND_MAX + 1.0);
    57. if( i % 2 == 0)
    58. (*cloud)[i].z = 1024 * rand () / (RAND_MAX + 1.0);
    59. else
    60. (*cloud)[i].z = -1 * ((*cloud)[i].x + (*cloud)[i].y);
    61. }
    62. }
    63. pcl::PCDWriter writer;
    64. writer.write("data.pcd", *cloud);
    65. std::vector<int> inliers;
    66. // created RandomSampleConsensus object and compute the appropriated model
    67. pcl::SampleConsensusModelSphere::Ptr
    68. model_s(new pcl::SampleConsensusModelSphere (cloud));
    69. pcl::SampleConsensusModelPlane::Ptr
    70. model_p (new pcl::SampleConsensusModelPlane (cloud));
    71. if(pcl::console::find_argument (argc, argv, "-f") >= 0)
    72. {
    73. pcl::RandomSampleConsensus ransac (model_p);
    74. ransac.setDistanceThreshold (.01);
    75. ransac.computeModel();
    76. ransac.getInliers(inliers);
    77. }
    78. else if (pcl::console::find_argument (argc, argv, "-sf") >= 0 )
    79. {
    80. pcl::RandomSampleConsensus ransac (model_s);
    81. ransac.setDistanceThreshold (.01);
    82. ransac.computeModel();
    83. ransac.getInliers(inliers);
    84. }
    85. // copies all inliers of the model computed to another PointCloud
    86. pcl::copyPointCloud (*cloud, inliers, *final);
    87. writer.write("plane.pcd", *final);
    88. // creates the visualization object and adds either our original cloud or all of the inliers
    89. // depending on the command line arguments specified.
    90. pcl::visualization::PCLVisualizer::Ptr viewer;
    91. if (pcl::console::find_argument (argc, argv, "-f") >= 0 || pcl::console::find_argument (argc, argv, "-sf") >= 0)
    92. viewer = simpleVis(final);
    93. else
    94. {
    95. viewer = simpleVis(cloud);
    96. }
    97. while (!viewer->wasStopped ())
    98. {
    99. viewer->spinOnce (100);
    100. std::this_thread::sleep_for(100ms);
    101. }
    102. return 0;
    103. }

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

  • 相关阅读:
    Django-数据库路由映射
    等级保护2.0安全体系框架新升级,山石网科助力企业网络安全建设
    【Linux】多线程(重中之重)(学习兼顾复习)
    深入理解java虚拟机:虚拟机字节码执行引擎(2)
    【注入电子邮件】SMTP命令漏洞查找、注入、防止
    Request&Response
    [MAUI 项目实战] 笔记App(二):数据库设计
    Rust 从入门到精通04-变量
    LabVIEW中比较两个VI
    Docker跨主机网络通信
  • 原文地址:https://blog.csdn.net/weixin_42398658/article/details/132869178