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;
}