使用cv::findFundamentalMat要注意的几点

转自http://blog.sina.com.cn/s/blog_4298002e01013w9a.html

在新版的OpenCV中,非常多C代码都被又一次封装成了C++代码,对应的其调用接口也发生了改变,而文档中的叙述也越来越不清楚,往往导致使用过程中出现各种问题。

在处理立体图像对的时候经常会用到对极几何的知识,计算基础矩阵也是非经常见的事。OpenCV实现了基本矩阵的算法。对于老版本号的C代码,计算基本矩阵的RANSAC方法中有一个迭代次数不收敛的bug。可能导致每次计算的採样次数都达到最大限制的次数。其根源在于计算採样可信度的公式有误,新版本号的代码还没有细致看过,不敢确定是否已经修正了这个bug。可是这个bug并不会对最后的结果造成多大影响,仅仅是会影响计算的效率——原本几次採样就可以结束迭代。在这个bug的影响下可能要採样数百次。

新版本号的计算基本矩阵的函数的使用也有一些问题,以下来看看cv::findFundamentalMat函数:

//! the algorithm for finding fundamental matrix
enum
{
    FM_7POINT = CV_FM_7POINT, //!< 7-point algorithm
    FM_8POINT = CV_FM_8POINT, //!< 8-point algorithm
    FM_LMEDS = CV_FM_LMEDS,  //!< least-median algorithm
    FM_RANSAC = CV_FM_RANSAC  //!< RANSAC algorithm
};

//! finds fundamental matrix from a set of corresponding 2D points
CV_EXPORTS Mat findFundamentalMat( const Mat& points1, const Mat& points2,
                                     CV_OUT vector<uchar>& mask, int method=FM_RANSAC,
                                     double param1=3., double param2=0.99 );

//! finds fundamental matrix from a set of corresponding 2D points
CV_EXPORTS_W Mat findFundamentalMat( const Mat& points1, const Mat& points2,
                                     int method=FM_RANSAC,
                                     double param1=3., double param2=0.99 );

上面是OpenCV计算基本矩阵的C++接口,其内部实现仍然是调用的C代码函数。不过在上层进行了一次封装。网上有些文档中说const Mat& points1和points2这两个參数能够直接由vector<Point2f>类型作为传入參数,事实上这是错误的。

直接用vector<Point2f>传递,在编译时可能不会报错,可是执行时会直接崩溃。

由于cv::Mat的构造函数并不会把Point2f转化为两个浮点数存于Mat的两个元素中,而是仍然以Point2f存于Mat的一个元素中。于是findFundamentalMat一读取这个Mat就会出错。

因此我们最好老老实实地去构建Mat points1和Mat points2。该矩阵的维度能够是2xN,也能够是Nx2的,当中N是特征点的数目。还有一个要注意的地方就是该矩阵的类型不能是CV_64F,也就是说findFundamentalMat内部解析points1和points2时是依照float类型去解析的。设为CV_64F将导致读取数据失败,程序崩溃。最好设为CV_32F。

以下是从匹配好的特征点计算F的代码演示样例:

// vector<KeyPoint> m_LeftKey;
// vector<KeyPoint> m_RightKey;

// vector<DMatch> m_Matches;

// 以上三个变量已经被计算出来,各自是提取的关键点及其匹配,以下直接计算F

// 分配空间

int ptCount = (int)m_Matches.size();
Mat p1(ptCount, 2, CV_32F);
Mat p2(ptCount, 2, CV_32F);

// 把Keypoint转换为Mat

Point2f pt;
for (int i=0; i<ptCount; i++)
{
     pt = m_LeftKey[m_Matches[i].queryIdx].pt;
     p1.at<float>(i, 0) = pt.x;
     p1.at<float>(i, 1) = pt.y;
  
     pt = m_RightKey[m_Matches[i].trainIdx].pt;
     p2.at<float>(i, 0) = pt.x;
     p2.at<float>(i, 1) = pt.y;
}

// 用RANSAC方法计算F

// Mat m_Fundamental;

// 上面这个变量是基本矩阵

// vector<uchar> m_RANSACStatus;

// 上面这个变量已经定义过,用于存储RANSAC后每一个点的状态

m_Fundamental = findFundamentalMat(p1, p2, m_RANSACStatus, FM_RANSAC);

// 计算野点个数

int OutlinerCount = 0;
for (int i=0; i<ptCount; i++)
{
     if (m_RANSACStatus[i] == 0) // 状态为0表示野点
     {
          OutlinerCount++;
     }
}

// 计算内点

// vector<Point2f> m_LeftInlier;
// vector<Point2f> m_RightInlier;
// vector<DMatch> m_InlierMatches;

// 上面三个变量用于保存内点和匹配关系

int InlinerCount = ptCount - OutlinerCount;
m_InlierMatches.resize(InlinerCount);
m_LeftInlier.resize(InlinerCount);
m_RightInlier.resize(InlinerCount);
InlinerCount = 0;
for (int i=0; i<ptCount; i++)
{
     if (m_RANSACStatus[i] != 0)
     {
          m_LeftInlier[InlinerCount].x = p1.at<float>(i, 0);
          m_LeftInlier[InlinerCount].y = p1.at<float>(i, 1);
          m_RightInlier[InlinerCount].x = p2.at<float>(i, 0);
          m_RightInlier[InlinerCount].y = p2.at<float>(i, 1);
          m_InlierMatches[InlinerCount].queryIdx = InlinerCount;
          m_InlierMatches[InlinerCount].trainIdx = InlinerCount;
          InlinerCount++;
     }
}

// 把内点转换为drawMatches能够使用的格式

vector<KeyPoint> key1(InlinerCount);
vector<KeyPoint> key2(InlinerCount);
KeyPoint::convert(m_LeftInlier, key1);
KeyPoint::convert(m_RightInlier, key2);

// 显示计算F过后的内点匹配

// Mat m_matLeftImage;
// Mat m_matRightImage;

// 以上两个变量保存的是左右两幅图像

Mat OutImage;
drawMatches(m_matLeftImage, key1, m_matRightImage, key2, m_InlierMatches, OutImage);
cvNamedWindow( "Match features", 1);
cvShowImage("Match features", &(IplImage(OutImage)));
cvWaitKey( 0 );
cvDestroyWindow( "Match features" );

以上就是核心代码。

加载左右两幅图像后,先用http://blog.sina.com.cn/s/blog_4298002e01013w4z.html一文中所述方法提取特征点并匹配,然后用上面的程序计算基本矩阵。并显示内点匹配。

如图:

初始匹配:

RANSAC过后的内点匹配:

转载于:https://www.cnblogs.com/jzdwajue/p/7064454.html

使用cv::findFundamentalMat要注意的几点相关推荐

  1. SLAM之特征匹配(一)————RANSAC-------OpenCV中findFundamentalMat函数使用的模型

    目录 1.RANSAC原理 2. RANSAC算法步骤: 3. RANSAC源码解析 step one niters最初的值为2000,这就是初始时的RANSAC算法的循环次数,getSubset() ...

  2. Vins中的FeatureTracker::readImage(const cv::Mat _img, double _cur_time)函数

    该函数读取图像Mat以及当前世界_cur_time,并对其进行处理,这一段判断是否对图像利用opencv进行处理,从而消除其明暗变化,并且将传入的时间记录为当前时间. cv::Mat img;TicT ...

  3. VINS-mono详细解读与实现

    VINS-mono详细解读 VINS-mono详细解读 前言 Vins-mono是香港科技大学开源的一个VIO算法,https://github.com/HKUST-Aerial-Robotics/V ...

  4. RANSAC算法原理与实现

    参考原文: RANSAC算法学习笔记 重点内容: 算法流程: 1.在可以有(也可以没有,主要看应用场景)条件限制(比如选的子集里的点不能过远等)的情况下,随机选取子集,并假设为局内点.子集的大小,主要 ...

  5. vins 解读_代码解读 | VINS 视觉前端

    AI 人工智能 代码解读 | VINS 视觉前端 本文作者是计算机视觉life公众号成员蔡量力,由于格式问题部分内容显示可能有问题,更好的阅读体验,请查看原文链接:代码解读 | VINS 视觉前端 v ...

  6. SIFT(ASIFT) Matching with RANSAC

    十来天没上来写东西了,在实践试错的过程中,有太多东西没来得及总结,忙着填BoW的坑,忙着投简历(工作碗里来).尽管这样,还是抽了点空把这十来天自己在完善Bag of Words cpp实现(stabl ...

  7. VINS-Mono关键知识点总结——前端详解

    VINS-Mono关键知识点总结--前端详解 VINS-Mono关键知识点总结--前端详解 1. VINS-Mono的前端流程概述 2. setMask() 函数的作用 3. rejectWithF( ...

  8. 二. 2d-2d 对极约束 估计相机位姿pose(R,t)

    #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace c ...

  9. opencv-python 对极几何

    目标: 本章节你需要学习以下内容: 我们将了解多视角几何的基础知识 我们将看到什么是极点,极线,对极约束等. 基础 当我们使用针孔相机拍摄图像时,我们会丢失一些重要的信息,比如图像的深度.或者是图像中 ...

最新文章

  1. 修改服务器端的访问模式,ftp服务器端 修改主动模式
  2. 怎么快速把语音转成文字
  3. nsis使用汇总(一)
  4. 彻底理解Canal,看这篇就够了
  5. 一张图读懂八大全国一体化算力网络国家枢纽节点一览
  6. php中引入jquery文件_WP模板开发中,怎样给wordpress网站的文章,添加点赞功能?...
  7. teleport 组件的作用_承德专业做链轮组件哪家好
  8. html5 input选择文件,input文件选择,限定文件类型。
  9. Pannellum:实例之在部分视角内展示全景图
  10. 如何将喜马拉雅上的音频保存并导出来
  11. python绘制qq图_Python中作QQ图(quantilequantile Plot)
  12. jq实现checkbox全选中以及获得选中的checkbox的值
  13. 小程序对企业、商家有哪些方面的好处?
  14. 如何做好自己的职业规划?
  15. C# winform设置开机启动
  16. [Java初学]Java上溯造型(upcasting)与下溯造型(Downcasting)
  17. 学习BLE蓝牙一个月总结
  18. adb: failed to install app-debug.apk: Failure [INSTALL_FAILED_ABORTED: User rejected permissions]
  19. 分析及解决:虚拟机无法连接虚拟设备idel 0:1 问题
  20. 闪兼云带你游历互联网网赚的不同时代

热门文章

  1. 【Java从0到架构师】Maven
  2. 【安卓项目】—— 口算测试APP(教程源自B站)
  3. sqlserver命令行修改用户登录密码
  4. ubuntu使用之-rime
  5. 简单梳理帆软报表即决策系统的登录步骤 一
  6. Pandas时间索引的骚操作
  7. flutter listview 滚动到底部_Flutter系列之Flex布局详解
  8. python列表数据类型(一分钟读懂)
  9. python动态图表变化_Python数据可视化 pyecharts实现各种统计图表过程详解
  10. ios 动画 隐藏tabbar_iOS_自定义转场TabBar的隐藏动画