实验环境:
python高于2.7版本的要注意更改所用demo的print的格式,从print “XXX”
-> print("XXX")
数据设置:
概括来说就是:
接下来将从第二点开始对图像拼接的原理进行阐述。
在计算单应性之前,需要进行特征提取和特征匹配:
特征提取
特征提取使用是SIFT算子,具体的原理及计算方法可以参考图片特征值匹配。
图片的匹配
图片的匹配可以采用OpenCV提供的FLANN或BFMatcher
# FLANN parameters
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50) # or pass empty dictionary
flann = cv2.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)
img3 = cv2.drawMatchesKnn(img1c,kp1,img2c,kp2,matches,None,**draw_params)
cv2.imshow("correspondences", img3)
cv2.waitKey()
匹配完可以得到类似下图的图片
在完成这两个步骤后,就可以进行单应性计算了。
warped_image = cv2.warpPerspective(image, homography_matrix, dimension_of_warped_image)
图片经过翘曲变换后呈如下效果:
2.拼接
在翘曲完成后,通过重复对扭曲的图像向左向右缝合即可完成图像的拼接。
对于图像拼接部分的原理大致可以表示为如下过程:如果一个图像开始的坐标点为 ( 0 , 0 ) (0,0) (0,0),结束的坐标点为 ( r e , c e ) (r_{e},c_{e}) (re,ce),那我们可以通过翘曲得到一个新的图片矩阵,从开始点start: H × [ 0 , 0 ] H×[0,0] H×[0,0]到结束点end: H × [ r e , c e ] H×[r_{e},c_{e}] H×[re,ce],如果开始点为负数,就对它进行平移。并且还要确保单应性矩阵的归一化。
然后再使用basic for looping constructs和覆盖两个图像的方法对图像进行拼接,方法的输入将是stableimage和warpedImage。迭代两个图像对其进行处理,如果像素相等,则将像素作为该值。否则优先考虑非黑色像素。具体代码如下:
def mix_and_match(self, leftImage, warpedImage):
i1y, i1x = leftImage.shape[:2]
i2y, i2x = warpedImage.shape[:2]
print (leftImage[-1,-1])
t = time.time()
black_l = np.where(leftImage == np.array([0,0,0]))
black_wi = np.where(warpedImage == np.array([0,0,0]))
print (time.time() - t)
print (black_l[-1])
for i in range(0, i1x):
for j in range(0, i1y):
try:
if(np.array_equal(leftImage[j,i],np.array([0,0,0])) and np.array_equal(warpedImage[j,i],np.array([0,0,0]))):
# print "BLACK"
# instead of just putting it with black,
# take average of all nearby values and avg it.
warpedImage[j,i] = [0, 0, 0]
else:
if(np.array_equal(warpedImage[j,i],[0,0,0])):
# print "PIXEL"
warpedImage[j,i] = leftImage[j,i]
else:
if not np.array_equal(leftImage[j,i], [0,0,0]):
bw, gw, rw = warpedImage[j,i]
bl,gl,rl = leftImage[j,i]
# b = (bl+bw)/2
# g = (gl+gw)/2
# r = (rl+rw)/2
warpedImage[j, i] = [bl,gl,rl]
except:
pass
# cv2.imshow("waRPED mix", warpedImage)
# cv2.waitKey()
return warpedImage
test1:
首先进行最简单的图片图片拼接,我把下图下图(集美大学延奎图书馆)裁剪成了三部分,来测试其的拼接效果。
左边三张为剪切后的图片,每张图都与相邻右边的图片有所重复,最右为原图:
拼接结果图:
整张图整体和原图没有什么差别,只有楼梯部分变斜了,至于尺寸的问题是因为resize()的原因。
test2
对于外景图片的拼接,使用的是集美大学的尚大楼的图片:
拼接结果:
基本拼接上是没有什么大问题的,只是第二张和第三张图片拼接之后的亮度差异表明显,离镜头较近的石头的拼接上出现了一定的偏移。
test3
现在进行室外景深不同的景物的拼接,使用的图片是集美大学美玲楼附近的三张图片。
三张图片如下:
拼接的效果图:
可以看出来在第一张图片和第二张图片的拼接上并没有完成的很好,有明显的间隔感,楼房之间的连接也出现了差错。
但是在第二张和第三张的部分就完成的比较好。
test4
对于室内照片的拼接,使用的是我自己桌子的照片(小乱= =)
拼接结果:
其中蓝色部分圈出的是拼接的比较好的,红色部分圈出的拼接的比较不好的地方。在拼接的交界处都出现了一定程度的偏移。可见对于一些细节比较多的,距离镜头比较近的图片的拼接效果就比较差了。
如果再在上面的基础上增加一张桌子右侧的图片:
拼接的效果就变得非常,极其不理想起来:
??????
导致这样的原因大致是因为最后一张图片和第三张图片之间的关联点确实太少了(只有几本书是一样的),并且最后一张图还存在着干扰项。可以看出来处理的过程中,算法想把左边的木质墙面和右边的木质墙面当成一个平面处理,所以整个图像变得很扭曲。
参考文章:https://kushalvyas.github.io/stitching.html
参考代码:https://github.com/kushalvyas/Python-Multiple-Image-Stitching