首页 > 编程语言 >基于OpenCV的SIFT算法实现图像拼接(全景图像)

基于OpenCV的SIFT算法实现图像拼接(全景图像)

时间:2024-06-09 15:30:02浏览次数:16  
标签:匹配 imageB imageA cv2 OpenCV SIFT 图像

一、SIFT算法

尺度不变特征转换(Scale-invariant feature transform或SIFT)是一种机器视觉的算法用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变数,此算法由David Lowe在1999年所发表,2004年完善总结。

SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。

SIFT算法的步骤

1.尺度空间的极值检测:利用高斯金字塔以及高斯差分函数找出极大值与极小值点,这些极值点被视为可能的关键点。

2.特征点定位:通过一系列的拟合函数模型来找出特征点的位置或者是通过双线性插值找到关键点在不同尺度上的精确位置,确保它们在尺度变化下依然稳定。

3.特征点赋值:对于每个关键点,计算其周围区域的梯度方向图像,然后找到方向直方图。通过选择方向直方图中强度最高的两个方向(邻近角),确定关键点的主方向。

4.特征点描述:基于关键点周围的局部图像,通过高斯滤波、差分、旋转不变性和对比度归一化等操作,生成一个固定长度的SIFT描述符。

详细的操作步骤可以参考有关文章:http://t.csdnimg.cn/iHtdD这里不做过多介绍。

二、图像拼接

图像拼接技术是一种将多个具有重叠部分的图像组合成一幅无缝全景图或高分辨率图像的技术。这项技术在医学成像、计算机视觉、卫星数据处理、军事目标自动识别等领域具有重要应用。图像拼接的基本思想是找到图像之间的映射关系,然后将它们拼接在一起,形成一个统一的视图。

图像拼接通常包括以下几个关键步骤:

  1. 特征检测与提取:在所有输入图像中检测特征点,这些特征点是图像中的像素组,用于后续的图像配准。常用的特征提取方法包括SIFT(尺度不变特征变换)、SURF(加速稳健特征)、FAST(特征加速检测算法)和ORB(Oriented FAST and Rotated BRIEF)等。
  2. 特征匹配:建立图像之间的几何对应关系,使得它们可以在一个共同的参照系中进行变换、比较和分析。这一步骤通常涉及到使用匹配算法,如暴力匹配或KNN(k最近邻)匹配。
  3. 透视变换:根据匹配的特征点计算出图像之间的变换矩阵,通常是单应性矩阵,用于将图像从一个坐标系映射到另一个坐标系。
  4. 图像融合:通过改变边界附近的图像灰度级,去除缝隙,创建混合图像,从而在图像之间实现平滑过渡。混合模式(Blend modes)用于将两层融合到一起。

三、操作实现

这里先展示一下需要拼接的图片

(1)特征提取与检测:

def detectAndDescribe(self, image):
        # 将彩色图片转换成灰度图
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        # 建立SIFT生成器
        descriptor = cv2.xfeatures2d.SIFT_create()
        # 检测SIFT特征点,并计算描述子
        (kps, features) = descriptor.detectAndCompute(image, None)
        # 将结果转换成NumPy数组
        kps = np.float32([kp.pt for kp in kps])
        # 返回特征点集,及对应的描述特征
        return (kps, features)

(2)模版匹配(借助暴力模版匹配)并且计算透视变换矩阵。

def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh):
        # 建立暴力匹配器
        matcher = cv2.BFMatcher()
        # 使用KNN检测来自A、B图的SIFT特征匹配对,K=2
        rawMatches = matcher.knnMatch(featuresA, featuresB, 2)
        matches = []
        for m in rawMatches:
            # 当最近距离跟次近距离的比值小于ratio值时,保留此匹配对
            if len(m) == 2 and m[0].distance < m[1].distance * ratio:
            # 存储两个点在featuresA, featuresB中的索引值
                matches.append((m[0].trainIdx, m[0].queryIdx))
        # 当筛选后的匹配对大于4时,计算视角变换矩阵
        if len(matches) > 4:
            # 获取匹配对的点坐标
            ptsA = np.float32([kpsA[i] for (_, i) in matches])
            ptsB = np.float32([kpsB[i] for (i, _) in matches])
            # 计算视角变换矩阵
            (H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh)
            # 返回结果
            return (matches, H, status)
        # 如果匹配对小于4时,返回None
        return None

(3)初始化拼接图片

def drawMatches(self, imageA, imageB, kpsA, kpsB, matches, status):
        # 初始化可视化图片,将A、B图左右连接到一起
        (hA, wA) = imageA.shape[:2]
        (hB, wB) = imageB.shape[:2]
        vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8")
        vis[0:hA, 0:wA] = imageA
        vis[0:hB, wA:] = imageB

        # 联合遍历,画出匹配对
        for ((trainIdx, queryIdx), s) in zip(matches, status):
            # 当点对匹配成功时,画到可视化图上
            if s == 1:
                # 画出匹配对
                ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
                ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1]))
                cv2.line(vis, ptA, ptB, (0, 255, 0), 1)
        # 返回可视化结果
        return vis

(4)图像融合

def stitch(self, images, ratio=0.75, reprojThresh=4.0,showMatches=False):
        #获取输入图片
        (imageB, imageA) = images
        #检测A、B图片的SIFT关键特征点,并计算特征描述子
        (kpsA, featuresA) = self.detectAndDescribe(imageA)
        (kpsB, featuresB) = self.detectAndDescribe(imageB)
        # 匹配两张图片的所有特征点,返回匹配结果
        M = self.matchKeypoints(kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh)
        # 如果返回结果为空,没有匹配成功的特征点,退出算法
        if M is None:
            return None
        # H是3x3视角变换矩阵    
        (matches, H, status) = M
        # 将图片A进行视角变换,result是变换后图片
        result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
        self.cv_show('result', result)
        # 将图片B传入result图片最左端
        result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
        self.cv_show('result', result)
        # 检测是否需要显示图片匹配
        if showMatches:
            # 生成匹配图片
            vis = self.drawMatches(imageA, imageB, kpsA, kpsB, matches, status)
            # 返回结果
            return (result, vis)

(5)效果展示

# 读取拼接图片
imageA = cv2.imread("left_01.png")
imageB = cv2.imread("right_01.png")

# 把图片拼接成全景图
stitcher = Stitcher()
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)

# 显示所有图片
cv2.imshow("Image A", imageA)
cv2.imshow("Image B", imageB)
cv2.imshow("Keypoint Matches", vis)
cv2.imshow("Result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

标签:匹配,imageB,imageA,cv2,OpenCV,SIFT,图像
From: https://blog.csdn.net/2302_81324947/article/details/139504127

相关文章

  • 【CTF MISC】XCTF GFSJ0290 reverseMe Writeup(图像处理)
    reverseMe暂无解法导入Photoshop。水平翻转,得到flag。Flagflag{4f7548f93c7bef1dc6a0542cf04e796e}声明本博客上发布的所有关于网络攻防技术的文章,仅用于教育和研究目的。所有涉及到的实验操作都在虚拟机或者专门设计的靶机上进行,并且严格遵守了相关法律法......
  • Watermark Sense for Mac(批量图像水印添加工具)v1.4.3版
    WatermarkSensemac是一款为MacOS平台上设计开发的批量图像水印实用程序.WatermarkSenseforMac(图像批量水印工具)使您能够实现伟大创造性的结果,在批处理模式下,节省大量的时间。WatermarkSensemac软件地址WatermarkSenseMac软件功能WatermarkSense支持文本......
  • 【图像融合】基于加权算法实现高分辨率和低分辨率图像融合,含清晰度附Matlab代码
     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......
  • C++ OpenCV 图像分类魔法:探索神奇的模型与代码
    ⭐️我叫忆_恒心,一名喜欢书写博客的研究生......
  • 【python】OpenCV—Blob Detection(11)
    学习来自OpenCV基础(10)使用OpenCV进行Blob检测文章目录1、cv2.SimpleBlobDetector_create中文文档2、默认parameters3、配置parameters附录——cv2.drawKeypoints1、cv2.SimpleBlobDetector_create中文文档cv2.SimpleBlobDetector_create是OpenCV库中用于创......
  • Net AI学习笔记系列第五章 OpenCVSharp实操——图片中物体轮廓查找描绘
    .NetAI学习笔记系列第五章OpenCVSharp实操——图片中物体轮廓查找描绘文章目录.NetAI学习笔记系列前言一、OpenCVSharp实操——图片中物体轮廓查找描绘二、步骤1.开发工具2.引入库3.示例代码4.运行效果总结前言本文主要介绍使用OpenCVSharp中的FindContours......
  • 华为OD刷题C卷 - 每日刷题 13(图像物体的边界,英文输入法)
    1、(图像物体的边界):这段代码是解决“图像物体的边界”的问题。它提供了一个Java类Main,其中包含main方法和getResult方法,以及一个内部UnionFindSet类,用于计算像素1代表的物体的边界个数。main方法首先读取二维数组的行数m和列数n,然后读取二维数组matrix中的像素值。接着,调用......
  • 医学图像分析入门
    医学图像是什么?医学图像是反映解剖区域内部结构或内部功能的图像,它是由一组图像元素--像素(2D)或立体像素(3D)组成的。医学图像是由采样或者重建产生的离散图像,它能将数值映射到不同的空间位置上。像素所表达的具体数值是由成像设备、成像协议、影像重建以及后期加工所决定的。医学......
  • 在Java、Java Web中放置图片、视频、音频、图像文件的方法
    在Java软件中放置图片,通常涉及将图片文件(如JPEG、PNG等)作为资源包含在我们的项目中,并在代码中通过适当的方式引用这些资源。这可以通过多种方式实现,但最常见的是在Java桌面应用(如Swing或JavaFX)或Web应用(如Servlet/JSP)中。1.如何在Java中如何放置图片以下是一个在JavaSwing桌......
  • 在Java、Java Web中放置图片、视频、音频、图像文件的方法
    在Java软件中放置图片,通常涉及将图片文件(如JPEG、PNG等)作为资源包含在我们的项目中,并在代码中通过适当的方式引用这些资源。这可以通过多种方式实现,但最常见的是在Java桌面应用(如Swing或JavaFX)或Web应用(如Servlet/JSP)中。1.如何在Java中如何放置图片以下是一个在JavaSwing桌面......