c++ opencv mat_图像拼接Opencv源码重构

请看赵春江https://me.csdn.net/zhaocj的主页,他已经对Opencv图像拼接流程中的代码做了很详细的解释。前人栽树,后人乘凉。

一.本文所做的事

1.重构了Opencv图像拼接的源代码,整个代码是面向过程的;

2.在赵春江源码分析基础上,对一些细节部分进行说明。

代码链接:https://github.com/mhhai/ImageStitch

二.特征点检测

一切起源于这段代码

Ptr

finder =newOrbFeaturesFinder(); 这段代码生成了一个OrbFeaturesFinder对象,其构造函数为:

OrbFeaturesFinder

可以看出这里面创建了一个ORB类。关于这一点,看OrbFeaturesFinder类的继承结构

61108131313c80d44b98f8cba606a372.png

真正实现ORB算法是在orb.cpp中的ORB_Impl类,其他的都是一些函数调用过程,这也是opencv难以看懂的部分。OrbFeaturesFinder类声明(在matchers.hpp)如下:

class 

可以看出OrbFeaturesFinder是没有重载()的,那么它为什么可以使用

(

这段代码呢,因为在其父类FeaturesFinder中实现了()的重载,派生类直接使用父类的公有方法。父类FeaturesFinder重载()代码如下:

void 

接下来,在函数operator()中,调用了find函数,由于OrbFeaturesFinder类实现了自己的find函数版本,所以,接下来执行OrbFeaturesFinder中的find函数,该函数有点长,但还是拿来说明一下:

void 

之所以把这段这么长的代码贴出来,是因为这段代码从全局的角度讲述了怎样进行特征点检测。继续看

finder = new  OrbFeaturesFinder();

这段代码,由OrbFeaturesFinder类的构造函数可知,使用默认参数时是检测出1500个特征点,建立5层高斯金字塔图像,那么第一个参数Size(3,1)参数作何解释?Size(3,1)是说把图像分成1 * 3的网格,对每个网格进行特征点检测,每个网格检测出的数目是500,那么总共检测出的特征点数目就为1500,可以看下面的示意图:

6a1c6569ffd4b76dc169a41ce5f5cad5.png

不是检测出1500个特征点吗,在哪里设置500这个参数了?其实在你第一次写

finder = new  OrbFeaturesFinder();

这段代码时,构造函数中的这段代码

orb = ORB::create(n_features * (99 + grid_size.area())/100/grid_size.area(), scaleFactor, nlevels);

create函数第一个参数的值被设置成了510,也就是每个区域检测出的特征点数目不是刚好500,而是多一点。通过设置find的函数中的r、c参数,你可以对想要的部分进行特征点检测。另外,从这里可以看出,Opencv实现的ORB特征点检测并不是对整幅图像建立高斯金字塔,而是对每个网格建立高斯金字塔。另外每层金字塔检测出来的数目是根据尺度实现分配好的,这方面可以参看赵春江的书或者博客。

三.特征点匹配

这一部分类与类之间的关系比较复杂,具体可以看下图:

ce755fc26267e7a6c9d30663ece291db.png

特征匹配使用的是最近邻匹配(BestOf2NearestMatcher),实现最近邻匹配可以使用暴力匹配法和K-D树最近邻搜索。不是说暴力匹配法一定不好。对于3000个特征点对以下的特征匹配,暴力匹配法是优于K-D树搜寻的,因为K-D树的构建本身就需要耗费时间。

当你使用下面代码时

BestOf2NearestMatcher 

其构造函数为:

BestOf2NearestMatcher

该类内部维护的一个FeaturesMatcher对象(智能指针)就被实例化为CpuMatcher,所以特征匹配调用的关系虽然很复杂,但是没有必要去研究这些,只需要着重于CpuMatcher类中的match函数,该函数实现了两个特征点集之间的匹配。BestOf2NearestMatcher类也有一个match函数,该match函数属于更上层,它调用了CpuMatcher类中的match()函数以及findHomography()函数,其中findHomography()实现了使用RANSAC算法去除误匹配。关于findHomography()重构的代码放在下一小节中,findHomography()能够看到RANSAC算法的精细之处。另外,knnMatch()代码没有重构出来,个人感觉这部分代码重构难度大,而且不重要,因此还是重构findHomography()更具有意义。

四.计算单应性矩阵

这部分代码是在特征匹配的基础上继续深入的,目的是为了更好地看出计算单应性矩阵的过程。包括通过4个点计算单应性矩阵、使用重映射误差剔除外点,更新RANSAC算法的迭代阈值等。

五.恢复相机内外参

这部分代码只重构的相机内参的部分。相机外参涉及到光束平差法、雅可比矩阵和波形校正等等。。。这部分我也很晕。所以,计算外参,尤其是多幅图像拼接之间的外参计算是很麻烦的。愿有后来人能将这部分代码讲清楚。。。

六.投影变换

如果你的项目镜头是固定的,也就是说你的内外参是固定的,上面的结果就可以看作是预训练的过程。因此你就可以不需要太去了解光束平差法怎么实现之类的细节问题。这一部分我会再细讲一下。

七.动态规划法寻找最佳缝合线

这部分很早之前就重构出来了,因此很多细节都我忘了。还是可以看一看的。

八.图像融合

这部分是我针对项目中特殊镜头成像写的,因此不具普遍性。这部分代码主要包括计算能量函数、寻找最佳缝合线,渐入渐出法融合。因为只寻找了小部分的缝合线,所以PC机图像融合部分耗是0.3s(两张图片)。当然还是很慢。由于Opencv羽化融合不适合我的图像,所以前面代码中的pano结果中间会有细微的黑影。

总结:

基本重构出了Opencv图像拼接整个流程的代码,由于一些工作是早期做的,所以很多东西没有记录下来,只有重构好的代码保留了下来。所以大家可以当作这是一份参考资料。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值