图像拼接是将两张具有相同信息的图片,根据相同的信息拼接起来,从而得到全景图片。
完整代码:
https://github.com/YvanYan/image_processing/tree/master/image_stitching
步骤:
1.输入需要拼接的图像
2.查找图片中的特征点和特征描述
3.匹配两张图片所有的特征点
4.进行视角变换,拼接
1.输入图像
根据这两张图片中相同区域进行匹配拼接。
2.查找图片中的特征点和特征描述
def find_kps_feas(self, image):
# 建立SIFT生成器
descriptor = cv2.xfeatures2d.SIFT_create()
# 检测SIFT特征点
(kps, features) = descriptor.detectAndCompute(image, None)
npkps = np.float32([kp.pt for kp in kps])
# 返回特征点集
return (kps, npkps, features)
使用SIFT算法来检测特征点,关于SIFT网上有许多讲解,在此不在解释。(这篇博客讲解的很好,https://blog.csdn.net/qq_37374643/article/details/88606351)。使用SIFT_create来实例化SIFT。detectAndCompute来检测图片中的特征点(kps)和特征描述(features)。这里npkps是为了计算方便将kps转成了numpy,原始的kps在后面绘图的时候会用到。
3.匹配两张图片所有的特征点
def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh):
bf = cv2.BFMatcher()
allMatches = bf.knnMatch(featuresB, featuresA, k=2)
matches = []
good = []
for m, n in allMatches:
if m.distance < ratio * n.distance:
matches.append((m.trainIdx, m.queryIdx))
good.append([m])
if len(matches) > 4:
ptsA = np.float32([kpsA[i] for (i, _) in matches])
ptsB = np.float32([kpsB[i] for (_, i) in matches])
(H, status) = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, reprojThresh)
return (good, H, status)
matchKeypoints函数的输入分为图像A和kpsA、图像B和kpsB、ratio是David Lowe’s ratio测试变量、reprojThresh是RANSAC重投影门限。
cv2.BFMatcher建立暴力匹配器。使用knnMatch进行匹配,通过ratio过滤掉不符合条件的特征匹配对。queryIdx:测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下标。trainIdx:样本图像的特征点描述符下标,同时也是描述符对应特征点的下标。findHomography: 计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列) ,使用最小均方误差或者RANSAC方法。因为变换矩阵H是3 * 3,且H[3][3]设为1,所以共有八个未知数,因此需要保证至少有四组匹配值。
在匹配过程中要注意顺序,例如本代码中knnMatch输入是(图像B,图像A),那么trainIdx代表的是图像A的下标,queryIdx代表的图像B的下标。在findHomography时,我们是将图像B向图像A进行变换,因此输入顺序是(ptsB,ptsA)。
4.进行视角变换,拼接
M = self.matchKeypoints(npkpsA, npkpsB, feasA, feasB, ratio, reprojThresh)
(good, H, status) = M
result = cv2.warpPerspective(imageB, H, (imageA.shape[1] + imageB.shape[1], imageB.shape[0]))
self.cv_show('result1', result)
result[0:imageA.shape[0], 0:imageA.shape[1]] = imageA
self.cv_show('result2', result)
img = cv2.drawMatchesKnn(imageB, kpsB, imageA, kpsA, good, None, flags=2)
self.cv_show('result', img)
warpPerspective根据变化矩阵H将图像B进行视角变换。然后将图像A拼接到相应位置。drawMatchesKnn是将两个图像的特征匹配信息绘制出来。
在进行实现过程中,我想将图像A进行视角变化,变换至图像B的大小,然后将图像B拼接到图像A上。但是未能实现,图像A视角变换后,会将图片信息丢失一部分。希望有大神可以指导一下。