《计算机视觉》——图像拼接

news/2025/2/25 7:11:11

图像拼接

  • 图像拼接是将多幅有重叠区域的图像合并成一幅全景或更大视角图像的技术,以下为你详细介绍:
    • 原理:图像拼接的核心原理是基于图像之间的特征匹配。首先,从每幅图像中提取独特的特征点,如角点、边缘点等,这些特征点具有在不同图像中能被准确识别的特点。然后,通过计算特征点之间的相似度,找到不同图像中相匹配的特征点对。一旦确定了匹配点,就可以根据这些点来计算图像之间的变换关系,如平移、旋转、缩放等,从而将图像对齐到同一坐标系中。最后,将对齐后的图像进行融合,消除拼接缝隙,生成一幅无缝的拼接图像。

主要步骤

  • 特征提取:常用的特征提取算法有 SIFT(尺度不变特征变换)、SURF(加速稳健特征)和 ORB(加速的具有旋转不变性的 FAST 特征点和 BRIEF 描述子)等。这些算法可以在不同光照、尺度和旋转条件下,稳定地提取图像中的特征点。
  • 特征匹配:通过计算特征点的描述子之间的距离(如欧氏距离),找到不同图像中相似的特征点对。为了提高匹配的准确性,通常会使用一些匹配策略,如最近邻匹配、比率测试等。
  • 图像变换:根据匹配点计算出图像之间的变换矩阵,然后将其中一幅图像进行变换,使其与另一幅图像对齐。常见的变换模型有仿射变换、透视变换等。
  • 图像融合:将对齐后的图像进行融合,以消除拼接缝隙。常用的融合方法有加权平均融合、多分辨率融合等。

应用领域

  • 全景摄影:通过拍摄多张不同角度的照片,然后拼接成一幅全景图像,为用户提供更广阔的视野。
  • 医学图像:在医学领域,将多幅显微镜图像或 X 光图像拼接成一幅完整的图像,以便医生更全面地观察病变区域。
  • 计算机视觉:在机器人导航、自动驾驶等领域,图像拼接技术可以帮助系统获取更广阔的环境信息,提高系统的感知能力。
  • 文物保护与修复:对破损的文物图像进行拼接和修复,恢复文物的原貌。

实例

对两张图片进行拼接:图片1在这里插入图片描述
图片2
在这里插入图片描述

代码

  • 导入模块
# 导入OpenCV库,用于计算机视觉任务,如图像读取、处理和显示等
import cv2
# 导入NumPy库,用于处理多维数组和矩阵运算
import numpy as np
# 导入sys模块,用于与Python解释器进行交互,这里主要用于退出程序
import sys
  • 定义显示图像
# 定义一个函数用于显示图像
def cv_show(name, img):
    # 在名为name的窗口中显示图像img
    cv2.imshow(name, img)
    # 等待用户按键,按任意键后关闭窗口
    cv2.waitKey(0)
  • 定义检测关键点
# 定义一个函数用于检测图像中的关键点并提取特征描述符
def detectAndDescribe(image):
    # 将输入的彩色图像转换为灰度图像,因为SIFT算法通常在灰度图像上进行处理
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 创建一个SIFT(尺度不变特征变换)特征检测器和描述符对象
    descriptor = cv2.SIFT_create()
    # 使用SIFT对象检测图像中的关键点并计算其特征描述符
    # kps是关键点对象列表,des是对应的特征描述符矩阵
    (kps, des) = descriptor.detectAndCompute(gray, None)
    # 将关键点的坐标从关键点对象中提取出来,并转换为NumPy的浮点型数组
    kps_float = np.float32([kp.pt for kp in kps])
    # 返回关键点对象列表、关键点坐标数组和特征描述符矩阵
    return (kps, kps_float, des)
  • 读取图像显示图像
# 读取第一张图像,图像文件名为'1.jpg'
imageA = cv2.imread('1.jpg')
# 读取第二张图像,图像文件名为'2.jpg'
imageB = cv2.imread('2.jpg')
# 显示第一张图像,窗口名为'imageA'
cv_show('imageA', imageA)
# 显示第二张图像,窗口名为'imageB'
cv_show('imageB', imageB)

在这里插入图片描述
在这里插入图片描述

  • 进行关键点检测和特征描述符提取
# 对第一张图像进行关键点检测和特征描述符提取
(kpsA, kps_floatA, desA) = detectAndDescribe(imageA)
# 对第二张图像进行关键点检测和特征描述符提取
(kpsB, kps_floatB, desB) = detectAndDescribe(imageB)
  • 创建暴力匹配器对象
# 创建一个暴力匹配器对象,用于匹配特征描述符
matcher = cv2.BFMatcher()
  • 特征匹配
# 使用K近邻匹配算法对第二张图像和第一张图像的特征描述符进行匹配
# 这里的2表示每个查询描述符返回两个最近邻的匹配结果
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列表中
        good.append(m)
        # 将匹配点的索引对添加到matches列表中
        matches.append((m[0].queryIdx, m[0].trainIdx))
  • 绘制匹配关键点
# 在两张图像上绘制满足条件的匹配关键点
# flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS表示绘制带有关键点信息的匹配线
vis = cv2.drawMatchesKnn(imageB, kpsB, imageA, kpsA, good, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# 显示绘制了匹配关键点的图像,窗口名为'Keypoint Matches'
cv_show('Keypoint Matches', vis)

在这里插入图片描述

  • 透视变换
# 检查匹配点的数量是否大于4
if len(matches) > 4:
    # 提取第二张图像中匹配点的坐标
    ptsB = np.float32([kps_floatB[i] for (i, _) in matches])
    # 提取第一张图像中匹配点的坐标
    ptsA = np.float32([kps_floatA[i] for (_, i) in matches])
    # 使用RANSAC算法计算从第二张图像到第一张图像的单应性矩阵H
    # 10是RANSAC算法的阈值
    (H, mask) = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, 10)
else:
    # 如果匹配点数量小于等于4,打印提示信息
    print('图片未找到四个以上的匹配点')
    # 退出程序
    sys.exit()

# 使用计算得到的单应性矩阵H对第二张图像进行透视变换
# 变换后的图像宽度为两张图像宽度之和,高度为第二张图像的高度
result = cv2.warpPerspective(imageB, H, (imageB.shape[1] + imageA.shape[1], imageB.shape[0]))
# 显示透视变换后的第二张图像,窗口名为'resultB'
cv_show('resultB', result)

在这里插入图片描述

  • 进行拼接
# 将第一张图像复制到透视变换后的图像的左上角
result[0:imageA.shape[0], 0:imageA.shape[1]] = imageA
# 显示拼接后的最终图像,窗口名为'result'
cv_show('result', result)

在这里插入图片描述


http://www.niftyadmin.cn/n/5865143.html

相关文章

Hadoop--Secondary NameNode工作机制,作用及与NameNode HA的区别

Secondary NameNode 主要用于辅助 NameNode 进行元数据的管理和检查点&#xff08;Checkpoint&#xff09;的生成。 1. Secondary NameNode 的工作机制详解 Secondary NameNode 的工作机制可以分为以下步骤&#xff1a; ① Secondary NameNode 询问 NameNode 是否需要 Check…

为什么java从json中获取值有数据类型,而从xml中获取值没有数据类型?

在 Java 中处理 JSON 和 XML 数据时,表面上看起来从 JSON 中获取的值具有数据类型,而从 XML 中获取的值没有,但实际上这是由 JSON 和 XML 的本质特点决定的。 JSON 的本质特点 语法结构:JSON(JavaScript Object Notation)是基于键值对的文本格式,结构清晰,适合表示数据…

首次使用WordPress建站的经验分享(一)

之前用过几种内容管理系统(CMS),如:dedeCMS、phpCMS、aspCMS,主要是为了前端独立建站,达到预期的效果,还是需要一定的代码基础的,至少要有HTML、Css、Jquery基础。 据说WordPress 是全球最流行的内容管理系统CMS,从现在开始记录一下使用WordPress 独立建站的步骤 选购…

VSCODE 终端执行PNPM 命令出错

1、编译错误 错误提示&#xff1a; pnpm : 无法加载文件 C:\Users\AppData\Roaming\npm\pnpm.ps1 在终点命令行执行&#xff1a;get-ExecutionPolicy 如果显示 Restricted 执行命令&#xff1a;Set-ExecutionPolicy -Scope CurrentUser RemoteSigned 修改后&#xff1a;…

Web Worker终极优化指南:4秒卡顿→0延迟的实战蜕变

&#x1f4a1; 导读&#xff1a;从4秒卡顿到丝滑响应 真实痛点场景&#xff1a;当斐波那契数列计算量达10亿次时&#xff0c;页面完全冻结4.2秒&#xff01;通过Web Worker优化后&#xff0c;UI响应时间降至16ms以内。本文手把手带您实现性能蜕变&#xff01; 一、Web Worker核…

深度优先搜索(DFS)在 Spark 中的应用与实现

深度优先搜索&#xff08;DFS&#xff09;在 Spark 中的应用与实现 深度优先搜索&#xff08;Depth-First Search, DFS&#xff09;是一种经典的图遍历算法&#xff0c;广泛应用于图论、路径搜索、连通性检测等场景。在 Spark 中&#xff0c;DFS 可以用于处理图数据&#xff0…

在 MySQL 的 InnoDB 存储引擎中,部分数据库优化策略

在 MySQL 的 InnoDB 存储引擎中&#xff0c;以下操作是 同步的&#xff0c;并且会直接影响数据库执行 SQL 的效率&#xff1a; 1. Redo Log 的同步刷盘&#xff08;事务提交时&#xff09; 触发条件&#xff1a; 当 innodb_flush_log_at_trx_commit1 时&#xff0c;事务提交时强…

GreatSQL修改配置文件参数无法生效

GreatSQL修改配置文件参数无法生效 一、问题描述 客户需要创建无主键表&#xff0c;因提供默认模板设置了参数sql_require_primary_key ON&#xff08;创建新表或更改现有表结构的语句强制要求表具有主键&#xff09;&#xff0c;当创建无主键表时会提示ERROR 3750 (HY000):…