• 手撕 视觉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 (row)[column])

                    3.2.2 去除没有深度的点

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

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

            4.1求解(cv::solvePnP)

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

    1. int main( int agrc, char** agrv) {
    2. // 1. 读图(两张rgb)
    3. Mat image1 = imread(agrv[1] , CV_LOAD_IMAGE_COLOR );
    4. Mat image2 = imread(agrv[2] , CV_LOAD_IMAGE_COLOR );
    5. assert(image1.data && image2.data && "Can not load images!");
    6. // 2. 找到两张rgb图中的特征点匹配对
    7. // 2.1定义keypoints1, keypoints2,matches
    8. std::vectorkeypoints1,keypoints2;
    9. std::vectormatches;
    10. // 2.2 提取每张图像的检测 Oriented FAST 角点位置并匹配筛选
    11. Featurematcher(image1,image2, keypoints1,keypoints2,matches);
    12. // 3. 建立3d点(像素坐标到相机坐标)
    13. Mat K = (Mat_<double>(3, 3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);//内参
    14. vector pts_3d;
    15. vector pts_2d;
    16. //3.1读出深度图
    17. Mat d1 =imread(agrv[3],CV_LOAD_IMAGE_UNCHANGED);
    18. //3.2取得每个匹配点对的深度(ushort d = d1.ptr (row)[column];就是指向d1的第row行的第column个数据。数据类型为无符号的短整型 )
    19. for (DMatch m: matches)
    20. {
    21. //3.2.1 得到第y行,第x个位置的像素的深度值
    22. ushort d = d1.ptr<unsigned short>(int (keypoints1[m.queryIdx].pt.y)) [int(keypoints1[m.queryIdx].pt.x)];
    23. // 3.2.2 去除没有深度的点
    24. if(d==0){
    25. continue;
    26. }
    27. float dd=d/5000.0 ;
    28. //3.2.3 转到相机坐标系
    29. Point2d p1 = pixtocam(keypoints1[m.queryIdx].pt , K);
    30. pts_3d.push_back(Point3f(p1.x*dd,p1.y*dd,dd));
    31. pts_2d.push_back(keypoints2[m.trainIdx].pt);
    32. }
    33. cout << "3d-2d pairs: " << pts_3d.size() << endl;
    34. // 4. 调用epnp求解(input:3d点,2d点对,内参,false,求解方式)
    35. // solvePnP( InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int flags = SOLVEPNP_ITERATIVE );
    36. Mat r,t;
    37. // 4.1求解
    38. solvePnP(pts_3d,pts_2d,K,Mat(), r,t,false,SOLVEPNP_EPNP);
    39. // 4.2 求解结果为向量,需要转成矩阵
    40. Mat R;
    41. cv::Rodrigues(r,R);
    42. cout<<"R="<
    43. cout<<"T="<
    44. // 5.可视化匹配
    45. Mat img_goodmatch;
    46. drawMatches(image1, keypoints1, image2, keypoints2, matches, img_goodmatch);
    47. imshow("good matches", img_goodmatch);
    48. waitKey(0);
    49. return 0;
    50. }

    功能函数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作为下限.

    1. void Featurematcher( const Mat &image1, const Mat &image2, std::vector&keypoints1, std::vector &keypoints2, std::vector &matches){
    2. // 2.2.1初始化存储特征点数据的变量
    3. Mat descr1, descr2;
    4. Ptr detector = ORB::create();
    5. Ptr descriptor = ORB::create();
    6. Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming");
    7. // 2.2.2 提取每张图像的检测 Oriented FAST 角点位置
    8. detector->detect(image1, keypoints1);
    9. detector->detect(image2, keypoints2);
    10. // 2.2.3 计算图像角点的BRIEF描述子
    11. descriptor->compute(image1, keypoints1, descr1);
    12. descriptor->compute(image2, keypoints2, descr2);
    13. // 2.2.4 根据刚刚计算好的BRIEF描述子,对两张图的角点进行匹配
    14. std::vector match;
    15. matcher->match(descr1, descr2, match);
    16. Mat img_match;
    17. drawMatches(image1, keypoints1, image2, keypoints2, match, img_match);
    18. imshow("all matches", img_match);
    19. waitKey(0);
    20. // 2.2.5 匹配点对筛选计算最小距离和最大距离
    21. double min_dis = 10000, max_dis = 0;
    22. // 2.2.5.1找出所有匹配之间的最小距离和最大距离, 即是最相似的和最不相似的两组点之间的距离
    23. for (int i = 0; i < descr1.rows; i++)
    24. {
    25. double dist = match[i].distance;
    26. if (dist < min_dis)
    27. min_dis = dist;
    28. if (dist > max_dis)
    29. max_dis = dist;
    30. }
    31. cout<<"max_dis="<
    32. cout<<"min_dis="<
    33. //2.2.6 当描述子之间的距离大于两倍的最小距离时,即认为匹配有误.但有时候最小距离会非常小,设置一个经验值30作为下限.
    34. for (int i = 0; i < descr1.rows; i++)
    35. {
    36. if (match[i].distance<= max(2*min_dis,30.0))
    37. {
    38. matches.push_back(match[i]);
    39. }
    40. }
    41. cout<<"matches.size="<size()<
    42. }

    功能函数2:

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

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

    \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}=\begin{bmatrix} f_{x} &0&c_x\\ 0&f_y&c_y\\ 0&0&1 \end{bmatrix} \begin{bmatrix} X \\ Y \\ 1 \end{bmatrix}

    所以 X=(x-c_x)/f_x     ,    Y=(y-c_y)/f_y

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

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

    allmatch:

    goodmatch:

    位姿输出:R,T:

    下一篇介绍 如何用非线性优化g2o的BA来求解位姿:(2)

  • 相关阅读:
    chapter four in C primer plus
    python基础语言:tuple(元组)
    UI案例——登陆系统
    九、多项式朴素贝叶斯算法(Multinomial NB,Multinomial Naive Bayes)(有监督学习)
    系列十二、强引用、软引用、弱引用、虚引用分别是什么?
    葡萄糖-聚乙二醇-阿奇霉素,Azithromycin-PEG-Glucose
    Paper - Zotero 论文管理 以及 订阅最新 蛋白质结构预测(PSP) 领域论文
    python+vue+elementui旅游信息管理系统pycharm源码
    在Jupyter Notebook中使用Matplotlib(Anaconda3)
    二十三种设计模式全面解析-解密迭代器模式:探索遍历之道
  • 原文地址:https://blog.csdn.net/weixin_62952541/article/details/132603926