当前位置:   article > 正文

15.图像拼接_matchkeypoints ratio

matchkeypoints ratio

目录

1  项目介绍

2  代码实现

2.1  ImageStiching

2.2  Stitcher

2.2.1  cv_show()

2.2.2  stitch()

2.2.3  detectAndDescribe()

2.2.4  stitch()

2.2.5  matchKeyPoints()

2.2.6  stitch()

2.2.7  drawMatches()


1  项目介绍

现在我们有不同角度照的两张图

  • left.png

  • right.png

我们最后要拼成这个样子

在拼接过程中会有部分信息缺失,比如右下角的花,如果我们使用两张宽与高本就相同的图片效果会好一些,我们的手机中拍摄长图与文章中的方法类似

2  代码实现

项目中一共有两个代码,一个为主代码ImageStiching,另一个为调用代码Stitcher

2.1  ImageStiching

首先导入Sticher文件中的Stithcer类,然后导入cv2,之后读取两张图片

  • 我们这个是左右拼接,如果要上下拼接需要修改Sticher的部分内容

由于我两张图片的尺寸不一样,我们在这里要修改一下尺寸,最后使两张图片等宽,等高

  • 宽与高使用两个图片中最小的宽,最小的高,第一个if是修改高,第二个if是修改宽

实例化Sticher,然后使用stitcher的stitch方法

  • 这个调用的流程放到下面Stitcher讲

最终将结果展示出来

2.2  Stitcher

首先导入库,然后定义类,之后向类中添加函数,一共有五个函数

2.2.1  cv_show()

显示函数,测试时方便就在这先定义了

我们下面按照运行的流程走一遍

2.2.2  stitch()

这个是主函数的接口,我们从这开始看,我们先看参数

  • image 图像,这个是两个图像和起来的列表
  • ratio 匹配置信率,这个是筛选置信的,下面matchKeyPoints中会用到
  • reprojThresh 拒绝阈值,这个是RANSAC算法中用到的,拒绝阈值越小代表要求越高,在这里我们使用4
  • showMatches 是否显示匹配,这个在下方会有一个判定,如果为True则显示匹配

之后我们读入图像

对应主函数的

我们可以发现这里实际上是吧这两张图的变量名称交换了,下面我们的imageA是右侧的图,我们下面对右侧图进行变化,左侧图不变

之后我们使用了定义的detectAndDescribe()方法

2.2.3  detectAndDescribe()

参数为image,我们上面依次放入了imageA与imageB,导入后我们对图像进行灰度处理

然后我们使用SIFT算法

  • None为输出图像

此时我们获得了关键点与特征,特征就是每个点对应的向量前面的SIFT课程中有提到

然后我们将关键点转换为float32的形式,之后返回关键点与特征这个元组

我们现在对应下面这个图来看,kspA是right图的关键点,kpsB是left这张图的关键点

2.2.4  stitch()

此时我们回到主函数发现调用了matchKeyPoints()这个方法,输入的参数有刚刚获取的两个图的关键点与特征,还有匹配置信率ratio与RANSAC的拒绝阈值

2.2.5  matchKeyPoints()

首先我们创建蛮力匹配器,然后进行蛮力匹配

然后我们创建空列表matches用于存放置信高的匹配内容

之后我们进行筛选,我们对所有的匹配进行遍历,两个判定条件

  • len(m) == 2 在2对匹配中都有的匹配长度为2,如果只在m[0]或m[1]其中一个有长度就为1,这个就和我们 14.特征匹配中的m,n,j一样
  • m[0].distance < m[1].distance * ratio m[0]的欧氏距离小于m[1]欧式距离的0.75,这个会筛选掉相似度低的匹配

筛选过后我们这次并不是直接添加m的所有内容,而是只添加匹配的关键点索引

  • trainIdx(训练索引) 是我们对比中右侧图像关键点的索引
  • queryIdx(查询索引) 是我们对比中左侧图像的关键点索引

也就是说上面这个图中左边的是queryIdx,右边的是trainIdx,但是我们在最开始读图像的时候是交换了图像的左右位置的,也就是说此时的queryIdx是实际上right这个图的关键点,trainIdx是left这个图的关键点

trainIdx与queryIdx都是整形数据,我们打印出来看一下

由于是遍历所有的匹配,会出现很多组结果,我们在这只显示一组的结果

之后我们进入下一组判定,如果我们的匹配数量大于4,那么可以继续运行否则就return None,return None就代表左右这两张图片不像,所以就不用完成拼接了

4这个值是在 14.特征匹配 提到的单应性矩阵,这个单应性矩阵需要四组匹配才能进行计算

在处理下面之前我们先整理一下

  • 上面提到kpsA是right这个图的关键点,kpsB是left这个图的关键点
  • matches是一个元组(trainIdx,queryIdx),trainIdx对应的是left这个图的关键点索引,queryIdx是right这个图的关键点索引

所以kpsA对应queryIdx(也就是matches的1号元素),kpsB对应trainIdx(也就是matches的0号元素)

如果判定大于4我们可以继续进行,首先我们提取出关键点,这个时候我们使用到了上面提出来的索引,元组内的1号元素是左侧图像的索引,我们提取出来

然后将点转换为np.float32格式

ptsB同理,提取的右侧图像的关键点

之后使用我们的单应性矩阵,我们通过单应性矩阵对右侧的图进行变化

findHomograhy的参数为

  • ptsA 左图关键点
  • ptsB 有图关键点
  • cv2.RANSAC RANSAC算法(随机抽样一致算法)
  • reprojThresh 容错阈值

返回值有两个左边的矩阵为H,右边的矩阵为status,status表示关键点是否匹配的状态,有0与1两个值

我们看一下H与states

  • H

  • states

states有很多个值,我们只截取了头部与尾部的部分,它表示我们关键点是否匹配的状态,如果是1则代表两个关键点匹配上了,如果是0则代表关键点没有匹配上

返回匹配与H,status两个矩阵的元组

2.2.6  stitch()

此时再回到我们的stitch()

如果刚刚进行的matchKeyPoints返回值为None则不能进行拼接

把元组M的三个元素提取出来

warpPerspective是下面这样图的操作,我们在 11.提取图像内容区域 中介绍过,参数为原图像的尺寸,变化矩阵,变换后图像的尺寸

现在的result是我们变换后的结果,我们看一下

之后我们把imageB(left图像)贴到result的左侧,我们看一下结果

现在两张图片已经贴合上了,但是图像的上侧我们发现有部分黑边,这个时候我们要给它裁掉,这也表示了两张图拼接会有部分的信息损失

裁掉了5个像素点,这个根据图片的实际情况来,有的可能不需要裁,裁掉之后我们合成的图像是这样的

现在回到我们的stitcher,我们走到了这里,如果上面的showMatches使用False则直接返回result,如果为True则执行drawMatches()

2.2.7  drawMatches()

这个函数的作用是画出匹配,我们先看一下画出匹配的结果

然后我们分析一下,这个参数的参数是imageA(right图),imageB(left图),kspA(right图的关键点),kspB(left图的关键点),matches(两图的匹配),status(关键点匹配状态)

之后我们进入函数,首先我们分别获取两张图像的宽与高

然后我们创造一张空白的图像vis,高为两图的最高值,宽为两图的和,通道为3

然后把图像的左侧放为imageA,右侧放为imageB

然后我们对matches和status打个包,matches中提取trainIdx与queryIdx元素,status就提取器本身的元素

如果能匹配上,则获取两图相应的横纵坐标,queryIdx是right这个图的关键点,所以在kpsA中寻找,int(kpsA[queryIdx][0]是横坐标,int(kpsA[queryIdx][1])是纵坐标,下面那一行同理

点坐标获取完毕后我们使用line()在vis这张图像上把两组点连接上,使用颜色为(0,255,0),线宽为1,然后返回vis

以上就是图像拼接的全部过程

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/356007
推荐阅读
相关标签
  

闽ICP备14008679号