通过两张图片实现2D-2D对极几何位姿估计

对极几何方法——2D图片特征点估计运动 E为3×3的矩阵,有9个未知数。为了便于计算只考虑它的尺度等价性(即矩阵同时除以其中一个未知数,可以使得这个未知数变成1,这样的E也是等价的,从而可以减少一个未知数),使用8对点来估计E——这就是经典的。由于E和F只相差了相机内参,而内参在SLAM中通常是已知的,所以实践中往往使用形式更简单的E。考虑一对匹配点,它们的归一化坐标为x1=[u1,v1,1]T,x2=[u2,v2,1]T。同理,对于其他点对也有相同的表示。如果这八个点互不相关,即系数满秩,那么E的各元素就可由上述方程解得。 阅读详情

需要安装opencv3并且编译了features模块

代码中的1.png

代码中的2.png

// 来自高翔SLAM十四讲
#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/calib3d/calib3d.hpp>

using namespace std;
using namespace cv;

/*
    2D-2D的特征匹配估计相机运动
*/


void find_feature_matches(
    const Mat& img_1,  const Mat& img_2,
    std::vector<KeyPoint>& keypoints_1,
    std::vector<KeyPoint>& keypoints_2,
    std::vector<DMatch>& matches);

void pose_estimation_2d2d(
    std::vector<KeyPoint> keypoints_1,
    std::vector<KeyPoint> keypoints_2,
    std::vector<DMatch> matches,
    Mat& R, Mat& t);

    // 像素坐标转相机归一化坐标
    Point2d pixel2cam(const Point2d& p, const Mat& K);

int main(){
    // 读取图像
    Mat img_1 = imread("1.png", CV_LOAD_IMAGE_COLOR);
    Mat img_2 = imread("2.png", CV_LOAD_IMAGE_COLOR);
    
    vector<KeyPoint> keypoints_1, keypoints_2;
    vector<DMatch> matches;
    find_feature_matches(img_1, img_2, keypoints_1, keypoints_2, matches);
    cout<<"一共找到了"<<matches.size()<<"组匹配点"<<endl;

    // 估计两张图像之间的运动
    Mat R,t;
    pose_estimation_2d2d(keypoints_1, keypoints_2, matches, R, t);

    // 验证E=t^R*scale
    Mat t_x = (Mat_<double>(3,3) <<
                            0,          -t.at<double>(2,0),         t.at<double>(1,0),
                            t.at<double>(2,0),      0,                  -t.at<double>(0,0),
                            -t.at<double>(1,0),     t.at<double>(0,0),      0);
    // 这个t^R就是essential矩阵(本质矩阵),但是相差一个倍数
    cout<<"t^R = "<<endl<<t_x * R<<endl;

    // 验证对极约束
    Mat K = (Mat_<double>(3,3)<<520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);
    for(DMatch m:matches){
        Point2d pt1 = pixel2cam(keypoints_1[m.queryIdx].pt, K);
        Mat y1 = (Mat_<double>(3,1)<<pt1.x, pt1.y, 1);
        Point2d pt2 = pixel2cam(keypoints_2[m.trainIdx].pt, K);
        Mat y2 = (Mat_<double>(3,1) << pt2.x, pt2.y, 1);
        Mat d = y2.t() * t_x * R * y1;
        // 验证对极约束,理论上这个d应该是近似为0的
        cout<<"epipolar constraint = "<<d<<endl;
    }
    return 0;
}

// 找到匹配的特征点
void find_feature_matches(const Mat& img_1, const Mat& img_2,
                                        std::vector<KeyPoint>& keypoints_1,
                                        std::vector<KeyPoint>& keypoints_2,
                                        std::vector<DMatch>& matches){
    // 初始化
    Mat descriptors_1, descriptors_2;
    Ptr<FeatureDetector>detector = ORB::create();
    Ptr<DescriptorExtractor>descriptor = ORB::create();
    Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");   // 暴力匹配

    // 第一步:检测Oriented FAST角点位置
    detector->detect(img_1, keypoints_1);
    detector->detect(img_2, keypoints_2);

    // 第二步: 根据角点位置计算BRIEF描述子
    descriptor->compute(img_1, keypoints_1, descriptors_1);
    descriptor->compute(img_2, keypoints_2, descriptors_2);

    // 第三步:对两幅图像中的BRIEF描述子进行匹配,使用汉明距离
    vector<DMatch> match;
    matcher->match(descriptors_1, descriptors_2, match);

    // 第四步:对匹配点对进行筛选
    double min_dist = 10000, max_dist = 0;

    // 找出所有匹配之间的最小距离和最大距离
    // 即是最相似和最不相似的两组点之间的距离
    for(int i=0; i<descriptors_1.rows; i++){
        double dist = match[i].distance;
        min_dist = min_dist<dist?min_dist:dist;
        max_dist = max_dist>dist?max_dist:dist;
    }
    printf("--Max dist : %f\n", max_dist);
    printf("--Min dist : %f \n", min_dist);

    // 当描述子之间的距离大于两倍的最小距离时,即认为匹配有误
    // 设置30为阈值
    for(int i=0; i<descriptors_1.rows; i++){
        if(match[i].distance <= max(2*min_dist, 30.0)){
            matches.push_back(match[i]);
        }
    }
}

Point2d pixel2cam(const Point2d& p, const Mat& K){
    return Point2d(
        (p.x - K.at<double>(0,2))/K.at<double>(0,0),
        (p.y - K.at<double>(1,2))/K.at<double>(1,1)
    );
}

void pose_estimation_2d2d(std::vector<KeyPoint>keypoints_1,
                                                std::vector<KeyPoint>keypoints_2,
                                                std::vector<DMatch>matches,
                                                Mat&R ,Mat& t){
    // 相机内参,TUM Feriburg2
    Mat K = (Mat_<double>(3,3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);

    // 把匹配点转化为vector<Point2f>的形式
    vector<Point2f>points1;
    vector<Point2f>points2;

    for(int i=0; i<(int)matches.size(); i++){
        points1.push_back(keypoints_1[matches[i].queryIdx].pt);
        points2.push_back(keypoints_2[matches[i].trainIdx].pt);
    }

    // 计算基础矩阵:使用的8点法,但是书上说8点法是用来计算本质矩阵的呀,这两个有什么关系吗
    // 答:对于计算来说没有什么区别,本质矩阵就是基础矩阵乘以一个相机内参
    // 多于8个点就用最小二乘去解
    Mat fundamental_matrix;
    fundamental_matrix = findFundamentalMat(points1, points2, CV_FM_8POINT);    // Eigen库计算会更快一些
    cout<<"fundamental_matrix is "<<endl<<fundamental_matrix<<endl;

    // 计算本质矩阵:是由对极约束定义的:对极约束是等式为零的约束
    Point2d principal_point(325.1, 249.7);  // 相机光心,TUM dataset标定值
    double focal_length = 521;      // 相机焦距,TUM dataset标定值
    Mat essential_matrix;
    essential_matrix = findEssentialMat(points1, points2, focal_length, principal_point);
    cout<<"essential_matrix is "<<endl<<essential_matrix<<endl;

    // 计算单应矩阵:通常描述处于共同平面上的一些点在两张图像之间的变换关系
    Mat homography_matrix;
    homography_matrix = findHomography(points1, points2, RANSAC, 3);
    cout<<"homography_matrix is "<<endl<<homography_matrix<<endl;

    // 从不本质矩阵中恢复旋转和平移信息
    // 这里的R,t组成的变换矩阵,满足的对极约束是:x2 = R * x1 + t,是第一个图到第二个图的坐标变换矩阵x2 = T21 * x1
    recoverPose(essential_matrix, points1, points2, R, t, focal_length, principal_point);
    cout<<"R is "<<endl<<R<<endl;
    cout<<"t is "<<endl<<t<<endl;
}

 

【视觉 SLAM】2D-2D:对极几何 本文为视觉 SLAM 学习总结,讲解 2D-2D 对极几何。欢迎交流 阅读详情

相关推荐

slam 2d-2d对极几何(四)

一、2D-2D对极几何介绍 二、2D-2D求解步骤 1、通过两张图片中像素坐标转换求出本质矩阵E,基础矩阵F 本质矩阵E 基础矩阵F 相机姿态 1.根据像素位置求E,F 2.根据E,F求R,T 求本质矩阵E 1.E乘以非零常数对极约束依然满...

m0_58173801的博客 1332

【svopro】图像对齐align2D

【代码】【svopro】图像对齐align2D。

格物致知 679

计算机视觉基础——相机运动位姿估计

文章目录运动估计前提假设对极几何约束随机抽样一致算法三角测量 运动估计前提假设 求解相机运动估计我们先有问题求解的前提假设: 相机运动估计的步骤如下: 最后我们可以通过这种方式进行3D点的重建。 对极几何约束 线性代数表达在第二个照相机视角下的图像里epipolar line 的表达(证明略) l′=(K′)T[t]xRK−1ml'=(K')^T[t]_xRK^{-1}ml′=(K′)T[t]x​RK−1m 随机抽样一致算法 异常值对于运动估计的结果有不可忽略的影响,我们之前学过的最小二乘法拟合函数对于

weixin_44991673的博客 1985

全景图像拼接——相机参数评估

一、项目名称:全景图像拼接 二、语言、库和开发环境:C++、opencv249、VS2013 三、参考 1:博客https://blog.youkuaiyun.com/zhaocj/article/details/78799194?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_releva...

tiantangzixue的博客 3014

【从零开始学习SLAM】2D-2D 两张图像匹配的特征点求解位置姿态

文章目录算法解析源码解读 算法解析 对极几何约束:当相机为单目时,我们只知道2D的像素坐标,因而问题是根据两组2D点估计运动。 单个图像中的像素,只能提供物体与相机成像平面的角度以及物体采集到的亮度,而无法提供物体的距离(Range)。 使用单目相机,利用移动相机之后进行三角化,测量像素的距离。 基础矩阵(Fundamental Matrix) F 和本质矩阵(Essential Matrix) E, 当相机为单目时,我们只知道2D像素坐标,因而问题是根据两组2D点估计运动RT,该问题用对极几何解决。

小秋 AI SLAM 入门实战教程 2602

基于两帧间图象的相机姿态估计方法.pptx

根据视觉十四讲中第七讲为框架,自制的介绍多试图几何的讲义。介绍了基于单目摄像机采集到的多帧图像,实现相机的位姿估计。介绍了対级几何,三角测量,八点法,P3P,ICPSVD分解。对于上述方法的理论推导完善且详尽,对于求解问题用到的算法进行了简明的整理。是学习SLAM前端特征点法的好资料。

相机位姿估计3:根据两幅图像的位姿估计结果求某点的世界坐标

关键词:相机位姿估计,单目尺寸测量,环境探知 用途:基于相机的环境测量,SLAM,单目尺寸测量 文章类型:原理说明、Demo展示 @Author:VShawn @Date:2016-11-28 @Lab: CvLab202@CSU 目录 《相机位姿估计0:基本原理之如何解PNP问题》 《相机位姿估计1:根据四个特征点估计相机姿态》 《相机位姿估计1_1:OpenCV:...

weixin_30436891的博客 1546

C++计算位姿之间的相对变换矩阵

输入是两帧的位姿放入qw,qc,tw,tc中,记住qw,qc里的第一个参数是TUM GroundTruth里位姿的最后一项,输出是两帧的变换矩阵T,下载就能用。

视觉里程计——基于特征点的位姿估计

视觉里程计--基于特征点的位姿估计

举个栗子的博客 2504

Silvaco 学习笔记——物理模型:载流子产生复合模型

对载流子的复合机制进行总结

reactortiger的博客 1万+

幸狐RV1106开发板实战:5分钟搞定Yolo8模型部署(附避坑指南)

本文详细介绍了在幸狐RV1106开发板上快速部署YOLOv8模型的实战流程。通过RKNN-Toolkit2工具链,将ONNX模型转换为RV1106 NPU专用的RKNN格式,并完成交叉编译与上板运行。文章重点分享了环境搭建、模型转换的关键步骤以及常见的避坑指南,帮助开发者高效实现边缘AI目标检测应用。

weixin_28677451的博客 912

SLAM十四讲-ch7(2)-位姿估计(包含2d-2d、3d-2d、3d-3d、以及三角化实现代码的注释)

1、利用2d-2d进行位姿估计 源码如下: // // #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/features2d/features2d.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/calib3d/calib3d.hpp> using namespace std;

joun772的博客 2441

Multisim实战:从零搭建体温检测报警电路(附完整仿真文件+调试技巧)

本文详细介绍了如何使用Multisim从零搭建体温检测报警电路,涵盖LM35温度传感器、LM358运算放大器等核心器件的选型与连接,以及信号调理、阈值比较和数码管显示等关键电路设计。附赠完整仿真文件和实用调试技巧,帮助电子工程初学者快速掌握体温温度检测系统的设计与实现。

weixin_28285943的博客 292

【菜狗学三维重建】Slam对极几何实战—从两张未知相机内参的图片计算出来相机Rt——20250413

对极几何实战

weixin_53796634的博客 917

实战分享:如何用本地替换和插桩调试搞定Kasada最新版x-kpsdk-cd环境检测

本文深入解析Kasada最新版x-kpsdk-cd环境检测机制,提供动态请求拦截、本地替换和函数插桩等实战调试策略。通过Proxy保护破解、关键函数断点调试和环境检测对抗方案,帮助逆向工程师有效应对从280位扩展到294位的加密数组挑战,实现高效补环境调试。

weixin_29251567的博客 569

安卓手机必备:Auto.js快手极速版自动刷视频避坑指南(含最新3.0脚本)

本文是一份安卓自动化工具Auto.js的全面实践指南,重点解析了如何搭建稳定运行环境、配置关键权限以及管理脚本。针对快手极速版等应用的自动化需求,文章详细介绍了设备选择、Auto.js版本对比、各品牌手机后台保活设置,并强调了脚本安全与调试技巧,帮助用户有效避坑,实现自动化任务的稳定执行。

i7j8k9l的博客 782

实现两张图片的叠加

看了好多网上的图片叠加,说的最多的就是水印效果,但是我需要做的是两张图片完全重合的叠加,但是我的情况有点特殊,一张图片是从远程生成的,一张图片是本地生成的,所以在读图片的时候方法不一样,今天终于完成了,废话不多说,上代码: 首先是一个根据url网络网络url函数: public static BufferedImage RequestImage(String imageurl) throws

Sampson的专栏 6156

基于 51 单片机的智能手势控制小车设计与实现

智能手势控制小车以STC89C52RC 单片机为控制核心,通过手势识别模块采集用户手势指令,经单片机处理后驱动电机执行前进、后退、左转、右转等动作。该项目融合了传感器技术、单片机编程和电机驱动技术,具有成本低、易实现、互动性强的特点,适合作为嵌入式系统入门实践案例。本项目成功实现了基于 51 单片机的智能手势控制小车,通过 APDS-9960 模块采集手势信号,经单片机处理后驱动电机完成基本动作,验证了 “传感器 + 单片机 + 执行器” 的嵌入式系统设计思路。

weixin_42300449的博客 178

unity——合并两张图片

要对两张图片进行叠加,只需要将背景图片中对应的像素颜色,替换成另一张图片的像素颜色就行了 public void CaptureScreenShot() { StartCoroutine(CaptureCoroutine()); } private IEnumerator CaptureCoroutine() { yield retu...

Wmayy_123的博客 3302

17.6 LangSmith 私有化部署实战指南:企业级AI应用的安全基石

LangSmith 私有化部署, 企业级AI开发平台, 数据隐私合规, 混合云架构, 模型监控与审计。

yonggeit的博客 3777

IMEI引起的无法驻网问题

问题不复杂,场景很简单,如上图,UE在进行LTE attach过程时,在送完NAS security mode complete后,就立刻收到了网络attach reject 带cause 6 Illegal ME,根据协议描述这个cause 代表ME不被网络可接受,例如ME在禁止名单或者黑名单中就会有这种cause。然而前方在报这个问题的时候,也是知道SIM卡和手机IMEI在运营商那边没能成功绑定,然后才报的问题,要查看手机是不是有问题...... 告诉前方原因后,还认为是手机问题,告知要继续查。

asd199086的博客 1426

2D-2D:对极几何估计姿态

1.对极几何 从2张图片中,得到若干个配对好的2d特征点,就可以运用对极几何来恢复出两帧之间的运动. 设P的空间坐标为: \(P=[X,Y,Z]^{T}\) 两个像素点\(p_{1},p_{2}\)的像素坐标为: \(s_{1}p_{1}=KP, s_{2}p_{2}=K(RP+t)\) K为相机内参,R,t为图像1到图像2的旋转矩阵和平移矩阵. 取\(x_{1}=k^{-1}p...

penuel 821

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

java实现把两张图片合并

package cn.com.bmsoft.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.

孤雁是天的寂寞 1万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

java 两张图片合并_java实现把两张图片合并(Graphics2D)

package com.yin.text;import java.awt.Graphics2D;import java.awt.image.BufferedImage;import java.io.File;import java.io.IOException;import javax.imageio.ImageIO;/*** 把两张图片合并* @version 2018-2-27 上午11:12...

weixin_35693911的博客 2168

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

对极几何-Epipolar Geometry

对极几何

761527200_leili的博客 2515

特征点法slam中位姿估计方法总结

这篇博客主要是对基于特征点匹配的slam中的位姿估计方法进行总结。 2d-2d的位姿估计 一般用在单目slam的初始阶段,系统还没有地图,此时只有输入的2D的图片序列。一般会使用如下方法进行位姿估计。而RGBD与双目系统中,无需进行初始化。 首先通过对极约束求解出本质矩阵(比较经典的有八点法),然后对本质矩阵进行奇异值分解(SVD),求解出R与t; 原理公式(对极约束) 通过单应约束求解出单应矩阵,然后通过对单应矩阵进行分解求解出R与t; 原理公式 (单应约束) 这两种方法有...

sky的博客 2726
上一篇: ORB特征点匹配
下一篇: 利用三角测量计算帧间特征点的空间位置
rdc01234
博客等级 码龄9年 10粉丝 156原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值