图像拼接技术就是将数张有重叠部分的图像(可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的全景图或高分辨率图像的技术。
在医学成像、计算机视觉、卫星数据、军事目标自动识别等领域具有重要意义。
图像拼接目前有很多算法,图像拼接的质量,主要依赖于图像的配准程度,因此通过不同的图像匹配方式将算法分为以下两种:
特征是要匹配的两个输入图像中的元素,为了给图像提供更好的特征匹配,采用角点匹配,进行定量测量。在视点变化时,角点特征是稳定的。角点检测算法有Harris角点检测算法、SIFT特征点检测算法、FAST角点检测算法、SURF特征点检测算法。
本次实验使用的Opencv stitch源码中默认第一选择是SURF特征点检测,第二是ORB特征点检测。
SURF(Speeded Up Robust Features)改进了特征的提取和描述方式,用一种更为高效的方式完成特征的提取和描述。它是SIFT的高效变种,也是提取尺度不变特征,算法步骤与SIFT算法大致相同,但采用的方法不一样,SURF算法要比SIFT算法更高效。
SIFT算法:变换过程在上一篇博客有详细介绍。
SURF算法:
在特征点被检测出来之后,这样子我们就可以得到了两幅待拼接图的匹配点集,接下来我们进行图像的配准,即将两张图像转换为同一坐标下,我们需要以某种方式将它们关联起来。
因为是在使用opencv的条件下面做的实验,这里我们需要使用findHomography函数来求得变换矩阵。但是需要注意的是,findHomography函数所要用到的点集是Point2f类型的,所有我们需要对我们刚得到的点集GoodMatchePoints再做一次处理,使其转换为Point2f类型的点集。
vector imagePoints1, imagePoints2;
for (int i = 0; i
这样子,我们就可以拿着imagePoints1, imagePoints2去求变换矩阵了,并且实现图像配准。值得注意的是findHomography函数的参数中我们选泽了CV_RANSAC,这表明我们选择RANSAC算法继续筛选可靠地匹配点,这使得匹配点解更为精确。
RANSAC原理在上一节也有就介绍,在此简述一下其原理:
从数据集中随机选取一组数据并认为是有效数据(内点)来确定待定参数模型,以此模型测试数据集中的所有数据,满足该模型的数据成为内点,反之为外点(通常为噪声、错误测量或不正确数据的点),迭代执行,直到某一个参数模型得到的内点数最大,则该模型为最优模型。
RANSAC算法在此应用于剔除错误匹配点,提高匹配的精度。
首先计算每个输入图像的变形图像坐标范围,得到输出图像大小,可以很容易地通过映射每个源图像的四个角并且计算坐标(x,y)的最小值和最大值确定输出图像的大小。最后,需要计算指定参考图像原点相对于输出全景图的偏移量的偏移量xoffset和偏移量yoffset。
下一步是使用上面所述的反向变形,将每个输入图像的像素映射到参考图像定义的平面上,分别执行点的正向变形和反向变形。
融合目的在于拼缝消除, Multi-Band能够达到比较好的融合效果,但是效率低,采用Laplacian(拉普拉斯)金字塔,通过对相邻两层的高斯金字塔进行差分,将原图分解成不同尺度的子图,对每一个之图进行加权平均,得到每一层的融合结果,最后进行金字塔的反向重建,得到最终融合效果过程。
上图中,我们把两个Patch拼合到一起,它们首先被放置为有一定重合区域。为了让两者之间的缝隙尽可能的不明显,我们需要知道一个分割线(cut),在这个分割线的左边,图像像素由A贡献,相反在其右边,图像像素则由B贡献。
这里我们将输出的图像看做是由”图(Graph)“所表示,并且给这个Graph两个端点,一个是A,一个是B:
上图中,标有数字的节点实际上是重合区域的像素,节点之间的连接都是有代价的。我们需要拿起剪刀从某个连接上剪掉某些连接,并且要使得被剪掉的连接的代价之和最小化,这就是最典型的图算法中的最小割问题(min cut),它也对应着所谓的最大流问题(max flow)。
那么,如何定义连接之间的代价呢?这里假设在重合区域两个相邻的输出像素分别是s和t。我们知道输出的像素既可能来自于A,也可能来自于B,于是我们用A(s),B(s)来表示s点在A图和B图的颜色, 用A(t),B(t)来表示t点在A图和B图的颜色。
于是,s点和t点的连接的代价被定义为:
我们要做的就是寻找一个切割缝,最小化 M ( s , t , A , B ) M(s,t,A,B) M(s,t,A,B)当找到这条缝之后,左边的像素从A中拷贝而来,而右边的像素则从B中拷贝而来即可。
接下来就可以不断的拼合更多的Patch,目标是用越来越多次的覆盖输出图片中的缝隙,使得图像重合部分越来越多,直到代价值收敛。
实现两张图片的全景拼接,图片有重叠部分
进行三组不同场景的实验
拼接后:
小结:由于光照不同,可以通过色差,看出缝隙的位置。所以在室外景深小的图像中,该图除了后期的色差还未融合,其他地方的衔接都比较完美,效果较好。拼接之后的图片左侧有点倾斜是因为拍摄时的角度有所倾斜,所以整个画面呈现“凸起”状态。
小结:不管是远处还是近处,因为其是在同一光照下,同一角度,拍摄的同一尺寸的图片,其拼接效果非常好,近处的枯草墙面,和远处的楼房都在一张图片里面拼接的很完整,几乎看不出缝隙在哪(我的确没有发现),即使是视差较大,但是效果很好,应该是因为没有太大角度变化和尺度变化加上opencv的这个拼接函数的确很强大的原因。。。。
小结:在这组实验中,可以发现拼接后的图片有明显的“扭曲”现象,因为其中一张图片的角度变化较大,图像中的水平面处于倾斜状态。为了实现拼接,应该是对图像进行了旋转变换处理,将缝隙边缘部分尽量重叠在一起后进行图片融合。所以最后结图片呈现不是很完美,但是能把两张图片中的特征融合在一起。
实验小结:要做图像拼接,避免产生“鬼影”现象,尽量保证使用的是静态图片,不要加入一些动态因素干扰拼接。
Opencv stitch源码
调用函数实现:
# -*- coding: utf-8 -*-
import numpy as np
import cv2
from cv2 import Stitcher
if __name__ == "__main__":
img1 = cv2.imread(r'D:\CVphoto\03205.jpg')
img2 = cv2.imread(r'D:\CVphoto\03203.jpg')
stitcher = cv2.createStitcher(False)
#stitcher = cv2.Stitcher.create(cv2.Stitcher_PANORAMA), 根据不同的OpenCV版本来调用
(_result, pano) = stitcher.stitch((img1, img2))
#cv2.imshow('pano',pano)
res = cv2.resize(pano, (1000, 600), interpolation=cv2.INTER_CUBIC)
cv2.imshow('llg.jpg', res)
cv2.waitKey(0)
error: C:\projects\opencv-python\opencv\modules\imgproc\src\resize.cpp:4044: error: (-215) ssize.width > 0 && ssize.height > 0 in function cv::resize
if image is not None:
res = cv2.resize(pano, (1000, 600), interpolation=cv2.INTER_CUBIC)
不过这只是让程序不再报错,依然没有拼接结果,直接进行imshow也是没有拼接结果的,
因此初步判断是因为通过opencv函数stitch形成的拼接结果为空,所以不能将图片进行resize和imshow,具体原因希望可以有空探究一下。
目前暂时只能通过改变图片寻找可以进行拼接的探讨实验。
实现过程中
本次实验是直接利用opnecv中的stitch函数实现图像拼接,当然效果也是相当好的,但是因为其实现很复杂,而且代码量很庞大,其实在一些小应用下的拼接有点杀鸡用牛刀的感觉
课本《计算机视觉》上面有提供通过SIFT的特征匹配,然后进行图像拼接的源码,希望有机会可以进行对比实验,对比两种算法对于图像拼接的优缺点。
匹配算法改进
在之前进行图像特征匹配时,使用的一直是SIFT特征匹配,但是这次实验中接触了SURF算法。
用SIFT算法来实现图像拼接是很常用的方法,但是因为SIFT计算量很大,所以在速度要求很高的场合下不再适用。所以,它的改进方法SURF因为在速度方面有了明显的提高(速度是SIFT的3倍),所以在图像拼接领域还是大有作为。虽说SURF精确度和稳定性不及SIFT,但是其综合能力还是优越一些。下面将详细介绍拼接的主要步骤。