刚到实验室,做了一个全景图像拼接的training project,自己前前后后搞了1个多月(汗啊,只能自我安慰是接触到的第一个图形学的东西),尝试了几种方法,写了很多无用代码,下面把我一路曲曲折折的过程抛出来,希望能对大家有些许帮助吧。
一. 做拼接的第一步一定是warp,就是把每张图像投影到柱面或者球面,我将每张图片做了柱面投影,而这么做的理由呢,就是将图像投影到统一的面上以方便拼接,根据我做的过程中的理解就是使拼接的图像很平滑,当然如果只是拼接两张图片的话,完全可以省略这一步。
二. 图像拼接的第二步就是提取特征点(也可以采用边特征的提取),特征点的提取方法有很多,我使用了lowe的SIFT,SIFT是一个非常鲁棒的算法,但是速度很慢,如果想程序运行速度很快,可以使用其他特征点提取方法,lowe提供了SIFT的源码,可以直接使用。
三. 提取出两张图片的特征点以后,就要找到特征点间的对应关系,这一步是一个简单的距离比值删选的过程,我自己实现了一个暴力筛选的方法,还是比较简单的,但是这样肯定会很影响速度,所以要使用一个k-d tree的approximate nearest neighbour算法,可以用ann库实现,当然也可以直接用rob hess的特征点匹配算法实现。
四. 上一步找到对应特征点以后,接下就是用RANSAC对已有匹配进行筛选并求出对应的homography,实际上就是一个简单的迭代过程。
五. 求出homography以后就可以进行alignment了,这一步可以用opencv提供的WarpPerspective函数实现,但是用这个函数一张图像经过几次align之后,拼接后图像越靠右边越有发散效果,所以用这个函数只有两张图片好用(如果有人知道多张图片怎么用这个函数进行拼接,请您不吝赐教),这一步还有一个很重要的边界问题,及拼接图像转换后的坐标可能出现负值,这一点一定要考虑进去,否则会出现拼接后的图像包含不全的情况。
六. alignment之后就是blend的问题,以使拼接边界不那么明显,我采用了一个简单的线性的距离权值算法,效果还可以看,即pixel=pixel_a*alpha+pixel_b*(1-alpha),alpha为当前像素点距拼接左边界的距离除以整个重叠区域的宽度。下面两张图分别是4张,3张图像用WarpPerspective函数拼接的。
七. 如果你只需要拼接两张图片,那到上一步就可以了,以下是360度拼接的额外过程,即图片有n张的情况,我只考虑了所有图片都属于一个全景图没有噪音图片的乱序图片的情况。要先将图片排好序,以下为排序过程:①在所有图像对间找到inliers个数最多两张图像②在两张图片的基础上向前向后依次找出与当前图像邻接的图像直到结束。
八. 经过上一步就可以进行alignment了,因为之前用提过的WarpPerspective函数使用中的问题,这一步只使用了homography中的水平和垂直平移分量tx,ty,依旧采用线性权值的方法进行blend,多长图像拼接还有一个很重要的问题就是拼接后首尾不能相接的情况,这就需要惊醒调整,比较好的方法是bundle adjustment,我也分别用opencv和sba实现了,但是估计还是实现的方法不对,调了好长时间没有出效果,无奈只能先放弃了,以后比较闲的时候再实现吧(如果有人在这一步用bundle adjustment实现,请赐教)。转去实现了一个比较简单的线性调整的方法,最后结果看起来还可以,有些模糊的地方,我估计可能是blend方法的问题,但是没有继续实现multi-blend,所以结果只能是现在这样了。
总之呢,整个拼接程序还比较粗糙,有很多地方有待完善,欢迎大家有问题可以和我交流。下面为两个17张图片的全景图