RANSAC 配准算法

RANSAC 配准算法

  • 1. 简介
  • 2. RANSAC步骤
  • 3. RANSAC原理
  • 4. RANSAC的优缺点
  • 5. 代码实现
  • 6. 参考

1. 简介

先讲一下背景吧。

点云配准(Point Cloud Registration)指的是输入两幅点云 (source 和 target) ,输出一个变换使得变换后的sourcetarget的重合程度尽可能高。

点云配准可以分为粗配准(Coarse Registration)和精配准(Fine Registration)两步。粗配准指的是在两幅点云之间的变换完全未知的情况下进行较为粗糙的配准,目的主要是为精配准提供较好的变换初值;精配准则是给定一个初始变换,进一步优化得到更精确的变换。

而今天我们所要讲的内容就是RANSAC 粗配准算法。RANSAC即Random Sample Consensus,随机采样一致算法。

2. RANSAC步骤

RANSAC算法的核心思想是随机性和假设性。 请记住这句话。

随机性用于减少计算,循环次数是利用正确数据出现的概率。

而假设性,就是说随机抽出来的数据都认为是正确的,并以此去计算其他点,获得其他满足变换关系的点,然后利用投票机制,选出获票最多的那一个变换。

RANSAC广义上讲,是随机选择一个小的数据点子集,然后对其进行拟合,查看有多少其他点匹配到拟合的模型上,迭代这个过程直至有较大的概率找到我们想要拟合的模型。

在点云配准这个应用中,使用 RANSAC 方法,就是在源点云中随机找不共线的三个点,去“蒙”他们和目标点云中的哪三个点相对应,然后计算变换矩阵,并验证是否为最优的变换矩阵。简要流程如下:

  1. 在源点云中随机选择 3 个点。
  2. 分别查找他们在目标点云中特征向量最接近的点。这里的“接近”是欧式距离意义下的,查询数据结构使用 KD 树。当然,这里最接近的点会很多,我们为了在最快的时间内得到最终更好的匹配,通常会加一些约束,比如每组点的连线形成一个三角形,三角形的边不能太短、两个三角形的对应边长不能差太多、优先选择特征向量远离均值的点等等;
  3. 假设2中最接近的点是正确的,计算两组点之间的变换矩阵。本质是求最小二乘法意义下的最优变换矩阵。
  4. 求出源点云在此变换之后的点云,计算其与目标点云的重合度(定义为源点云中阈值半径内存在目标点的点的个数)。
  5. 回到1,重复若干次,返回重合度最高的变换。

以上,RANSAC其实是一种不确定的算法,即有一定的概率得出一个合理的结果,当然也会出现错误的结果。他为了提高时间效率不会去遍历每一个可能性,只是采取随机采样的方式,得到这些随机采样中的最好的结果,这个最好的结果也许是错误的结果,这里面就涉及到概率。如果要提高概率,一个要提高迭代的次数,在一个就是减少数据集离群点的比例。

因此,问题来了,在这算法流程中存在两个重要的参数需要设置,迭代次数(采样次数)和阈值。

迭代的次数我们应该选择多大呢?这个值是否可以事先知道应该设为多少呢?还是只能凭经验决定呢?

我们要剔除离群点 ,需要事先设定阈值,当模型具有明显的物理意义时,这个阈值还比较容易设定,但是若模型比较抽象时,阈值就不那么容易设定了,而且固定阈值不适用于样本动态变化的应用。那我们该怎么设置这个阈值呢?

3. RANSAC原理

我们先从一个小例子开始。

假设我们主观上看出了两个图像之间的点匹配,并且我们认为可以用一些参数去表示两者之间的变换,那么我们该如何去得到这个变换参数呢?

通常的策略是用最小二乘法去估计点之间的关系,但是会存在一个问题,如下图所示:
在这里插入图片描述
像这种离群点其实是不能很好拟合我们的模型的。能够拟合模型的点称为inliers,离群点称为outlier。
在这里插入图片描述
最小二乘估计对这些离群点很敏感,因此一些outlier可能会对结果进行扭曲,如下图所示。
在这里插入图片描述
而且,最小二乘估计只能估计出一个模型,如果存在两个或多个模型,也会对结果进行扭曲。
在这里插入图片描述

因此,为了解决以上问题,需要将估计视为一个两阶段过程:
– 将数据点分类为outlier或inlier
– 将模型拟合到inlier,同时忽略outlier

RANSAC可以解决以上问题,

比如我们要拟合的模型是一条直线,一条直线两个点就可以确定,因为我们需要随机采样两个点,如下图所示。
在这里插入图片描述
我们给一个阈值去评估这个模型,在这个阈值内,有4个点圈进来了。
在这里插入图片描述
如果换其他的采样点呢?
在这里插入图片描述

此时 ,有6个点圈进来了。
在这里插入图片描述
我们再一次迭代,
在这里插入图片描述
此时,有19个点圈进来了。

在这里插入图片描述
继续迭代。
在这里插入图片描述
此时,有13个点圈进来了。
在这里插入图片描述
在这几次迭代中 ,第三次圈进来的点数最多,我们可以认为第三次是目前这几次迭代中的最优解。
在这里插入图片描述
那么,整个算法流程如下,
在这里插入图片描述
那么,回到我们最开始的问题,我们怎么去选择迭代次数N呢?
在这里插入图片描述
注:outlier的概率e通常是一个先验值,P 是我们希望RANSAC得到正确模型的概率。如果事先不知道e的值,可以使用自适应迭代次数的方法。也就是一开始设定一个无穷大的迭代次数,然后每次更新模型参数估计的时候,用当前的outlier比值当成e来估算出迭代次数。

那么我们怎么去选择阈值呢? 通常来说,我们是根据经验去选择。好吧,确实太抽象了,这个就需要多做实验,多try。

4. RANSAC的优缺点

RANSAC的优点是它能鲁棒的估计模型参数。例如,它能从包含大量局外点的数据集中估计出高精度的参数。

RANSAC的缺点是它计算参数的迭代次数没有上限;如果设置迭代次数的上限,得到的结果可能不是最优的结果,甚至可能得到错误的结果。RANSAC只有一定的概率得到可信的模型,概率与迭代次数成正比。RANSAC的另一个缺点是它要求设置跟问题相关的阀值。

RANSAC只能从特定的数据集中估计出一个模型,如果存在两个(或多个)模型,RANSAC不能找到别的模型。

RANSAC可以对局外点进行剔除,这一点是比较好的,但它也并不是完美的,虽然缺点有这么多,但是我们还是离不开它。

5. 代码实现

PCL 库中以随机采样一致性算法( RANSAC) 为核心,实现了五种类似于RANSAC的随机参数估计算法,例如随机采样一致性估计(RANSAC ) 、最大似然一致性估计 (MLESAC ) 、最小中值方差一致性估计 ( LMEDS )等,所有的估计参数算法都符合一致性准则。利用RANSAC可以实现点云分割,目前 PCL 中支持的几何模型分割有 空间平面、直线、二维或三维圆、圆球、锥体等 。 RANSAC的另一应用就是点云的配准对的剔除。

下面用opencv进行代码示例。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/features2d/features2d.hpp>
void extracte_orb(cv::Mat input,std::vector<cv::KeyPoint> &keypoint,cv::Mat &descriptor){
    cv::Ptr<cv::ORB> f2d = cv::ORB::create(500);
    f2d->detect(input,keypoint);
    cv::Mat image_with_kp;
    f2d->compute(input,keypoint,descriptor);
    cv::drawKeypoints(input, keypoint, image_with_kp, cv::Scalar::all(-1),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
    cv::imwrite("orb"+std::to_string(random())+".png",image_with_kp);
}

void match_two_image(cv::Mat image1,cv::Mat image2, std::vector<cv::KeyPoint> keypoint1,std::vector<cv::KeyPoint> keypoint2,cv::Mat descriptor1,cv::Mat descriptor2){
    cv::BFMatcher matcher(cv::NORM_HAMMING);
    std::vector<cv::DMatch> matches;
    matcher.match(descriptor1,descriptor2, matches);
    cv::Mat good_matches_image;
    cv::drawMatches(image1, keypoint1, image2, keypoint2,
                    matches, good_matches_image, cv::Scalar::all(-1), cv::Scalar::all(-1),
                    std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    cv::imwrite("good_matches_image.png",good_matches_image);
    {
        std::vector <cv::KeyPoint> RAN_KP1, RAN_KP2;
        std::vector<cv::Point2f> keypoints1, keypoints2;
        for (int i = 0; i < matches.size(); i++) {
            keypoints1.push_back(keypoint1[matches[i].queryIdx].pt);
            keypoints2.push_back(keypoint2[matches[i].trainIdx].pt);
            RAN_KP1.push_back(keypoint1[matches[i].queryIdx]);
            RAN_KP2.push_back(keypoint2[matches[i].trainIdx]);
        }

        std::vector<uchar> RansacStatus;
        cv::findFundamentalMat(keypoints1, keypoints2, RansacStatus, cv::FM_RANSAC);
        std::vector <cv::KeyPoint> ransac_keypoints1, ransac_keypoints2;
        std::vector <cv::DMatch> ransac_matches;
        int index = 0;
        for (size_t i = 0; i < matches.size(); i++)
        {
            if (RansacStatus[i] != 0)
            {
                ransac_keypoints1.push_back(RAN_KP1[i]);
                ransac_keypoints2.push_back(RAN_KP2[i]);
                matches[i].queryIdx = index;
                matches[i].trainIdx = index;
                ransac_matches.push_back(matches[i]);
                index++;
            }
        }
        cv::Mat after_ransac_sift_match;
        cv::drawMatches(image1, ransac_keypoints1, image2, ransac_keypoints2,
                        ransac_matches, after_ransac_sift_match, cv::Scalar::all(-1), cv::Scalar::all(-1),
                        std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
        cv::imwrite("after_ransac_orb_match.png",after_ransac_sift_match);
    }
}

int main(int argc, char *argv[])
{
    cv::Mat image1 = cv::imread(argv[1]);
    cv::Mat image2 = cv::imread(argv[2]);
    std::vector<cv::KeyPoint> keypoint1,keypoint2;
    cv::Mat descriptor1, descriptor2;
    extracte_orb(image1,keypoint1,descriptor1);
    extracte_orb(image2,keypoint2,descriptor2);
    match_two_image(image1,image2,keypoint1,keypoint2,descriptor1,descriptor2);
    return 0;
}

OpenCV RANSAC的效果展示
在这里插入图片描述

6. 参考

Robust Estimation : RANSAC
04-随机采样一致性算法RANSAC
RANSAC

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/567209.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

管理 Python 项目的艺术:在 PyCharm 中使用虚拟环境(以BPnP为例)

在 PyCharm 中使用虚拟环境对于 Python 项目开发具有多方面的重要作用&#xff0c;这些作用体现在提升项目管理的效率、保障代码的可运行性以及维护项目的长期稳定性等方面。以下是使用虚拟环境的几个关键好处&#xff1a; 1. 依赖管理和隔离 虚拟环境允许每个项目拥有…

深度相机(3D相机)

传统的RGB彩色相机称为2D相机&#xff0c; 只能得到2D的图像信息&#xff0c; 无法得到物体与相机的距离信息&#xff0c;也就是深度信息。 顾名思义&#xff0c; 深度相机除了获取2D信息&#xff0c;还能得到深度信息&#xff0c;也叫RGBD相机&#xff0c; 或3D相机。 顺便提…

CSS介绍及三种应用方式[内联,内嵌,外链]元素及实例讲解

css介绍 CSS&#xff08;Cascading Style Sheets&#xff09;是一种用于描述HTML文档外观和格式的样式表语言。CSS允许开发者和设计师将网页的呈现&#xff08;布局、颜色、字体等&#xff09;与内容&#xff08;HTML&#xff09;分离开来&#xff0c;从而使得网页的设计更加灵…

vue2+vxe-table实现表格增删改查+虚拟滚动

vue2vxe-table实现表格增删改查虚拟滚动 使用的vxe-table版本&#xff1a;v3.x (vue 2.6 长期维护版) 完整代码 <template><div><vxe-toolbar ref"xToolbar" export :refresh"{query: findList}"><template #buttons><vxe-b…

vulhub weblogic全系列靶场

目录 简介 需要使用的工具 CVE-2017-10271 0x00 漏洞产生原因 0x01 影响范围 0x02 漏洞地址 0x03 环境 0x04 漏洞复现 1. 手工 2. 漏洞利用工具 CVE-2018-2628 0x00 漏洞产生原因 0x01 影响范围 0x02 环境 0x03 漏洞复现 1.nmap扫是否是T3协议 2.漏洞检测&…

【C++】详解初始化列表,隐式类型转化,类静态成员,友元

前言 初始化列表是对构造函数内容的补充&#xff0c;小编会详细的讲解初始化列表的概念&#xff0c;特性&#xff0c;注意点。这是本篇内容的重头戏&#xff0c;小编会先提一个问题来抛砖引玉。 隐式类型转换顾名思义&#xff0c;首先它不需要主动转换&#xff0c;类似于把浮点…

抖音运营全攻略 沈阳新媒体运营培训

抖音发展趋势 数据显示&#xff0c;2023年&#xff0c;抖音日活量突破10亿。是目前最火的短视频软件。 抖音的总用户数量已超过12亿&#xff0c;日活10亿&#xff0c;人均单日使用时长超过2小时&#xff0c;这只是平均数据&#xff0c;其实大部分人刷抖音时间会超过3个小时&am…

Hive数据类型

1.基本数据类型 示例&#xff1a; -- 创建表并定义列的数据类型 CREATE TABLE data_types_example (tinyint_column TINYINT,smallint_column SMALLINT,int_column INT,bigint_column BIGINT,boolean_column BOOLEAN,float_column FLOAT,double_column DOUBLE,string_column S…

HSB矩形调色板设计和计算方法

HSB矩形调色板设计和计算方法 RGB调色板绘制较容易&#xff0c;HSB调色板较难绘制&#xff0c;前些天发文介绍了几个矩形样例的绘制方法&#xff0c;今介绍矩形的HSB调色板的设计方法和H,S,B值的计算方法&#xff0c;好东西必须与大家分享。 此文介绍HSB调色板和选色条的绘制方…

jdbc操作数据库 and 一个商品管理页面

文章目录 1. 介绍1.1 应用知识介绍1.2 项目介绍 2. 文件目录2.1 目录2.2 介绍以下&#xff08;从上到下&#xff09; 3. 相关代码3.1 DBConnection.java3.2 MysqlUtil.java3.3 AddServlet.java3.4 CommodityServlet.java3.5 DelectServlet.java3.6 SelectByIdServlet.java3.7 S…

Springboot 结合PDF上传到OSS

目录 一、首先注册阿里云OSS&#xff08;新用户免费使用3个月&#xff09; 二、步骤 2.1 将pdf模板上传到oos 2.2 这里有pdf地址,将读写权限设置为共工读 ​编辑 三、代码 3.1 pom.xml 3.2 配置文件 3.3 oss model 3.4 配置类(不需要修改) 3.5 将配置类放入ioc容器 3.…

【C++】:构造函数和析构函数

目录 前言一&#xff0c;构造函数**1.1 什么是构造函数****1.2 构造函数的特性**1.3 总结 二&#xff0c;析构函数**2.1 什么是析构函数****2.2 析构函数的特性****2.3 总结** 前言 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并…

JetBrains PhpStorm v2024.1 安装教程 (PHP集成开发IDE)

前言 PhpStorm是由JetBrains推出的一款轻量级集成开发环境&#xff0c;专为PHP开发者而设计。该软件融合了智能的HTML/CSS/JavaScript/PHP编辑器、代码质量分析工具、版本控制系统集成&#xff08;包括SVN和GIT&#xff09;、调试和测试等功能。除此之外&#xff0c;PhpStorm还…

画图的神器及必备的调色和选图工具

大学生研究生论文写作及画图的神器 前言常用的工具集合画图工具配色参考画图神器词云 最后下篇 前言 好久没有更博&#xff0c;来更一下吧。最近刚好被问到平常是用什么来画图的&#xff0c;包括会议论文&#xff0c;各种类型的PPT汇报以及项目报告等等里面的图怎么画好。所以…

CSS动画(css、js动画库:各种动画效果)

第一种方法&#xff1a;文字从上到下显示动画&#xff1b; <div class"text-container"><div class"text">文字从上到下显示</div></div><style scoped> /*确保 keyframes 规则在引用它的任何选择器之前定义&#xff0c;以避…

Linux服务器网络问题排查思路

服务器网络问题排查 一.测试是否能ping通其他服务器 ping <其他电脑的IP>如图是网段互通的情况 如图是不互通的情况 该命令是最常用的命令&#xff0c;主要功能如下&#xff1a; 网络连通性&#xff1a; ping 用于检查两台主机之间是否可以相互通信。如果目标主机可达…

DB索引B+树SQL优化

数据库的索引就像一本书的目录&#xff0c;查数据快人一步&#xff0c;快速定位&#xff0c;精准打击&#xff01; 什么是数据库的索引&#xff1f; 官方介绍索引是帮助MySQL高效获取数据的数据结构。更通俗的说&#xff0c;数据库索引好比是一本书前面的目录&#xff0c;能加…

invidia-smi占用显存,无法显示PID

如果是动用了子线程创建进程&#xff0c;比如利用accelerate训练脚本&#xff0c;那么大概率可以通过这种方式解决&#xff1a;nvidia-smi没有进程&#xff0c;但是显存占用_nvidia-smi有的卡是0%-CSDN博客 如果这种方法不可用&#xff0c;请尝试直接查询所有python进程&#x…

BI建设案例:FineBI大数据分析平台助力工程机械行业降本增效

工程机械行业作为国民经济的重要支柱&#xff0c;产品多样化、应用广泛&#xff0c;市场集中度高。其上游涉及原材料和核心零部件&#xff0c;下游则与房地产、基建工程和采矿等行业紧密相连。 如今&#xff0c;中国已崛起为全球工程机械制造大国&#xff0c;各类机械产品产量…

关于MCU核心板的一些常见问题

BGA植球与焊接&#xff08;多涂焊油&#xff09;&#xff1a; 【BGA芯片是真麻烦&#xff0c;主要是植锡珠太麻烦了&#xff0c;拆一次就得重新植】https://www.bilibili.com/video/BV1vW4y1w7oNvd_source3cc3c07b09206097d0d8b0aefdf07958 / NC电容一般有两种含义&#xff1…