slambook2+ch7+pose_estimation_2d2d+估计多张图像之间的位姿

2023-05-16

算法

  1. 计算第一张图和第二张图的关键点并匹配
  2. 以第一张图的相机坐标为世界坐标,计算第二张图相对第一张图的旋转矩阵、平移矩阵
  3. 不断更新第一张图,在进行第二次计算时,以第二张图为第一张图,以第二张图的相机坐标系为世界坐标系

代码

//
// Created by automobile on 2020/7/19.
//
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <chrono>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#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(
        Mat &img_1,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(){
    //--读取图像
   // cv::String path = "/home/automobile/wcm/database/1080img" ;
    cv::String path = "/home/automobile/wcm/database/img_data" ;
    std::vector<cv::String> filenames;
    //cv::glob()读取文件夹中数据
    cv::glob(path, filenames);

    if (filenames.size() == 0){
        cout << "NO image files [png]" << endl;
    }

    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();

    //--寻找关键点,计算描述子,匹配关键点
    vector<KeyPoint> keypoints_1, keypoints_2;
    vector<DMatch> matches;
    Mat img_1, img_2;
    Mat R, t;

    Mat K = (Mat_<double>(3,3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);//给相机内参数矩阵赋值


    //开始计算文件夹下的图像之间的位姿
   for (int size = filenames.size() - 1 ; size > 0; size-- ){
   //开始读取图像
   Mat img_1 = cv::imread(filenames[size]);
   Mat img_2 = cv::imread(filenames[size - 1]);
   assert(img_1.data && img_2.data && "Cannot load images");

    //匹配特征点
    find_feature_matches(img_1, img_2, keypoints_1, keypoints_2, matches);

    //估计两张图像间相机运动
   pose_estimation_2d2d(keypoints_1, keypoints_2, matches, R, t);
   cout <<  "位姿估计 i= " << size << endl;


    //--验证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
        );
    cout << "对第 " << size << " t^R= " << t_x * R << endl;



    /*
    //验证对极约束
    cout << "对第 " << size << " 验证对极约束 " << endl;
    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;
        cout << " epipolar constraint = " << d <<endl;
        }
        */

    }


    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> poseEstimation_2d2d = chrono::duration_cast<chrono::duration<double>>(t2 - t1);

    cout << "estimate 100 pose cost = " << poseEstimation_2d2d.count() << " seconds." <<endl;

   return 0;
}


//像素坐标与相机坐标转换
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 find_feature_matches(Mat &img_1, Mat &img_2,
                         std::vector<KeyPoint> &keypoints_1,
                         std::vector<KeyPoint> &keypoints_2,
                         std::vector<DMatch> &matches
                         ){
   //--初始化
   Mat descriptors_1, descriptors_2;
   //used in OpenCV3
   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描述子进行匹配,使用Hamming距离
   vector<DMatch> match;
   BFMatcher(NORM_HAMMING);
   matcher->match(descriptors_1, descriptors_2, match);

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

   //找出所有匹配之间的最小距离和最大距离,既是最相似和最不相似的两组点之间的距离
   for (int num = 0; num < descriptors_1.rows; num++){
       double dist = match[num].distance;
       if (dist < min_dist) min_dist = dist;
       if (dist > max_dist) max_dist = dist;
   }

   printf(" --Max dist : %f \n", max_dist);
   printf(" --Min dist : %f \n", min_dist);

   //当描述子之间距离大于两倍最小距离时,即认为匹配有误。但有时候最小距离会非常小,设置一个经验值30作为下限
   for (int num1 = 0; num1 < descriptors_1.rows; num1++){
       if (match[num1].distance <= max(2 * min_dist, 30.0)){
           matches.push_back(match[num1]);
       }
   }
}

void pose_estimation_2d2d(
       std::vector<KeyPoint> &keypoints_1,
       std::vector<KeyPoint> &keypoints_2,
       std::vector<DMatch> &matches,
       Mat &R, Mat &t
){
    cout << "进入pose-estimation" << endl;

   //相机内参。TUM Freiburg2
   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;

  // cout << "matches.size = " << matches.size() << endl;
   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].queryIdx].pt);
   }

   //--计算基础矩阵
   //使用像素坐标计算基础矩阵
   //CV_FM_8POINT采用8点法
   Mat fundamental_matrix;
   fundamental_matrix = findFundamentalMat(points1, points2, CV_FM_RANSAC_ONLY);
   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;

   //--从本质矩阵中恢复旋转和平移信息
   //SVD奇异值分解
   //此函数仅在OpenCV3中提供
   recoverPose(essential_matrix, points1, points2, R, t, focal_length, principal_point);
   cout << "R is " << endl << R << endl;
   cout << "t is " << endl << t <<endl;

}

运行结果

homography_matrix is 
[-0.6227391139971105, -2.886970200092988, 364.1872697938189;
 -0.2148405971333806, -0.972686679720263, 126.9249350232471;
 -0.001631390801007104, -0.007687557320241691, 0.9999999999999999]
R is 
[0.3194695470556352, 0.4729054474713082, -0.8211575039272485;
 0.4490655530003259, -0.8386377196567202, -0.3082643415601096;
 -0.8344335429574837, -0.2702724790298453, -0.4802847587280729]
t is 
[0.2296954847355427;
 -0.1516112670155564;
 0.9613813020888443]
位姿估计 i= 2
对第 2 t^R= [-0.3052136993786365, 0.8472269758895471, 0.3691761548756424;
 0.4987976662552955, 0.5167228229363109, -0.6791262298784655;
 0.1515835126764352, -0.1209335034643769, -0.1953036569510742]
 --Max dist : 85.000000 
 --Min dist : 5.000000 
进入pose-estimation
 fundamental_matrix is 
[-6.255652045940543e-06, 1.679691660890056e-05, -0.0005118221938695405;
 -5.358345603116775e-05, 0.0001784510571767766, -0.005452954314486946;
 0.01061051013232514, -0.03275577826825726, 1]
essential_Matrix is 
[0.004266503965144853, -0.6636712990779564, -0.1952643925552019;
 0.6959001651454869, -0.03315309018943863, 0.04331212815465878;
 0.1142026543150515, 0.1367396083384311, 0.04900965516181151]
homography_matrix is 
[-1.133399786845522, 0.2333755152279524, 382.6506100442739;
 -0.3823145696849643, 0.07505512543265744, 129.6483054540828;
 -0.002966733373018169, 0.0006222148878302129, 1]
R is 
[0.9606504274809822, -0.072697821483587, 0.2680779418977755;
 0.03923589585057277, 0.9909803233208437, 0.1281348635919174;
 -0.2749750909762716, -0.1125745332766574, 0.9548380353757032]
t is 
[0.2068527047159039;
 -0.159673994852563;
 0.9652544607094746]
位姿估计 i= 1
对第 1 t^R= [0.006033747771430509, -0.9385729521138152, -0.2761455522001097;
 0.9841514516064251, -0.04688554978048633, 0.06125259905155897;
 0.1615069425913533, 0.1933790086257947, 0.0693101190170626]
estimate 100 pose cost = 57.3466 seconds.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

slambook2+ch7+pose_estimation_2d2d+估计多张图像之间的位姿 的相关文章

随机推荐

  • 一文掌握FastDeploy Serving服务化部署(打造线上证件照制作系统,含完整代码)

    目录 一 概述1 1 服务化部署1 2 FastDeploy简介 二 搭建线上证件照制作系统2 1 准备环境2 1 1 安装Docker2 1 2 安装NVIDIA Container Toolkit2 1 3 获取FastDeploy S
  • 部署散记1(增强)

    拉取modelscope镜像 span class token function sudo span span class token function docker span pull registry cn hangzhou aliyu
  • 图形化深度学习开发平台PaddleStudio(代码开源)

    目录 一 PaddleStudio概述二 环境准备2 1 安装PaddlePaddle2 2 安装依赖库 三 基本使用介绍3 1 启动3 2 快速体验3 2 1 下载示例项目3 2 2 训练3 2 3 评估3 2 4 测试3 2 5 静态图
  • 一款免费的人像修图工具(笨擦擦)

    推荐一个我们自己开发的免费人像修图工具 xff1a 笨擦擦 使用这个工具可以免费抠图 美颜 证件照制作 我们是一群因为兴趣聚在一起的 二哈 程序员 xff0c 我们没资金 没大佬 没资质 xff0c 但就是喜欢做一些有意思的事 笨擦擦 是我
  • 利用Python生成和识读二维码(QR Code)和微二维码(Micro QR Code)

    目录 一 环境准备二 二维码 xff08 QR Code xff09 生成和读取2 1 生成二维码2 2 读取二维码 三 微二维码 xff08 Micro QR Code xff09 生成和读取3 1 生成微二维码3 2 读取微二维码 之前
  • 贴图问题,opengl,linux,windows,消除锯齿,摩尔纹,yuv 还是 rgb

    1 消除锯齿和摩尔纹 windows下使用d3d是很方便的 xff0c 基本不用设置很多东西 xff0c 就可以做到 xff0c 所以windows上最好使用d3d 但是linux上有所不同 摩尔条纹是两条线或两个物体之间以恒定的角度和频率
  • QT基础(五)----QPainter高级功能

    一 场景和窗口 头文件MyWidget h ifndef MYWIDGET H define MYWIDGET H include lt QWidget gt include lt QGraphicsScene gt 场景 include
  • DSP28335 高速modbus代码实现

    程序特点 不使用while循环速度尽可能快速除去程序运行时间 xff0c 没有多余等待时间优化CRC校验方式 头文件modbus h span class token macro property span class token dire
  • matlab 画图时遇到的一些问题以及解决方法

    matlab 画图时遇到的一些问题以及解决方法 最近在使用 matlab 画图时 xff0c 遇到了许许多多各式各样的问题 xff0c 有些问题甚至折腾了很久才搞好 xff0c 特此记录下来 设置画图时图中线段的粗细plot x1 y1 3
  • Ubuntu18.04上Gazebo安装和使用

    一 基本介绍 Gazebo是一款与机器人开发相关的3D动态模拟仿真软件 xff0c 能够在复杂的室内和室外环境中准确有效地模拟机器人群 这款软件中包含了丰富的机器人模型 xff0c 环境库以及各种各样的传感器 xff0c 并且在操作方面它的
  • Python运行 import cv2 等报错 Illegal instruction (core dumped) 解决办法

    import cv2 报错 Illegal instruction core dumped nanopc T4 开发板上安装好 opencv 后 xff0c import cv2 时 会报错 Illegal instruction core
  • 多个py文件同时执行(多进程与多线程实现)

    本人在编写python程序时 xff0c 需要多个py文件在不同终端内同时运行 xff0c 从而配合实现某种功能 xff0c 经过多方查找与实验 xff0c 排除了很多无法使用的方案 xff0c 最终确定了以下两个方案 xff0c 现将其记
  • nanopc-T4 开发板通过USB麦克风采集录制音频

    文章目录 1 使用 nanopc T4 开发板采集音频2 使用 Tyless外置usb麦克风录制声音3 使用 ffrmpeg 将实时视频与音频合并并推流到 rtmp 服务器中4 成功实现opencv采集图像与音频合并推送到rtmp 1 使用
  • 北京超级云计算中心操作训练指南

    北京超级云计算中心操作指南 本人在实验室做深度学习图像领域相关研究 xff0c 前期使用实验室的设备 2080Ti xff0c 运行时间较慢 xff1b 跑一轮需要6个小时以上 xff1b 后来开始使用超算 xff0c 运行速度比实验室快多
  • windows to go 和 linux to go 制作教程

    文章目录 使用 ventoy 制作windows to go 和 linux to go 教程 xff0c 将系统装进U盘中随身携带1 ventoy 介绍2 准备工作3 windows to go3 1 将 U盘初始化3 2 虚拟磁盘安装
  • 使用nps搭建内网穿透并配置泛域名解析

    使用nps搭建内网穿透并配置泛域名解析 前言1 准备工作2 服务器端搭建nps并配置2 1 配置nps配置文件2 2 docker安装nps2 3 web端配置nps并使用 3 客户端使用nps4 配置泛域名解析5 参考链接 前言 nps是
  • web内外网判断界面

    因日常需要 xff0c 我们在实验室内网中部署了一个服务 xff0c 在校园网内都能正常访问 xff0c 同时配置了内网穿透服务 xff0c 实现外网也能正常访问 但外网访问毕竟是通过内网穿透实现 xff0c 稳定性与网速都有限制 xff0
  • 为无登陆鉴权功能的接口与网站添加登陆鉴权功能

    1 缘由 本人部分服务的测试接口为方便日常测试调试 xff0c 使用了 ip 43 端口 的形式进行访问 xff0c 并且未配置账号密码鉴权机制 在日常测试一段时间后 xff0c 终于还是收到了来自腾讯云的监管通知 xff0c 说服务存在数
  • RoboMaster机器人运行教程(一)

    1 环境配置 系统 xff1a ubuntu16 04 xff0c 安装ROS 2 基础学习 需要C 43 43 和python基础 xff0c 和ROS的基础知识 xff0c 网上有很多教程 xff0c 推荐知乎大佬教程 xff1a 我的
  • slambook2+ch7+pose_estimation_2d2d+估计多张图像之间的位姿

    算法 计算第一张图和第二张图的关键点并匹配以第一张图的相机坐标为世界坐标 xff0c 计算第二张图相对第一张图的旋转矩阵 平移矩阵不断更新第一张图 xff0c 在进行第二次计算时 xff0c 以第二张图为第一张图 xff0c 以第二张图的相