基于Python和openCV实现图像的全景拼接详细步骤


Posted in Python onOctober 05, 2021

基本介绍

图像的全景拼接,即“缝合”两张具有重叠区域的图来创建一张全景图。其中用到了计算机视觉和图像处理技术有:关键点检测、局部不变特征、关键点匹配、RANSAC(Random Sample Consensus,随机采样一致性)和透视变形。

具体步骤

(1)检测左右两张图像的SIFT关键特征点,并提取局部不变特征 ;
(2)使用knnMatch检测来自右图(左图)的SIFT特征,与左图(右图)进行匹配 ;
(3)计算视角变换矩阵H,用变换矩阵H对右图进行扭曲变换;
(4)将左图(右图)加入到变换后的图像的左侧(右侧)获得最终图像;

import cv2 as cv        # 导入opencv包
import numpy as np      # 导入numpy包,图像处理中的矩阵运算需要用到


# 检测图像的SIFT关键特征点
def sift_keypoints_detect(image):
    # 处理图像一般很少用到彩色信息,通常直接将图像转换为灰度图
    gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)

    # 获取图像特征sift-SIFT特征点,实例化对象sift
    sift = cv.xfeatures2d.SIFT_create()                
    
    # keypoints:特征点向量,向量内的每一个元素是一个KeyPoint对象,包含了特征点的各种属性信息(角度、关键点坐标等)
    # features:表示输出的sift特征向量,通常是128维的
    keypoints, features = sift.detectAndCompute(image, None)
    
    # cv.drawKeyPoints():在图像的关键点部位绘制一个小圆圈
    # 如果传递标志flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,它将绘制一个大小为keypoint的圆圈并显示它的方向
    # 这种方法同时显示图像的坐标,size和方向,是最能显示特征的一种绘制方式
    keypoints_image = cv.drawKeypoints(
        gray_image, keypoints, None, flags=cv.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
    
    # 返回带关键点的图像、关键点和sift的特征向量
    return keypoints_image, keypoints, features


# 使用KNN检测来自左右图像的SIFT特征,随后进行匹配
def get_feature_point_ensemble(features_right, features_left):
    # 创建BFMatcher对象解决匹配
    bf = cv.BFMatcher()
    # knnMatch()函数:返回每个特征点的最佳匹配k个匹配点
    matches = bf.knnMatch(features_right, features_left, k=2)  # des1为模板图,des2为匹配图
    # 利用sorted()函数对matches对象进行升序(默认)操作
    matches = sorted(matches, key=lambda x: x[0].distance / x[1].distance)
    # x:x[]字母可以随意修改,排序方式按照中括号[]里面的维度进行排序,[0]按照第一维排序,[2]按照第三维排序

    # 建立列表good用于存储匹配的点集
    good = []
    for m, n in matches:
    # ratio的值越大,匹配的线条越密集,但错误匹配点也会增多
    	ratio=0.6
        if m.distance < ratio * n.distance:
            good.append(m)
    return good


# 计算视角变换矩阵H,用H对右图进行变换并返回全景拼接图像
def Panorama_stitching(image_right, image_left):
    _, keypoints_right, features_right = sift_keypoints_detect(image_right)
    _, keypoints_left, features_left = sift_keypoints_detect(image_left)
    goodMatch = get_feature_point_ensemble(features_right, features_left)

    # 当筛选项的匹配对大于4对(因为homography单应性矩阵的计算需要至少四个点)时,计算视角变换矩阵
    if len(goodMatch) > 4:
        # 获取匹配对的点坐标
        ptsR = np.float32(
            [keypoints_right[m.queryIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
        ptsL = np.float32(
            [keypoints_left[m.trainIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
        
        # ransacReprojThreshold:将点对视为内点的最大允许重投影错误阈值(仅用于RANSAC和RHO方法时),若srcPoints和dstPoints是以像素为单位的,该参数通常设置在1到10的范围内
        ransacReprojThreshold = 4
        
        # cv.findHomography():计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列),使用最小均方误差或者RANSAC方法
        # 函数作用:利用基于RANSAC的鲁棒算法选择最优的四组配对点,再计算转换矩阵H(3*3)并返回,以便于反向投影错误率达到最小
        Homography, status = cv.findHomography(
            ptsR, ptsL, cv.RANSAC, ransacReprojThreshold)

        # cv.warpPerspective():透视变换函数,用于解决cv2.warpAffine()不能处理视场和图像不平行的问题
        # 作用:就是对图像进行透视变换,可保持直线不变形,但是平行线可能不再平行
        result = cv.warpPerspective(
            image_right, Homography, (image_right.shape[1] + image_left.shape[1], image_right.shape[0]))
        
        cv.imshow("扭曲变换后的右图", result)
        cv.waitKey(0)
        cv.destroyAllWindows()
        # 将左图加入到变换后的右图像的左端即获得最终图像
        result[0:image_left.shape[0], 0:image_left.shape[1]] = image_left
        
        # 返回全景拼接的图像
        return result


if __name__ == '__main__':

    # 读取需要拼接的图像,需要注意图像左右的顺序
    image_left = cv.imread("./Left.jpg")
    image_right = cv.imread("./Right.jpg")

    # 通过调用cv2.resize()使用插值的方式来改变图像的尺寸,保证左右两张图像大小一致
    # cv.resize()函数中的第二个形参dsize表示输出图像大小尺寸,当设置为0(None)时,则表示按fx与fy与原始图像大小相乘得到输出图像尺寸大小
    image_right = cv.resize(image_right, None, fx=0.4, fy=0.24)
    image_left = cv.resize(image_left, (image_right.shape[1], image_right.shape[0]))

    # 获取检测到关键点后的图像的相关参数
    keypoints_image_right, keypoints_right, features_right = sift_keypoints_detect(image_right)
    keypoints_image_left, keypoints_left, features_left = sift_keypoints_detect(image_left)

    # 利用np.hstack()函数同时将原图和绘有关键点的图像沿着竖直方向(水平顺序)堆叠起来
    cv.imshow("左图关键点检测", np.hstack((image_left, keypoints_image_left)))
    # 一般在imshow后设置 waitKey(0) , 代表按任意键继续
    cv.waitKey(0)
    # 删除先前建立的窗口
    cv.destroyAllWindows()
    cv.imshow("右图关键点检测", np.hstack((image_right, keypoints_image_right)))
    cv.waitKey(0)
    cv.destroyAllWindows()
    goodMatch = get_feature_point_ensemble(features_right, features_left)

    # cv.drawMatches():在提取两幅图像特征之后,画出匹配点对连线
    # matchColor ? 匹配的颜色(特征点和连线),若matchColor==Scalar::all(-1),颜色随机
    all_goodmatch_image = cv.drawMatches(
        image_right, keypoints_right, image_left, keypoints_left, goodMatch, None, None, None, None, flags=2)
    cv.imshow("所有匹配的SIFT关键特征点连线", all_goodmatch_image)
    cv.waitKey(0)
    cv.destroyAllWindows()

    # 把图片拼接成全景图并保存
    result = Panorama_stitching(image_right, image_left)
    cv.namedWindow("全景图", cv.WINDOW_AUTOSIZE)
    cv.imshow("全景图", result)
    cv.imwrite("./全景图.jpg", result)
    cv.waitKey(0)
    cv.destroyAllWindows()

左图关键特征点检测

基于Python和openCV实现图像的全景拼接详细步骤

右图关键特征点检测

基于Python和openCV实现图像的全景拼接详细步骤

所有匹配的SIFT关键特征点连线

基于Python和openCV实现图像的全景拼接详细步骤

扭曲变换后的右图

基于Python和openCV实现图像的全景拼接详细步骤

全景图

基于Python和openCV实现图像的全景拼接详细步骤

由于输入的左右图像之间有大量重叠,导致全景图的主要添加部分是在拼接图像的右侧,因此会造成拼接后全景图右边大量的黑色空白区域。

到此这篇关于基于Python和openCV实现图像的全景拼接的文章就介绍到这了,更多相关Python openCV实现图像的全景拼接内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python 调用VC++的动态链接库(DLL)
Sep 06 Python
跟老齐学Python之编写类之三子类
Oct 11 Python
零基础写python爬虫之urllib2使用指南
Nov 05 Python
详解Python发送邮件实例
Jan 10 Python
使用pygame模块编写贪吃蛇的实例讲解
Feb 05 Python
Python自定义线程类简单示例
Mar 23 Python
Python global全局变量函数详解
Sep 18 Python
浅谈numpy生成数组的零值问题
Nov 12 Python
Pyspark获取并处理RDD数据代码实例
Mar 27 Python
python 实现仿微信聊天时间格式化显示的代码
Apr 17 Python
聊聊python中的循环遍历
Sep 07 Python
Python接口自动化系列之unittest结合ddt的使用教程详解
Feb 23 Python
C3 线性化算法与 MRO之Python中的多继承
Python编程super应用场景及示例解析
Python编程源码报错解决方法总结经验分享
Oct 05 #Python
Python编程根据字典列表相同键的值进行合并
Oct 05 #Python
python编程简单几行代码实现视频转换Gif示例
用 Python 定义 Schema 并生成 Parquet 文件详情
Sep 25 #Python
使用pipenv管理python虚拟环境的全过程
Sep 25 #Python
You might like
一个很方便的 XML 类!!原创的噢
2006/10/09 PHP
PHP CURL 内存泄露问题解决方法
2015/02/12 PHP
php使用ob_flush不能每隔一秒输出原理分析
2015/06/02 PHP
javascript 精粹笔记
2010/05/09 Javascript
jQuery autocomplate 自扩展插件、自动完成示例代码
2011/03/28 Javascript
poshytip 基于jquery的 插件 主要用于显示微博人的图像和鼠标提示等
2012/10/12 Javascript
jQuery实现长按按钮触发事件的方法
2015/02/02 Javascript
JS前端笔试题分析
2016/12/19 Javascript
前端自动化开发之Node.js的环境搭建教程
2017/04/01 Javascript
JS基于设计模式中的单例模式(Singleton)实现封装对数据增删改查功能
2018/02/06 Javascript
vue-cli项目根据线上环境分别打出测试包和生产包
2018/05/23 Javascript
vue.js实现的经典计算器/科学计算器功能示例
2018/07/11 Javascript
vue和H5 draggable实现拖拽并替换效果
2020/07/29 Javascript
Vue用mixin合并重复代码的实现
2020/11/27 Vue.js
[05:02]2014DOTA2 TI中国区预选赛精彩TOPPLAY第三弹
2014/06/25 DOTA
[01:55]2014DOTA2国际邀请赛 BBC正赛第一天总结
2014/07/10 DOTA
python使用在线API查询IP对应的地理位置信息实例
2014/06/01 Python
Python类属性与实例属性用法分析
2015/05/09 Python
Python字符串格式化
2015/06/15 Python
Python实现1-9数组形成的结果为100的所有运算式的示例
2017/11/03 Python
windows环境下tensorflow安装过程详解
2018/03/30 Python
Python打开文件,将list、numpy数组内容写入txt文件中的方法
2018/10/26 Python
使用Python制作缩放自如的圣诞老人(圣诞树)
2019/12/25 Python
CSS3+JavaScript实现炫酷呼吸效果的示例代码
2020/06/15 HTML / CSS
Janie and Jack美国官网:GAP旗下的高档童装品牌
2019/09/09 全球购物
Deux par Deux官方网站:设计师童装
2020/01/03 全球购物
abstract class和interface有什么区别?
2012/01/03 面试题
Python如何实现单例模式
2016/06/03 面试题
公路绿化方案
2014/05/12 职场文书
六一亲子活动总结
2014/07/01 职场文书
解除劳动关系协议书范文
2014/09/11 职场文书
机关作风建设工作总结
2014/10/23 职场文书
怎样写观后感
2015/06/19 职场文书
2021年pycharm的最新安装教程及基本使用图文详解
2021/04/03 Python
Python标准库之typing的用法(类型标注)
2021/06/02 Python
JavaScript正则表达式实现注册信息校验功能
2022/05/30 Java/Android