RANSAC简介
RANSAC(RAndom SAmple Consensus,随机采样一致)算法是从一组含有“外点”(outliers)的数据中正确估计数学模型参数的迭代算法。
“外点”一般指的的数据中的噪声,比如说匹配中的误匹配和估计曲线中的离群点。所以,RANSAC也是一种“外点”检测算法。RANSAC算法是一种不确定算法,它只能在一种概率下产生结果,并且这个概率会随着迭代次数的增加而加大。
- “内群”(inlier, 即正常数据)数据可以通过几组模型的参数来叙述其分布,而“离群”(outlier,似乎译为外点群更加妥当,异常数据)数据则是不适合模型化的数据。
- 数据会受噪声影响,噪声指的是离群,例如从极端的噪声或错误解释有关数据的测量或不正确的假设。
- RANSAC假定,给定一组(通常很小)的内点群,存在一个程序,这个程序可以估算最佳解释或最适用于这一数据模型的参数。
算法基本思想和流程
RANSAC是通过反复选择数据集去估计出模型,一直迭代到估计出认为比较好的模型。
具体的实现步骤可以分为以下几步:
- 选择出可以估计出模型的最小数据集;(对于直线拟合来说就是2个点,对于平面拟合就是3个点)
- 使用这个数据集来计算出数据模型;
- 将所有数据带入这个模型,计算出“内点”的数目;(累加在一定误差范围内的适合当前迭代推出模型的数据)
- 比较当前模型和之前推出的最好的模型的“内点“的数量,记录最大“内点”数的模型参数和“内点”数;
- 重复1-4步,直到迭代结束或者当前模型已经足够好了(“内点数目大于一定数量”)。
RANSAC筛除地面点云
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/segmentation/sac_segmentation.h>int main()
{// 读取点云数据pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);pcl::io::loadPCDFile<pcl::PointXYZ>("input_cloud.pcd", *cloud);// 创建地面分割对象pcl::SACSegmentation<pcl::PointXYZ> seg;pcl::PointIndices::Ptr inliers(new pcl::PointIndices);pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);// 设置地面分割参数seg.setOptimizeCoefficients(true);seg.setModelType(pcl::SACMODEL_PLANE);seg.setMethodType(pcl::SAC_RANSAC);seg.setMaxIterations(1000);seg.setDistanceThreshold(0.01);// 执行地面分割seg.setInputCloud(cloud);seg.segment(*inliers, *coefficients);// 创建提取器对象pcl::ExtractIndices<pcl::PointXYZ> extract;pcl::PointCloud<pcl::PointXYZ>::Ptr ground_cloud(new pcl::PointCloud<pcl::PointXYZ>);// 提取地面点云extract.setInputCloud(cloud);extract.setIndices(inliers);extract.setNegative(false);extract.filter(*ground_cloud);// 提取非地面点云pcl::PointCloud<pcl::PointXYZ>::Ptr non_ground_cloud(new pcl::PointCloud<pcl::PointXYZ>);extract.setNegative(true);extract.filter(*non_ground_cloud);// 保存结果pcl::io::savePCDFile<pcl::PointXYZ>("ground_cloud.pcd", *ground_cloud);pcl::io::savePCDFile<pcl::PointXYZ>("non_ground_cloud.pcd", *non_ground_cloud);std::cout << "地面点云保存成功!" << std::endl;return 0;
}