欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python+opencv图像拼接

程序员文章站 2022-05-16 10:34:38
...

#目前在看七月的CV课,今天第二节,作业是实现图像拼接

  1. 使用SIFT特征点检测
  2. 使用FLANN进行特征点单应性匹配
  3. 计算第二张相对于第一张的仿射变换
  4. 使用公式(1-alpha)×原+alpha×仿进行拼接
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
if __name__ == '__main__':
    top, bot, left, right = 100, 100, 0, 500
    img1 = cv.imread('1.png')
    img2 = cv.imread('2.png')
    #扩充图像的边界,CONSTANT表示常量法,填充的边界由value参数给定
    srcImg = cv.copyMakeBorder(img1, top, bot, left, right, cv.BORDER_CONSTANT, value = (0,0,0))
    testImg = cv.copyMakeBorder(img2, top, bot, left, right, cv.BORDER_CONSTANT, value = (0,0,0))
    img1gray = cv.cvtColor(srcImg, cv.COLOR_BGR2GRAY)
    img2gray = cv.cvtColor(testImg, cv.COLOR_BGR2GRAY)
    sift = cv.xfeatures2d_SIFT().create()
    #找到关键点和描述子
    kp1, des1 = sift.detectAndCompute(img1gray, None)
    kp2, des2 = sift.detectAndCompute(img2gray, None)
    #FLANN单应性匹配, 单应性指的是图像在投影发生了畸变后仍然能够有较高的检测和匹配准确率
    #kdtree建立索引方式的常量参数
    FLANN_INDEX_KDTREE = 0
    index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
    search_params = dict(checks = 50)#chesks指定索引树要被遍历的次数
    flann = cv.FlannBasedMatcher(index_params, search_params)
    #进行匹配搜索
    matches = flann.knnMatch(des1, des2, k=2)
    # 寻找距离近的放入good列表
    good = []
    for m, n in matches:
        if m.distance < 0.7 * n.distance:
            good.append(m)
    MIN_MATCH_COUNT = 10
    # 如果足够多就进行匹配
    if len(good) > MIN_MATCH_COUNT:
        # 通过距离近的描述符 找到两幅图片的关键点
        src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
        dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
        # 单应性匹配图关键点匹配线
        M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0)
        matchesMask = mask.ravel().tolist()
        #仿射变换的图像
        warpImg = cv.warpPerspective(testImg, np.array(M), (testImg.shape[1], testImg.shape[0]), flags = cv.WARP_INVERSE_MAP)
        rows, cols = srcImg.shape[:2]
        for col in range(cols):
            if srcImg[:,col].any() and warpImg[:, col].any():
                left = col
                break
        for col in range(cols-1, 0, -1):
            if srcImg[:,col].any() and warpImg[:,col].any():
                right = col
                break
        res = np.zeros([rows,cols,3], np.uint8)
        for row in range(rows):
            for col in range(cols):
                if not srcImg[row, col].any():
                    res[row, col] = warpImg[row, col]
                elif not warpImg[row, col].any():
                    res[row,col] = srcImg[row, col]
                else:
                    srcImgLen = float(abs(col-left))
                    testImgLen = float(abs(col-right))
                    alpha = srcImgLen / (srcImgLen+testImgLen)
                    res[row, col] = np.clip(srcImg[row,col] * (1-alpha) + warpImg[row, col] * alpha, 0, 255)
        #opencv is bgr, matplotlib is rgb
        res = cv.cvtColor(res, cv.COLOR_BGR2RGB)
        plt.imshow(res)
    #否则不进行拼接
    else:
        matchesMask = None