Python-OpenCV中Harris,SIFT特征点提取,SIFT描述子匹配,图片拼接生成全景图

将最近所学opencv的图像处理做个小整理,下期打算整理视频处理的一些记录。

1.使用OpenCV对图像进行Harris,SIFT特征点提取,并标注特征点

更多可以了解 Harris角点检测SIFT特征

· 特征点是啥?

图像处理中,特征点指的是图像灰度值发生剧烈变化的点或者在图像边缘上曲率较大的点(即两个边缘的交点)。图像特征点能够反映图像本质特征,能够标识图像中目标物体。通过特征点的匹配能够完成图像的匹配(来自百度百科)。

局部特征从总体上说是图像或在视觉领域中一些有别于其周围的地方;局部特征通常是描述一块区域,使其能具有高可区分度;局部特征的好坏直接会决定着后面分类、识别是否会得到一个好的结果。
局部特征应该具有的特点: 可重复性、可区分性、准确性、有效性(特征的数量、特征提取的效率)、鲁棒性(稳定性、不变性)。(来自 图像处理之特征提取 )

个人理解就是图像中有显著特征的点,好比人的眼睛这一特征,图像也有特征,但计算机需要通过计算来查找图像的特征点 ,人特征有的特性对于图像特征点也得具备。

· Harris角点算法

Harris角点是特征点检测的基础,提出了应用邻域像素点灰度差值概念,从而进行判断是否为角点,边缘,平滑区域。

Harris角点检测原理是利用移动的窗口在图像中计算灰度变化值,其中关键流程包括转化为灰度图像,计算差分图像,高斯平滑,计算局部极值,确认角点。

大体思路就是通过小窗口来移动,当它朝各个方向移动时它的像素都会变化很大,那么就找到了角点,更多可以了解 cv2.cornerHarris()详解 python+OpenCV 中的 Harris 角点检测

· SIFT算法

SIFT算法的实质是在不同的尺度空间上寻找关键点(特征点),计算关键点的大小,方向,尺度信息,利用这些信息组成关键点对特征点进行描述的问题。SIFT所查找的关键点都是一些十分突出,不会因光照,仿射变换和噪声等因素而变换的“稳定”特征点,如角点,边缘点,暗区的亮点以及亮区的暗点等。

个人简单理解就是通过生成高斯差分金字塔,构建尺度空间,不断找关键点,最后匹配决定出特征点。

代码如下
import cv2
import numpy as np
import imutils


def demo1():
    img = cv2.imread('./blox.png')
    origin = img.copy()

    # Harris特征点提取  
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换成灰度图
    # gray = np.float32(gray)
    # 输入图像必须是 float32 ,最后一个参数在 0.04 到 0.05 之间
    dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)
    dst = cv2.dilate(dst, None)
    img[dst > 0.01 * dst.max()] = [0, 0, 255]
    cv2.imshow('origin', origin)
    cv2.imshow('Harris', img)
    cv2.waitKey(0)

    # SIFT特征检测
    sift = cv2.xfeatures2d.SIFT_create()  # 得到特征点
    kp = sift.detect(gray, None)
    cv2.drawKeypoints(gray, kp, img)
    cv2.imshow('origin', origin)
    cv2.imshow('SIFT', img)
    cv2.waitKey(0)

    cv2.destroyAllWindows()

在这里插入图片描述

在这里插入图片描述

2.使用OpenCV生成特征的SIFT描述子,对两幅有重叠的图片进行描述子匹配
def demo2():
    img_left = cv2.imread('./left.png')
    img_right = cv2.imread('./right.png')
    img_left = cv2.resize(img_left, None, fx=0.8, fy=0.8, interpolation=cv2.INTER_CUBIC)  # 缩放
    img_right = cv2.resize(img_right, None, fx=0.8, fy=0.8, interpolation=cv2.INTER_CUBIC)

    # 创建SIFT特征检测器
    sift = cv2.xfeatures2d.SIFT_create()
    kp1, des1 = sift.detectAndCompute(img_left, None)
    kp2, des2 = sift.detectAndCompute(img_right, None)

    # 暴力匹配
    bf = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_BRUTEFORCE)
    matches = bf.match(des1, des2)

    # 绘制匹配
    matches = sorted(matches, key=lambda x: x.distance)
    result = cv2.drawMatches(img_left, kp1, img_right, kp2, matches[:100], None)
    cv2.imshow("match", result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

在这里插入图片描述

3.使用OpenCV对两幅有重叠的图片匹配后进行拼接,生成全景图
简约写法:

直接调用cv的stitcher类

def demo3():
    # 读取拼接图片
    imageA = cv2.imread("./left.png")
    imageB = cv2.imread("./right.png")
    imageA = cv2.resize(imageA, None, fx=0.7, fy=0.7, interpolation=cv2.INTER_CUBIC)  # 缩放
    imageB = cv2.resize(imageB, None, fx=0.7, fy=0.7, interpolation=cv2.INTER_CUBIC)

    # stitcher = cv2.Stitcher.create(cv2.Stitcher_PANORAMA) #根据不同cv版本选择,高版本选择这种写法
    stitcher = cv2.createStitcher(False)

   (_result, pano) = stitcher.stitch((imageA, imageB))
    if _result != cv2.Stitcher_OK:
        print("不能拼接图片, error code = %d" % _result) #失败的话再多试几次,我觉得可能是每次计算出来的特征点数量不一样,导致不能匹配生成吧
        sys.exit(-1)
    cv2.imshow("match", pano)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

在这里插入图片描述

探索写法:

· cv的stitcher类到底是啥样?

· 并当特征点点对匹配成功时,画到图上

参考 图片拼接SIFT , 但是我个人用的过程中发现,最好保持两张图的高度一致,不然可能拼接不成功或者报错。而且发现stitcher类也是用的SIFT描述子匹配的方法。

class Stitcher:
    # 拼接函数
    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是3*3视角变换矩阵
        (matches, H, status) = M
        # 将图片A进行视角变换, result是变化后图片
        result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
        # 将B图片传入result图片最左端
        result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB

        # 检验是否需要显示图片匹配
        if showMatches:
            # 生成匹配图片
            vis = self.drawMatches(imageA, imageB, kpsA, kpsB, matches, status)
            # 返回结果
            return (result, vis)

    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)

    def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh):
        # 建立暴力匹配器
        matcher = cv2.DescriptorMatcher_create('BruteForce')

        # 使用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)

        return None

    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


def demo3():
    # 读取拼接图片
    # imageA = cv2.imread("./left.png")
    # imageB = cv2.imread("./right.png")
    imageA = cv2.imread("./left_1.jpg")
    imageB = cv2.imread("./right_1.jpg")
    imageA = cv2.resize(imageA, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_CUBIC)  # 缩放
    imageB = cv2.resize(imageB, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_CUBIC)

    # 对图像进行拼接
    stitcher = Stitcher()  # 对类进行实例化
    (result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)
    cv2.imshow('vis.jpg', vis)
    cv2.imshow('result.jpg', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

在这里插入图片描述

  • 4
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Python是一种功能强大的编程语言,在计算机视觉领域广泛应用。OpenCV是一个开源的计算机视觉库,提供了许多处理图像和视频的函数和方法。SIFT是一种常用的特征提取算法,可以在图像检测出关键点,并生成特征向量。在这里,我们将介绍如何使用Python结合OpenCV实现SIFT特征提取匹配。 使用Python实现SIFT特征提取的基本步骤如下: 1. 导入OpenCV库并读取图像 ``` import cv2 img = cv2.imread('image.jpg') ``` 2. 创建SIFT对象并检测关键点 ``` sift = cv2.xfeatures2d.SIFT_create() kp, des = sift.detectAndCompute(img, None) ``` 通过使用SIFT对象的detectAndCompute()函数,我们可以对图像进行关键点检测和特征描述提取,并将结果保存在两个变量kp和des。 3. 可视化关键点并保存图像 ``` img_kp = cv2.drawKeypoints(img, kp, None) cv2.imshow('Keypoints', img_kp) cv2.imwrite('output.jpg', img_kp) cv2.waitKey() ``` 在这个步骤,我们使用drawKeypoints()函数将检测到的关键点绘制在图像上,并可以通过imshow()函数显示图像。然后,我们可以使用imwrite()函数将图像保存到本地。 实现SIFT特征匹配的基本步骤如下: 1. 读取并检测两张图像的关键点和描述符 ``` import cv2 img1 = cv2.imread('image1.jpg') img2 = cv2.imread('image2.jpg') sift = cv2.xfeatures2d.SIFT_create() kp1, des1 = sift.detectAndCompute(img1, None) kp2, des2 = sift.detectAndCompute(img2, None) ``` 2. 创建并运行暴力匹配器 ``` bf = cv2.BFMatcher() matches = bf.knnMatch(des1, des2, k=2) ``` 3. 使用比值测试来筛选出良好的匹配 ``` good_matches = [] for m, n in matches: if m.distance < 0.75 * n.distance: good_matches.append([m]) ``` 4. 可视化匹配点并保存图像 ``` img_matched = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good_matches, None, flags=2) cv2.imshow('Matching result', img_matched) cv2.imwrite('output.jpg', img_matched) cv2.waitKey() ``` 在步骤2,我们使用了暴力匹配器BFMatcher()来对特征描述符进行匹配。knnMatch()函数返回的是最近邻和次近邻的描述符距离,我们可以用比值测试筛选出距离最近的描述符,并将其作为好的匹配。最后,我们使用drawMatchesKnn()可以将匹配点绘制在图像上,并通过imshow()函数显示图像。最后,我们可以通过imwrite()函数保存图像。 综上所述,使用Python结合OpenCV实现SIFT特征提取匹配非常简单。利用OpenCV的函数和方法,我们可以轻松地处理图像和视频,实现各种计算机视觉应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值