OpenCV-Python 实现两张图片自动拼接成全景图

背景介绍

图片的全景拼接如今已不再稀奇,现在的智能摄像机和手机摄像头基本都带有图片自动全景拼接的功能,但是一般都会要求拍摄者保持设备的平稳以及单方向的移动取景以实现较好的拼接结果。这是因为拼接的图片之间必须要有相似的区域以保证拼接结果的准确性和完整性。本文主要简单描述如何用 Python 和 OpenCV 库实现两张图片的自动拼合,首先简单介绍一下两张图片拼接的原理。

基本原理

要实现两张图片的简单拼接,其实只需找出两张图片中相似的点 (至少四个,因为 homography 矩阵的计算需要至少四个点), 计算一张图片可以变换到另一张图片的变换矩阵 (homography 单应性矩阵),用这个矩阵把那张图片变换后放到另一张图片相应的位置 ( 就是相当于把两张图片中定好的四个相似的点給重合在一起)。如此,就可以实现简单的全景拼接。当然,因为拼合之后图片会重叠在一起,所以需要重新计算图片重叠部分的像素值,否则结果会很难看。所以总结起来其实就两个步骤:

1. 找两张图片中相似的点,计算变换矩阵

2. 变换一张图片放到另一张图片合适的位置,并计算重叠区域新的像素值 (这里就是图片融合所需要采取的策略)

具体实现

寻找相似点

当然,我们可以手动的寻找相似的点,但是这样比较麻烦。因为相似点越多或者相似点对应的位置越准确,所得的结果就越好,但是人的肉眼所找的位置总是有误差的,而且找出很多的点也不是一件容易的事。所以就有聪明的人设计了自动寻找相似点的算法,这里我们就用了 SIFT 算法,而 OpenCV 也给我们提供 SIFT 算法的接口,所以我们就不需要自己费力去实现了。如下是两张测试图片的原图和找出相似点后的图片。

其中红色的点是 SIFT 算法找出的相似点,而绿色的线表示的是在所有找出的相似的点中所筛选出的可信度更高的相似的点。因为算法找出的相似点并不一定是百分百正确的。然后就可以根据这些筛选出的相似点计算变换矩阵,当然 OpenCV 也提供了相应的接口方便我们的计算,而具体的代码实现也可以在 OpenCV 的 Python tutorial 中找到 [1]

图片拼接

计算出变换矩阵后,接下来就是第二步,用计算出的变换矩阵对其中一张图做变换,然后把变换的图片与另一张图片重叠在一起,并重新计算重叠区域新的像素值。对于计算重叠区域的像素值,其实可以有多种方法去实现一个好的融合效果,这里就用最简单粗暴的但效果也不错的方式。直白来说就是实现一个图像的线性渐变,对于重叠的区域,靠近左边的部分,让左边图像内容显示的多一些,靠近右边的部分,让右边图像的内容显示的多一些。用公式表示就是,假设 alpha 表示像素点横坐标到左右重叠区域边界横坐标的距离,新的像素值就为 newpixel = 左图像素值 × (1 - alpha) + 右图像素值 × alpha 。这样就可以实现一个简单的融合效果,如果想实现更复杂或更好的效果,可以去搜索和尝试一下 multi-band 融合,这里就不过多赘述了。最后附上实现的结果和代码,可供参考。

Python 代码如下:

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('test1.jpg')
    img2 = cv.imread('test2.jpg')
    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()
    # find the keypoints and descriptors with SIFT
    kp1, des1 = sift.detectAndCompute(img1gray, None)
    kp2, des2 = sift.detectAndCompute(img2gray, None)
    # FLANN parameters
    FLANN_INDEX_KDTREE = 1
    index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
    search_params = dict(checks=50)
    flann = cv.FlannBasedMatcher(index_params, search_params)
    matches = flann.knnMatch(des1, des2, k=2)

    # Need to draw only good matches, so create a mask
    matchesMask = [[0, 0] for i in range(len(matches))]

    good = []
    pts1 = []
    pts2 = []
    # ratio test as per Lowe's paper
    for i, (m, n) in enumerate(matches):
        if m.distance < 0.7*n.distance:
            good.append(m)
            pts2.append(kp2[m.trainIdx].pt)
            pts1.append(kp1[m.queryIdx].pt)
            matchesMask[i] = [1, 0]

    draw_params = dict(matchColor=(0, 255, 0),
                       singlePointColor=(255, 0, 0),
                       matchesMask=matchesMask,
                       flags=0)
    img3 = cv.drawMatchesKnn(img1gray, kp1, img2gray, kp2, matches, None, **draw_params)
    plt.imshow(img3, ), plt.show()

    rows, cols = srcImg.shape[:2]
    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)
        warpImg = cv.warpPerspective(testImg, np.array(M), (testImg.shape[1], testImg.shape[0]), flags=cv.WARP_INVERSE_MAP)

        for col in range(0, 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(0, rows):
            for col in range(0, 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)
        # show the result
        plt.figure()
        plt.imshow(res)
        plt.show()
    else:
        print("Not enough matches are found - {}/{}".format(len(good), MIN_MATCH_COUNT))
        matchesMask = None

Reference

[1] OpenCV tutorial: https://docs.opencv.org/3.4.1/d1/de0/tutorial_py_feature_homography.html

到此这篇关于OpenCV-Python 实现两张图片自动拼接成全景图的文章就介绍到这了,更多相关OpenCV 图片自动拼接成全景图内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python+OpenCV实现图像拼接

    本文实例为大家分享了利用python和OpenCV实现图像拼接,供大家参考,具体内容如下 python+OpenCV实现image stitching 在最新的OpenCV官方文档中可以找到C++版本的Stitcher类的说明, 但是python版本的还没有及时更新, 本篇对python版本的实现做一个简单的介绍. 由于官方文档中还没有python版本的Stitcher类的说明, 因此只能自己去GitHub源码上找, 以下是stitching的样例: from __future__ import

  • python opencv进行图像拼接

    本文实例为大家分享了python opencv进行图像拼接的具体代码,供大家参考,具体内容如下 思路和方法 思路 1.提取要拼接的两张图片的特征点.特征描述符: 2.将两张图片中对应的位置点找到,匹配起来: 3.如果找到了足够多的匹配点,就能将两幅图拼接起来,拼接前,可能需要将第二幅图透视旋转一下,利用找到的关键点,将第二幅图透视旋转到一个与第一幅图相同的可以拼接的角度: 4.进行拼接: 5.进行拼接后的一些处理,让效果看上去更好. 实现方法 1.提取图片的特征点.描述符,可以使用opencv创

  • python opencv 图像拼接的实现方法

    初级的图像拼接为将两幅图像简单的粘贴在一起,仅仅是图像几何空间的转移与合成,与图像内容无关.高级图像拼接也叫作基于特征匹配的图像拼接,拼接时消去两幅图像相同的部分,实现拼接合成全景图. 具有相同尺寸的图A和图B含有相同的部分与不同的部分,如图所示:             用基于特征的图像拼接实现后: 设图像高为h,相同部分的宽度为wx 拼接后图像的宽w=wA+wB-wx 因此,可以先构建一个高为h,宽为W*2的空白图像,将左图像向右平移wx,右图像粘贴在右侧.则右图像刚好覆盖左图像中的相同部分

  • opencv实现多张图像拼接

    本文实例为大家分享了opencv实现多张图像简单拼接,供大家参考,具体内容如下 #include <iostream> #include <core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include<opencv2/stitching.hpp> using namespace std; using nam

  • opencv2基于SURF特征提取实现两张图像拼接融合

    本文实例为大家分享了opencv2实现两张图像拼接融合的具体代码,供大家参考,具体内容如下 要用到两个文件,estimate.cpp和matcher.h(在有关鲁棒匹配这篇博文中有) estimate.cpp的头文件也需要添加一些东西才行,以下是对的,已经成功运行. 加了using namespace std;之后,cv::可以去掉了. estimate.cpp: #include <iostream> #include <vector> #include <opencv2/

  • OpenCV实现多图像拼接成一张大图

    本文实例为大家分享了OpenCV实现多图像拼接成大图的具体代码,供大家参考,具体内容如下 开始尝试merge函数,具体如下: 定义四个矩阵A,B,C,D.得到矩阵combine. #include<iostream> #include <core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> using namespace std

  • Python+OpenCV实现图像的全景拼接

    本文实例为大家分享了Python+OpenCV实现图像的全景拼接的具体代码,供大家参考,具体内容如下 环境:python3.5.2 + openCV3.4 1.算法目的 将两张相同场景的场景图片进行全景拼接. 2.算法步骤 本算法基本步骤有以下几步: 步骤1:将图形先进行桶形矫正 没有进行桶形变换的图片效果可能会像以下这样: 图片越多拼接可能就会越夸张. 本算法是将图片进行桶形矫正.目的就是来缩减透视变换(Homography)之后图片产生的变形,从而使拼接图片变得畸形. 步骤2:特征点匹配 本

  • OpenCV全景图像拼接的实现示例

    本文主要介绍了OpenCV全景图像拼接的实现示例,分享给大家,具体如下: left_01.jpg right_01.jpg Stitcher.py import numpy as np import cv2 class Stitcher: #拼接函数 def stitch(self, images, ratio=0.75, reprojThresh=4.0,showMatches=False): #获取输入图片 (imageB, imageA) = images #检测A.B图片的SIFT关键特

  • OpenCV-Python 实现两张图片自动拼接成全景图

    背景介绍 图片的全景拼接如今已不再稀奇,现在的智能摄像机和手机摄像头基本都带有图片自动全景拼接的功能,但是一般都会要求拍摄者保持设备的平稳以及单方向的移动取景以实现较好的拼接结果.这是因为拼接的图片之间必须要有相似的区域以保证拼接结果的准确性和完整性.本文主要简单描述如何用 Python 和 OpenCV 库实现两张图片的自动拼合,首先简单介绍一下两张图片拼接的原理. 基本原理 要实现两张图片的简单拼接,其实只需找出两张图片中相似的点 (至少四个,因为 homography 矩阵的计算需要至少四

  • python实现两张图片拼接为一张图片并保存

    本文实例为大家分享了python实现两张图片拼接为一张图片并保存的具体代码,供大家参考,具体内容如下 这里主要用Python扩展库pillow中Image对象的paste()方法把两张图片拼接起来 from os import listdir from PIL import Image def pinjie(): # 获取当前文件夹中所有JPG图像 im_list = [Image.open(fn) for fn in listdir() if fn.endswith('.jpg')] # 图片

  • Opencv Python实现两幅图像匹配

    本文实例为大家分享了Opencv Python实现两幅图像匹配的具体代码,供大家参考,具体内容如下 原图 import cv2 img1 = cv2.imread('SURF_2.jpg', cv2.IMREAD_GRAYSCALE) img1 = cv2.resize(img1,dsize=(600,400)) img2 = cv2.imread('SURF_1.jpg', cv2.IMREAD_GRAYSCALE) img2 = cv2.resize(img2,dsize=(600,400)

  • python实现两张图片的像素融合

    本文实例为大家分享了python实现两张图片像素融合的具体代码,供大家参考,具体内容如下 通过计算两张图片的颜色直方图特征,利用直方图对图片的颜色进行融合. import numpy as np import cv2 from PIL import Image,ExifTags def calcMeanAndVariance(img): row=img.shape[0] col=img.shape[1] #channel=img.shape[2] total=row*col print (row

  • python如何将两张图片生成为全景图片

    本文实例为大家分享了python将两张图片生成全景图片的具体代码,供大家参考,具体内容如下 1.全景图片的介绍 全景图通过广角的表现手段以及绘画.相片.视频.三维模型等形式,尽可能多表现出周围的环境.360全景,即通过对专业相机捕捉整个场景的图像信息或者使用建模软件渲染过后的图片,使用软件进行图片拼合,并用专门的播放器进行播放,即将平面照片或者计算机建模图片变为360 度全观,用于虚拟现实浏览,把二维的平面图模拟成真实的三维空间,呈现给观赏者. 2.如何实现 2.1.实现原理 主要是利用sift

  • python实现多张图片拼接成大图

    本文实例为大家分享了python实现多张图片拼接成大图的具体代码,供大家参考,具体内容如下 上次爬取了马蜂窝的游记图片,并解决了PIL模块的导入问题,现在直奔主题吧: import PIL.Image as Image import os IMAGES_PATH = 'D:\Mafengwo\photo\五月坦桑的暖风,非洲原野的呼唤\\' # 图片集地址 IMAGES_FORMAT = ['.jpg', '.JPG'] # 图片格式 IMAGE_SIZE = 256 # 每张小图片的大小 IM

  • 用python实现对比两张图片的不同

    from PIL import Image from PIL import ImageChops def compare_images(path_one, path_two, diff_save_location): """ 比较图片,如果有不同则生成展示不同的图片 @参数一: path_one: 第一张图片的路径 @参数二: path_two: 第二张图片的路径 @参数三: diff_save_location: 不同图的保存路径 """ im

  • python利用opencv如何实现答题卡自动判卷

    目录 1.设定答题卡模板 2.读取答题卡图像并对图像进行灰度化处理 3.高斯模糊图像去噪点 4.使用大津法二值分割图像 5.使用开运算去噪点 6.使用canny边缘检测算法 7.筛选答题区域轮廓,透视变换矫正目标区域 使用摄像头实时判卷部分 总结 1.设定答题卡模板 该图像为答题卡的答题区域,黑色边框是为了能够在各种环境中轻易的检测,左部分和上部分的黑色矩形,是为能够定位到答题选项的坐标而设置,同时题目数量为20×3共60道选择题,在进行批改试卷之前,需要手动输入该次考试的正确答案作为模板来对识

  • python+opencv实现论文插图局部放大并拼接效果

    目录 前言 cv2.rectangle() 函数 cv2.resize() 函数 np.hstack() 和 np.vstack() 函数 实现局部框定放大拼接 总结 前言 在制作论文插图时,有时要求将图片的局部放大来展示细节内容,同时将放大图拼接在原图上以方便观察对比. 当然直接利用电脑自带的画图软件或者别的软件也可以很方便地实现,但是如果碰到多个算法处理一张图片后多张图片进行对比就不太方便了,这里主要贴一下 python 代码的实现. cv2.rectangle() 函数 cv2.recta

  • 如何利用opencv判断两张图片是否相同详解

    OpenCV介绍 OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows.Android和Mac OS操作系统上.它轻量级而且高效--由一系列 C 函数和少量 C++ 类构成,同时提供了Python.Ruby.MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法. OpenCV用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语言接口.该库也有大量的Python.Java and MATLAB/OCTAVE(版本

随机推荐