为什么RANSAC被称为CV界的“多边形战士”?

点击下方卡片,关注「3D视觉工坊」公众号

选择星标,干货第一时间送达

来源:深蓝AI 

添加小助理:dddvision,备注:方向+学校/公司+昵称,拉你入群。文末附行业细分群

扫描下方二维码,加入3D视觉知识星球,星球内凝聚了众多3D视觉实战问题,以及各个模块的学习资料:近20门视频课程(星球成员免费学习)、最新顶会论文、计算机视觉书籍、优质3D视觉算法源码等。想要入门3D视觉、做项目、搞科研,欢迎扫码加入!

5c00ebc9ebfa6e6c9dbf8383efd5f9b9.jpeg

 笔者:William|审核:Los 

RANSAC(RAndom SAmple Consensus,随机采样一致)是一种随机参数估计算法,常常应用于二维图像的拟合、分割等等,由于是估计数学模型参数的迭代算法,因此也被用于三维平面、球的估计,这次笔者将主要介绍其算法原理及在点云拟合、分割及粗配准的代码应用分析,希望能够对读者们的工程研究有所帮助。

8cc7ea3cddec3f68f9efdd6ddd21a208.png

RANSAC算法由Fischler和Bolles于1981年提出,是一种从数据集合中迭代稳健估计模型参数的方法。该算法的基本思想是不断地从数据集合中随机抽取样本集,寻求支持更多局内点的模型参数,然后利用模型余集检验获得的模型参数,通过一定次数的迭代来达到最大的一致性概率,并将该采样样本集作为理解的样本集,且参数解的正确性由样本余集检验支撑。其中数据集合中包含正确数据(即内点inliers)和异常数据(外点outliers)。同时RANSAC假设:在给定一组含有少部分“内点”的数据,存在一个程序可以估计出符合“内点”的模型。

RANSAC的算法比较简单,主要有以下几步:

1)给定一个数据集,从中选择建立模型所需的最小样本数(例如直线最少由两个点确定,所以最小样本数是2,而平面可以根据不共线三点确定,所以最小样本数为3),记选择数据集为;

2)使用选择的数据集计算得到一个数学模型;

3)用计算的模型去测试数据集中剩余的点,如果测试的数据点在误差允许的范围内,则将该数据点判为内点(inlier),否则判为外点(outlier),记所有内点组成的数据集为,表示为的一致性集合;

4)比较当前模型和之前推出的最好的模型的“内点”的数量,记录最大“内点”数量时模型参数和“内点”数量;

5)重复1-4步,直到迭代结束或者当前模型已经足够好了(“内点数目大于设定的阈值”)。

这里的迭代次数可以通过理论推算获得。在一定的置信概率下,其最小样本数与至少取得一个良性采样子集的概率满足:

其中,内点数内点数外点数表示为数据集合中内点概率,是计算模型参数需要的最小数据量。

因此,在基本子集的在迭代次数内,至少有一次采样使得采样子集内的个点均为内点,从而保证在迭代次数中,至少存在一次采样能够取得目标函数的最大值,因此终止循环条件应满足:

b946384210dc6ca71ce02c45c02119cf.png

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

←左右滑动查看完整代码→

2c4e583ca8064698952a7640bccbf577.png

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点云+清华+小草莓), 拉你入群。

dfca802b50842dbb69a13acccc4e832b.png
▲长按扫码添加助理
3D视觉工坊知识星球

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

619f30a366eddd3d25d1517394490204.jpeg
▲长按扫码加入星球
3D视觉工坊官网:www.3dcver.com

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

452ba54848bf7493c22b5b9b5cddf31f.jpeg
▲长按扫码学习3D视觉精品课程
3D视觉相关硬件
图片说明名称
9635885927710df35445c647fa121a91.png硬件+源码+视频教程精迅V1(科研级))单目/双目3D结构光扫描仪
c4e63dbd20f12088d6ca6e817b12fe8f.png硬件+源码+视频教程深迅V13D线结构光三维扫描仪
6c22988db871323f668a4f60f4400944.jpeg硬件+源码+视频教程御风250无人机(基于PX4)
1fe934b68cf8b8ac833a74c3a8f6cae9.png低成本+体积小
+重量轻+抗高反
YA001高精度3D相机
67b15cd07a2c3735d9a2266bfbab3247.png抗高反+无惧黑色+半透明KW-D | 高精度3D结构光
开源相机
3de0df90027f240a727b3fb616bf6291.png硬件+源码‍工坊智能ROS小车
64f4752a68c282f11344772323ff4ea8.png配套标定源码高精度标定板(玻璃or大理石)
添加微信:cv3d007或者QYong2014 咨询更多
—   —

点这里👇关注我,记得标星哦~

一键三连「分享」、「点赞」和「在看」

3D视觉科技前沿进展日日相见 ~ 

outside_default.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值