【进阶OpenCV】 (4)--图像拼接

图像拼接

图像拼接是一项将多张有重叠部分的图像(这些图像可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的全景图或高分辨率图像的技术。

主要过程:找到特征匹配点,然后进行透视变换操作,模拟了人眼或相机镜头观看三维空间物体时的透视效果,从而能够改变图像的视角和形状,使得两个图片可以完全拼接在一起。

1. 读取图片

在这里插入图片描述

在这里插入图片描述

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
"""-----读取拼接图片-----"""
imageA = cv2.imread("t1.jpg")
cv_show('imageA',imageA)
imageB = cv2.imread("t2.jpg")
cv_show('imageB',imageB)

2. 计算图片特征点及描述符

def detectAndDescribe(image):
    gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY) # 将彩色图片转化为灰度图
    descriptor = cv2.SIFT_create() # 建立SIFT生成器
    # 检测SIFT特征点,并计算描述符,第二个参数为掩膜
    (kps,des) = descriptor.detectAndCompute(gray,None)
    # 将结果转化成Numoy数组
    kps_float = np.float32([kp.pt for kp in kps])
    # kp.pt包含两个值,分别是关键点在图像中的x和y坐标,这些坐标通常时浮点数,可以精确地描述关键点在图像中的位置
    return (kps,kps_float,des) # 返回特征点集,及对应的描述特征

"""-----计算图片特征点及描述符-----"""
(kpsA,kps_floatA,desA) = detectAndDescribe(imageA)
(kpsB,kps_floatB,desB) = detectAndDescribe(imageB)

3. 建立暴力匹配器

"""-----建立暴力匹配器BFMatcher,在匹配大型训练集合时使用FlannBasedMatcher速度更快-----"""
matcher = cv2.BFMatcher()

4. 特征匹配

方法:关键点A与找到的两个关键点 X、Y的欧氏距离分别 d1、d2,且d1<d2。

欧氏距离(关键点A,关键点X)=d1。欧氏距离(关键点A,关键点Y)=d2。

(1)d1<d2,比值较大:可能不是匹配点,通常是由噪声引起的。

(2)d1<d2,比值较小:是匹配点。

在这里插入图片描述

  • 函数
--knnMatch(queryDescriptors,trainDescriptors,k,mask=None,compactResult = None)
使用KNN检测来自A、B图的SIFT特征匹配对,参数说明:
queryDescriptors:匹配图像A的描述符
trainDescriptors:匹配图像B的描述符
k:最佳匹配的描述符个数,一般k=2
  • 返回值
--返回的数据结构描述:
distance:匹配的特征点描述符的欧氏距离,数值越小也就说明两个特征点越相近。
queryIdx:测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下表
trainIdx:样本图像的特征点描述符下标,同时也是描述符对应特征点的下标。
  • 代码应用:
rawMatches = matcher.knnMatch(desB,desA,2)
good = []
matches = []
for m in rawMatches:
    # 当最近距离跟次近距离的比值小于0.65时,保留此对匹配
    if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:
        good.append(m)
        # 存储两个点在featureA,featureB中的索引值
        matches.append((m[0].trainIdx,m[0].queryIdx))
print(len(good))
print(matches)

vis = cv2.drawMatchesKnn(imageB,kpsB,imageA,kpsA,good,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show("keypoint Matchs",vis)

在这里插入图片描述

5. 透视变换

透视变换是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,但仍能保持承影面上投影几何图形不变的变换。它是中心投影的射影变换,在用非齐次射影坐标表达时是平面的分式线性变换。

  • 函数
-- 计算透视变换矩阵
findHomography(srcPoints,disPoints,method=None,ransacReprojThreshold=None,mask=None,maxIters=None,confidence=None)
计算视角变换矩阵,透视变换函数,与cv2.getPerspectiveTransform()的区别在于可多个数据点变换
参数:
-- srcPoints:图片A的匹配点坐标
-- disPoints:图片B的匹配点坐标
-- method:计算变换矩阵的方法
   0 - 使用所有的点,最小二乘
   RANSAC - 基于随机样本一致性
   LMEDS - 最小中值
   RHO - 基于渐进样本一致性
-- ransacReprojThreshold:最大允许重投影错误阈值,该参数只有在method参数为RANSAC与RHO的时候启用,默认为3
返回值:H为变换矩阵,mask时掩膜标志,指示哪些点对时内点,哪些是外点.内点:指那些与估计的模型非常接近的数据点,通常是正确匹配或真实数据
  • 代码应用
if len(matches) > 4: # 当筛选后的匹配对大于4时,计算视角变换矩阵
    # 获取匹配对的点坐标
    ptsA = np.float32([kps_floatA[i] for (i, _) in matches]) # matches是通过阈值筛选之后的特征点对象
    ptsB = np.float32([kps_floatB[i] for (_, i) in matches]) # kps_floatA是图片A中的全部特征点坐标
    (H,mask) = cv2.findHomography(ptsB,ptsA,cv2.RANSAC,10)
else:
    print("图片未找到4个以上的匹配点")
    sys.exit()
result = cv2.warpPerspective(imageB,H,(imageB.shape[1] + imageA.shape[1],imageB.shape[0]))
cv_show('resultB',result)

在这里插入图片描述

6. 图像拼接

# 将图片A传入result图片最左端
result[0:imageA.shape[0],0:imageA.shape[1]] = imageA
cv_show("result",result)

在这里插入图片描述

总结

本篇介绍了:

如何通过计算关键点以及透视变换的矩阵将两个不同视角的图片进行拼接,使得它们能够完整协和的展示出来。

### 回答1: Opencv-python多图像拼接是指将多张图片拼接成一张大图的操作。这个操作可以用于制作全景图、拼接地图等等。在opencv-python中,可以使用cv2库中的函数cv2.stitcher_create()来实现多图像拼接。这个函数可以将多张图片拼接成一张大图,并且可以自动调整图片的位置和角度,使得拼接后的图片更加自然。需要注意的是,多图像拼接需要保证每张图片之间有重叠的部分,否则拼接后的图片会出现断裂的情况。 ### 回答2: OpenCV是一个流行的计算机视觉库,由C++编写而成,也提供了Python接口。OpenCV-Python是Opencv的Python接口,它提供了大量方便易用的函数,可以处理图像和视频等数据。 在OpenCV-Python中,可以使用cv2库中的函数来实现多图像拼接。通常情况下,多图像拼接需遵循以下步骤: 1. 加载每个图像到程序中 2. 确定每个图像相对于它们相关联的位置 3. 将这些图像组合成最终的拼接图像 下面是实现多图像拼接的基本流程: Step 1: 加载图像 使用cv2.imread()函数加载所有需要拼接的图像,然后将这些图像存储到一个列表中,以方便后续操作。 ```python import cv2 import numpy as np # Load all the images img1 = cv2.imread('image1.jpg') img2 = cv2.imread('image2.jpg') img3 = cv2.imread('image3.jpg') # Store all the images in a list images = [img1, img2, img3] ``` Step 2:确定每个图像的位置 计算每个图像与参考图像之间的平移量和旋转角度以获得它们的位置。可以使用cv2.estimateRigidTransform()函数来计算每个图像相对于参考图像的偏移量。该函数需要两张图像作为参数,并返回一个2x3的仿射变换矩阵。 ```python # Estimate the translation and rotation # to align all the images with the first image num_images = len(images) reference_image = images[0] transforms = [] for i in range(1, num_images): # Calculate the transformation matrix transform = cv2.estimateRigidTransform(images[i], reference_image, False) transforms.append(transform) ``` Step 3:拼接图像 使用cv2.warpAffine()函数将每个图像变换,并将它们组合成一个大的拼接图像。首先创建一个空图像,然后使用cv2.warpAffine()函数将每个图像变换为它们的实际位置,并将它们添加到空图像中。 ```python # Combine all the images max_x = 0 max_y = 0 for i in range(num_images): rows, cols, channels = images[i].shape dst = cv2.warpAffine(images[i], transforms[i], (cols, rows)) max_x = max(max_x, transforms[i][0, 2]) max_y = max(max_y, transforms[i][1, 2]) # Create an empty image panorama = np.zeros((max_y, max_x + cols, 3), np.uint8) # Add the images to the panorama panorama[0:rows, 0:cols] = img1 panorama[0:rows, int(transforms[0][0, 2]):cols+int(transforms[0][0, 2])] = img2 panorama[0:rows, int(transforms[1][0, 2]):cols+int(transforms[1][0, 2])] = img3 ``` 以上就是基本的多图像拼接流程。当然,这种拼接方式有很多的局限性,例如对光线的要求高,对图像的重叠区域要求高,需要手动校准等。因此,如果需要更加高质量的拼接,需使用更加复杂的算法,例如SIFT和SURF算法。这些算法可以实现自动化的图像拼接,可以处理复杂的场景,但也需要更多的计算资源和算法知识来实现。 ### 回答3: 对于需要将多张图片拼接到一起的应用场景,opencv-python提供了一种有效的解决方案。在opencv-python中,我们可以使用函数cv2.hconcat和cv2.vconcat来进行图像的水平和竖直方向的拼接。 假设我们有三张大小相同的图片A、B和C,它们的宽度分别为width,高度为height。现在我们需要将这三张图片水平拼接在一起,那么我们可以使用以下代码: ``` import cv2 # 读取图片 img_a = cv2.imread('a.jpg') img_b = cv2.imread('b.jpg') img_c = cv2.imread('c.jpg') # 图片拼接 result = cv2.hconcat([img_a, img_b, img_c]) # 显示拼接后的图片 cv2.imshow('Result', result) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在这段代码中,我们首先通过cv2.imread函数读取了三张图片A、B和C。然后,我们使用cv2.hconcat函数将这三张图片在水平方向上拼接在一起,得到了一个新的图像result。最后,我们使用cv2.imshow函数将拼接后的图片显示在窗口中。 在进行图像拼接时,我们还需要注意以下几点: 1. 图片尺寸必须相同。如果进行拼接的多张图片尺寸不同,我们需要使用cv2.resize函数将其缩放到相同的尺寸。 2. 图片数量不能太多。如果需要拼接的图片数量过多,可能会导致拼接后的图片过于宽或过于高,无法在屏幕上完整显示。 3. 拼接后的图片可能存在黑边。如果拼接的多张图片宽度不足,拼接后的图片可能会在右侧出现黑边;如果拼接的多张图片高度不足,拼接后的图片可能会在下方出现黑边。解决这个问题的方法是在拼接前使用cv2.copyMakeBorder函数在图片边缘添加一定量的填充。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值