手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (1)

这篇具有很好参考价值的文章主要介绍了手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (1)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

首先理清我们需要实现什么功能,怎么实现,提供一份整体逻辑:包括主函数和功能函数

主函数逻辑:

 1. 读图,两张rgb(cv::imread)

 2. 找到两张rgb图中的特征点匹配对

       2.1定义所需要的参数:keypoints1, keypoints2,matches

       2.2 提取每张图像的检测 Oriented FAST 角点位置并匹配筛选(调用功能函数1)

 3. 建立3d点(像素坐标到相机坐标)

        3.1读出深度图(cv::imread)

        3.2取得每个匹配点对的深度

                3.2.1 得到第y行,第x个像素的深度值

                   (ushort d = d1.ptr<unsigned short> (row)[column])

                3.2.2 去除没有深度的点

                3.2.3 转到相机坐标系(调用功能函数2)

4. 调用epnp求解(input:3d点,2d点对,内参,是否去畸变,求解方式)

        4.1求解(cv::solvePnP)

         4.2 求解结果为向量,需要转成矩阵(cv::Rodrigues)

int main( int agrc, char** agrv) {
//  1. 读图(两张rgb)
    Mat image1 = imread(agrv[1] , CV_LOAD_IMAGE_COLOR );
    Mat image2 = imread(agrv[2] , CV_LOAD_IMAGE_COLOR );
    assert(image1.data && image2.data && "Can not load images!");

//  2. 找到两张rgb图中的特征点匹配对
    // 2.1定义keypoints1, keypoints2,matches
    std::vector<KeyPoint>keypoints1,keypoints2;
    std::vector<DMatch>matches;

    // 2.2 提取每张图像的检测 Oriented FAST 角点位置并匹配筛选
    Featurematcher(image1,image2, keypoints1,keypoints2,matches);

//  3. 建立3d点(像素坐标到相机坐标)
    Mat K  = (Mat_<double>(3, 3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);//内参
    vector<Point3f> pts_3d;
    vector<Point2f> pts_2d;

    //3.1读出深度图
    Mat d1 =imread(agrv[3],CV_LOAD_IMAGE_UNCHANGED);
    //3.2取得每个匹配点对的深度(ushort d = d1.ptr<unsigned short> (row)[column];就是指向d1的第row行的第column个数据。数据类型为无符号的短整型 )
    for (DMatch m: matches)
    {
        //3.2.1 得到第y行,第x个位置的像素的深度值
        ushort d = d1.ptr<unsigned short>(int (keypoints1[m.queryIdx].pt.y)) [int(keypoints1[m.queryIdx].pt.x)];
        // 3.2.2 去除没有深度的点
        if(d==0){
            continue;
        }
       float dd=d/5000.0 ;
       //3.2.3 转到相机坐标系
       Point2d p1 = pixtocam(keypoints1[m.queryIdx].pt , K);
        pts_3d.push_back(Point3f(p1.x*dd,p1.y*dd,dd));
        pts_2d.push_back(keypoints2[m.trainIdx].pt);
    }
    cout << "3d-2d pairs: " << pts_3d.size() << endl;

//  4. 调用epnp求解(input:3d点,2d点对,内参,false,求解方式)
            // solvePnP( InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int flags = SOLVEPNP_ITERATIVE );
        Mat r,t;
        // 4.1求解
        solvePnP(pts_3d,pts_2d,K,Mat(), r,t,false,SOLVEPNP_EPNP);
        // 4.2 求解结果为向量,需要转成矩阵
        Mat R;
        cv::Rodrigues(r,R);
        cout<<"R="<<R<<endl;
        cout<<"T="<<t<<endl;

// 5.可视化匹配
        Mat img_goodmatch;
        drawMatches(image1, keypoints1, image2, keypoints2, matches, img_goodmatch);
        imshow("good matches", img_goodmatch);
        waitKey(0);
        return 0;
}

功能函数1:  Featurematcher

实现过程在前几篇中已经详细说明:视觉slam14讲 逐行解析代码 ch7 / orb_cv.cpp

2.2.1初始化存储特征点数据的变量

2.2.2 提取每张图像的检测 Oriented FAST 角点位置

2.2.3 计算图像角点的BRIEF描述子

2.2.4 根据刚刚计算好的BRIEF描述子,对两张图的角点进行匹配

2.2.5 匹配点对筛选计算最小距离和最大距离

2.2.6 当描述子之间的距离大于两倍的最小距离时,即认为匹配有误.但有时候最小距离会非常小,设置一个经验值30作为下限.

void Featurematcher( const Mat &image1, const Mat &image2, std::vector<KeyPoint>&keypoints1, std::vector<KeyPoint> &keypoints2,  std::vector<DMatch> &matches){
    // 2.2.1初始化存储特征点数据的变量
        Mat descr1, descr2;
        Ptr<FeatureDetector> detector = ORB::create();
        Ptr<DescriptorExtractor> descriptor = ORB::create();
        Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");

        // 2.2.2 提取每张图像的检测 Oriented FAST 角点位置
        detector->detect(image1, keypoints1);
        detector->detect(image2, keypoints2);

        // 2.2.3 计算图像角点的BRIEF描述子
        descriptor->compute(image1, keypoints1, descr1);
        descriptor->compute(image2, keypoints2, descr2);

        // 2.2.4 根据刚刚计算好的BRIEF描述子,对两张图的角点进行匹配
        std::vector<DMatch> match;
        matcher->match(descr1, descr2, match);

        Mat img_match;
        drawMatches(image1, keypoints1, image2, keypoints2, match, img_match);
        imshow("all matches", img_match);
        waitKey(0);

        // 2.2.5 匹配点对筛选计算最小距离和最大距离
        double min_dis = 10000, max_dis = 0;
        // 2.2.5.1找出所有匹配之间的最小距离和最大距离, 即是最相似的和最不相似的两组点之间的距离
        for (int i = 0; i < descr1.rows; i++)
        {
        double dist = match[i].distance;
        if (dist < min_dis)
            min_dis = dist;
        if (dist > max_dis)
            max_dis = dist;
        }
    cout<<"max_dis="<<max_dis<<endl;
    cout<<"min_dis="<<min_dis<<endl;

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

功能函数2:

将输入的像素坐标(x ,y)转化到归一化相机坐标系下得到(X,Y)

我们知道:相机的投影模型为:, 即

所以      ,   

Point2d pixtocam(const  Point2d &p ,  const Mat  &K){
    return Point2d(
        // X=(u-cx)/fx
        (p.x - K.at<double>(0,2)) / K.at<double>(0,0) ,
        // Y=(v-cy)/fy
        (p.y-K.at<double>(1,2)) / K.at<double>(1,1)
    );
}

最后匹配效果及位姿结果:

allmatch:

手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (1),视觉slam十四讲,SLAM,c++,计算机视觉

goodmatch:

手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (1),视觉slam十四讲,SLAM,c++,计算机视觉

位姿输出:R,T:手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (1),视觉slam十四讲,SLAM,c++,计算机视觉

下一篇介绍 如何用非线性优化g2o的BA来求解位姿:(2)文章来源地址https://www.toymoban.com/news/detail-692508.html

到了这里,关于手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (1)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 视觉SLAM十四讲——ch9实践(后端1)

    Ceres BA使用的是BAL数据集。在本例中,使用problem-16-22106-pre.txt文件。 BAL的数据集自身存在的特殊 BAL的相机内参模型由焦距f和畸变参数k1,k2给出。 因为BAL数据在投影时假设投影平面在相机光心之后,所以按照我们之前用的模型计算,需要在投影之后乘以系数-1。 安装meshlab,

    2024年02月09日
    浏览(46)
  • CH7-广播机制

    熟悉 广播机制的概述 ,能够归纳广播机制的实现流程 掌握 广播接收者的创建方式 ,能够独立创建广播接收者 掌握 自定义广播的方式 ,能够通过自定义广播实现饭堂小广播案例 熟悉 广播的类型 ,能够归纳 有序广播 与 无序广播 的工作流程 ​ 在Android系统中, 广播是一种

    2024年02月05日
    浏览(26)
  • 踩坑 Sophus 模板库安装及编译(视觉SLAM 十四讲第二版 ch4 )

    在《视觉slam十四讲》第二版中,第4、7、8、9、10讲都需要Sophus库,因此我们需要安装Sophus库,并且需要的是Sophus模板库,因此很多人因为安装了非模板版本导致报错,下面提供Sophus模板版本安装方式,以及对应不报错版本。 只要是 3.3以上的版本即可 官网进入,然后下载T

    2024年01月22日
    浏览(61)
  • 【SLAM14讲】02 视觉SLAM基本架构

    根据安装位置分为两类: 携带于机器人本体 上的传感器,比如激光传感器、相机、轮式编码器、惯性测量单元(Inertial Measurement Unit, IMU)等等,它们测到的通常都是一些间接的物理量而不是直接的位置数据。例如, 轮式编码器会测到轮子转动的角度、IMU 测量运动的角速度和

    2024年02月12日
    浏览(63)
  • 视觉SLAM14讲笔记-第7讲-视觉里程计2

    直接法的引出 直接法是视觉里程计另一个主要分支,它与特征点法有很大的不同。 使用特征点法估计相机运动时,我们把特征点看作固定在三维空间的不动点。根据它们在相机中的投影位置,通过 最小化重投影误差 来优化相机运动。 相对地,在直接法中,我们并不需要知

    2024年02月09日
    浏览(34)
  • 视觉SLAM14讲笔记-第10讲-后端1

    我们可以看到,前端视觉里程计能给出一个短时间内的轨迹和地图,但由于不可避免的误差累积,这个地图在长时间内是不准确的。所以怎么办?我们人类自己在现实世界中会记录自己走了多少米,还有就是使用路面的标志物来辅助定位,和机器人的方式也是相同的,即同时

    2024年02月09日
    浏览(32)
  • 视觉SLAM14讲笔记-第3讲-三维空间刚体运动

    空间向量之间的运算包括: 数乘、加法、减法、内积、外积。 内积 :可以描述向量间的投影关系,结果是一个标量。 a ⃗ ⋅ b ⃗ = ∑ i = 1 3 a i b i = ∤ a ∤ ∤ b ∤ c o s ⟨ a , b ⟩ vec{a} cdot vec{b}=sum_{i=1}^3{{a _i}{b_i}} =nmid a nmid nmid b nmid cos langle a,b rangle a ⋅ b = i = 1 ∑ 3 ​

    2024年02月11日
    浏览(47)
  • 视觉SLAM14讲笔记-第4讲-李群与李代数

    李代数 的引出: 在优化问题中去解一个旋转矩阵,可能会有一些阻碍,因为它对加法导数不是很友好(旋转矩阵加上一个微小偏移量可能就不是一个旋转矩阵),因为旋转矩阵本身还有一些约束条件,那样再求导的过程中可能会破坏要优化的矩阵是旋转矩阵的本质条件,所

    2024年02月10日
    浏览(33)
  • SynergyNet(头部姿态估计 Head Pose Estimation)复现 demo测试

    SynergyNet(github):https://github.com/choyingw/SynergyNet b站:https://www.bilibili.com/video/BV1Ph4y1k7LK/ 我用的AutoDL平台搭建 选择镜像 PyTorch 1.9.0 Python 3.8(ubuntu18.04) Cuda 11.1 安装其它包: 备注:如果无法下载,就到github中下载压缩包,然后上传解压安装 或者使用码云下载: 需要下载如下文件

    2024年02月14日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包