点击下方卡片,关注「3D视觉工坊」公众号
选择星标,干货第一时间送达
来源:深蓝AI
添加小助理:dddvision,备注:方向+学校/公司+昵称,拉你入群。文末附行业细分群
扫描下方二维码,加入3D视觉知识星球,星球内凝聚了众多3D视觉实战问题,以及各个模块的学习资料:近20门视频课程(星球成员免费学习)、最新顶会论文、计算机视觉书籍、优质3D视觉算法源码等。想要入门3D视觉、做项目、搞科研,欢迎扫码加入!

笔者:William|审核:Los
RANSAC(RAndom SAmple Consensus,随机采样一致)是一种随机参数估计算法,常常应用于二维图像的拟合、分割等等,由于是估计数学模型参数的迭代算法,因此也被用于三维平面、球的估计,这次笔者将主要介绍其算法原理及在点云拟合、分割及粗配准的代码应用分析,希望能够对读者们的工程研究有所帮助。
RANSAC算法由Fischler和Bolles于1981年提出,是一种从数据集合中迭代稳健估计模型参数的方法。该算法的基本思想是不断地从数据集合中随机抽取样本集,寻求支持更多局内点的模型参数,然后利用模型余集检验获得的模型参数,通过一定次数的迭代来达到最大的一致性概率,并将该采样样本集作为理解的样本集,且参数解的正确性由样本余集检验支撑。其中数据集合中包含正确数据(即内点inliers)和异常数据(外点outliers)。同时RANSAC假设:在给定一组含有少部分“内点”的数据,存在一个程序可以估计出符合“内点”的模型。
RANSAC的算法比较简单,主要有以下几步:
1)给定一个数据集,从中选择建立模型所需的最小样本数(例如直线最少由两个点确定,所以最小样本数是2,而平面可以根据不共线三点确定,所以最小样本数为3),记选择数据集为;
2)使用选择的数据集计算得到一个数学模型;
3)用计算的模型去测试数据集中剩余的点,如果测试的数据点在误差允许的范围内,则将该数据点判为内点(inlier),否则判为外点(outlier),记所有内点组成的数据集为,表示为的一致性集合;
4)比较当前模型和之前推出的最好的模型的“内点”的数量,记录最大“内点”数量时模型参数和“内点”数量;
5)重复1-4步,直到迭代结束或者当前模型已经足够好了(“内点数目大于设定的阈值”)。
这里的迭代次数可以通过理论推算获得。在一定的置信概率下,其最小样本数与至少取得一个良性采样子集的概率满足:
其中,内点数内点数外点数表示为数据集合中内点概率,是计算模型参数需要的最小数据量。
因此,在基本子集的在迭代次数内,至少有一次采样使得采样子集内的个点均为内点,从而保证在迭代次数中,至少存在一次采样能够取得目标函数的最大值,因此终止循环条件应满足:
■2.1 拟合
利用上述思想最开始可以进行拟合数据,这里给出C++的点云直线拟合代码及解析:
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/visualization/cloud_viewer.h>
using namespace std;
int main() {
//----------------读取点云数据---------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PCDReader reader;
reader.read<pcl::PointXYZ>("L.pcd", *cloud);
//---------------创建拟合模型---------------------
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
//inliers用来存储直线上点的索引
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
//创建一个分割器对象
pcl::SACSegmentation<pcl::PointXYZ> seg;
seg.setModelType(pcl::SACMODEL_LINE); //设置目标几何形状
seg.setMethodType(pcl::SAC_RANSAC); //拟合方法:随机采样法
seg.setDistanceThreshold(0.05); //设置误差容忍范围(即阈值)
seg.setMaxIterations(500); //最大迭代次数
seg.setInputCloud(cloud); //输入点云
seg.segment(*inliers, *coefficients); //拟合点云
//拟合直线的模型系数为:coefficients
//--------------提取拟合的直线------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr line(new pcl::PointCloud<pcl::PointXYZ>);
pcl::ExtractIndices<pcl::PointXYZ> extract; //创建点云提取对象
extract.setInputCloud(cloud); //设置输入点云
extract.setIndices(inliers); //设置分割后的内点为需要提取的点集
extract.setNegative(false); //false提取内点, true提取外点
extract.filter(*line);
//-----------------点云可视化---------------
pcl::visualization::PCLVisualizer viewer;
viewer.addPointCloud(cloud, "cloud"); // 加载比对点云
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> line_color(line, 255, 0, 0);
viewer.addPointCloud(line, line_color, "line");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "line");
//可视化拟合出来的直线
viewer.addLine(*coefficients, "line");
viewer.spin();
return 0;
}
←左右滑动查看完整代码→
■2.2 分割
分割也是利用拟合数据的思想,代码类似,这里给出主要部分的C++点云直线分割代码及解析:
//--------------------RANSAC分割直线--------
void fitMultipleLines(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, std::vector<pcl::ModelCoefficients>& lineCoff)
{
pcl::PointIndices::Ptr inliers(new pcl::PointIndices());
pcl::SACSegmentation<pcl::PointXYZ> seg; // 创建拟合对象
// 设置对估计模型参数进行优化处理
seg.setOptimizeCoefficients(true);
// 设置拟合模型为直线模型
seg.setModelType(pcl::SACMODEL_LINE);
// 设置拟合方法为RANSAC
seg.setMethodType(pcl::SAC_RANSAC);
// 设置最大迭代次数
seg.setMaxIterations(1000);
seg.setDistanceThreshold(0.1); //判断是否为模型内点的距离阈值
int i = 0, nr_points = cloud->points.size();
int k = 0;
while (k < 5 && cloud->points.size() > 0.1 * nr_points)// 从0循环到5执行6次,并且每次cloud的点数必须要大于原始总点数的0.1倍
{
pcl::ModelCoefficients coefficients;
seg.setInputCloud(cloud); // 输入点云
seg.segment(*inliers, coefficients); //内点的索引
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_line(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr outside(new pcl::PointCloud<pcl::PointXYZ>);
if (inliers->indices.size() > 20) // 小于20则该直线不合格
{
// 将参数保存进vector中
lineCoff.push_back(coefficients);
// 创建点云提取对象
pcl::ExtractIndices<pcl::PointXYZ> extract;
extract.setInputCloud(cloud);
extract.setIndices(inliers);
// 设置为false,表示提取内点
extract.setNegative(false);
extract.filter(*cloud_line);
// true提取外点(该直线之外的点)
extract.setNegative(true);
extract.filter(*outside);
// 将cloud_f中的点云赋值给cloud
cloud.swap(outside);
}
else
{
PCL_ERROR("Could not estimate a line model for the given dataset.\n");
break;
}
std::stringstream ss;
ss << "line_" << i + 1 << ".pcd";
pcl::PCDWriter writer;
writer.write<pcl::PointXYZ>(ss.str(), *cloud_line, false);
i++;
k++;
}
}
cout << "一共拟合出" << LinesCoefficients.size() << "条直线“;
←左右滑动查看完整代码→
■2.3 粗配准
同理,在点云粗配准中也是通过对应点集中随机选取3个对应点对,并求解刚体变换矩阵。然后计算对应点中剩余点对,在上一步所求的刚体变换矩阵的作用下点对的距离误差,若其中一点对的距离误差小于设定的阅值误差,则该点为样本内点,否则为样本外点,并统计前者数目。最后,达到指定选代次数。这里给出C++的点云粗配准代码及解析:
//--------------------RANSAC点云配准--------
pcl::SampleConsensusPrerejective<PointT, PointT, pcl::FPFHSignature33> r_sac;
r_sac.setInputSource(source); // 源点云
r_sac.setInputTarget(target); // 目标点云
r_sac.setSourceFeatures(source_fpfh); // 源点云FPFH特征
r_sac.setTargetFeatures(target_fpfh); // 目标点云FPFH特征
// 选择随机特征对应的邻居的数量,数值越大,特征匹配的随机性越大。
r_sac.setCorrespondenceRandomness(5);
// 所需的(输入的)inlier分数
r_sac.setInlierFraction(0.5f);
// 每次迭代中使用的采样点数量
r_sac.setNumberOfSamples(3);
r_sac.setMaxCorrespondenceDistance(1.0f);// 内点,阈值
r_sac.setMaximumIterations(100); // RANSAC 最大迭代次数
pointcloud::Ptr align(new pointcloud);
r_sac.align(*align);
pcl::transformPointCloud(*source,*align,
r_sac.getFinalTransformation());
cout << "变换矩阵:\n" << r_sac.getFinalTransformation() << endl;
}
←左右滑动查看完整代码→
RANSAC的优点是能鲁棒的估计模型参数。例如,它能从包含大量局外点的数据集中估计出高精度的参数。
RANSAC的缺点是计算参数的迭代次数没有上限;如果设置迭代次数的上限,得到的结果可能不是最优的结果,甚至可能得到错误的结果。且要求设置跟问题相关的阈值。
本文仅做学术分享,如有侵权,请联系删文。
3D视觉工坊交流群
目前我们已经建立了3D视觉方向多个社群,包括2D计算机视觉、大模型、工业3D视觉、SLAM、自动驾驶、三维重建、无人机等方向,细分群包括:
2D计算机视觉:图像分类/分割、目标/检测、医学影像、GAN、OCR、2D缺陷检测、遥感测绘、超分辨率、人脸检测、行为识别、模型量化剪枝、迁移学习、人体姿态估计等
大模型:NLP、CV、ASR、生成对抗大模型、强化学习大模型、对话大模型等
工业3D视觉:相机标定、立体匹配、三维点云、结构光、机械臂抓取、缺陷检测、6D位姿估计、相位偏折术、Halcon、摄影测量、阵列相机、光度立体视觉等。
SLAM:视觉SLAM、激光SLAM、语义SLAM、滤波算法、多传感器融合、多传感器标定、动态SLAM、MOT SLAM、NeRF SLAM、机器人导航等。
自动驾驶:深度估计、Transformer、毫米波|激光雷达|视觉摄像头传感器、多传感器标定、多传感器融合、自动驾驶综合群等、3D目标检测、路径规划、轨迹预测、3D点云分割、模型部署、车道线检测、Occupancy、目标跟踪等。
三维重建:3DGS、NeRF、多视图几何、OpenMVS、MVSNet、colmap、纹理贴图等
无人机:四旋翼建模、无人机飞控等
除了这些,还有求职、硬件选型、视觉产品落地、最新论文、3D视觉最新产品、3D视觉行业新闻等交流群
添加小助理: dddvision,备注:研究方向+学校/公司+昵称(如3D点云+清华+小草莓), 拉你入群。

3D视觉工坊知识星球
3D视觉从入门到精通知识星球、国内成立最早、6000+成员交流学习。包括:星球视频课程近20门(价值超6000)、项目对接、3D视觉学习路线总结、最新顶会论文&代码、3D视觉行业最新模组、3D视觉优质源码汇总、书籍推荐、编程基础&学习工具、实战项目&作业、求职招聘&面经&面试题等等。欢迎加入3D视觉从入门到精通知识星球,一起学习进步。

3DGS、NeRF、结构光、相位偏折术、机械臂抓取、点云实战、Open3D、缺陷检测、BEV感知、Occupancy、Transformer、模型部署、3D目标检测、深度估计、多传感器标定、规划与控制、无人机仿真、三维视觉C++、三维视觉python、dToF、相机标定、ROS2、机器人控制规划、LeGo-LAOM、多模态融合SLAM、LOAM-SLAM、室内室外SLAM、VINS-Fusion、ORB-SLAM3、MVSNet三维重建、colmap、线面结构光、硬件结构光扫描仪,无人机等。

3D视觉相关硬件
点这里👇关注我,记得标星哦~
一键三连「分享」、「点赞」和「在看」
3D视觉科技前沿进展日日相见 ~