计算机视觉基础 尺度不变特征变换-SIFT

文章目录

  • 了解
    • 定义
    • 特点
    • 应用
    • 实质
  • Sift算法原理
    • 大致步骤
    • step1.构建高斯差分金字塔
      • 图像金字塔
      • 高斯金字塔
        • 概念
        • 搭建过程
      • 尺度空间
      • 差分金字塔[DOG金字塔]
    • step2:空间极值点检测
    • step3:稳定关键点的精确定位
    • step4:稳定关键点方向信息分配
    • step5:关键点描述
    • step6:关键点匹配
  • 代码实现

了解

SIFT算法可以应用于图像拼接的例子上。通过SIFT,可以将多张图片拼接成全景图片。
计算机视觉基础 尺度不变特征变换-SIFT_第1张图片
计算机视觉基础 尺度不变特征变换-SIFT_第2张图片
计算机视觉基础 尺度不变特征变换-SIFT_第3张图片
计算机视觉基础 尺度不变特征变换-SIFT_第4张图片

定义

Sift(尺度不变特征变换),全称是Scale Invariant Feature Transform
Sift提取图像的局部特征,在尺度空间寻找极值点,并提取出其位置、尺度、方向信息。

特点

  1. 对旋转、尺度缩放、亮度变化保持不变性,对视角变化、噪声等也存在一定程度的稳定性;
  2. 独特性,信息量丰富,适用于在海量特征数据中进行快速,准确的匹配;
  3. 多量性,即使少数几个物体也可以产生大量的Sfit特征向量;
  4. 可扩展性,可以很方便的与其他形式的特征向量进行联合;

应用

Sfit的应用范围包括物体辨别、机器人地图感知与导航、影像拼接、3D模型建立、手势识别、影像追踪等

实质

计算机视觉基础 尺度不变特征变换-SIFT_第5张图片
Note:SIFT函数注册了专利,在商业用途上是收费的。将在opencv > 3.4.3中,不再提供。【可以降低python版本或者交钱】

Sift算法原理

大致步骤

1.生成高斯差分金字塔(DOG金字塔),尺度空间构建
2. 空间极值点检测(关键点的初步查探)
3. 稳定关键点的精确定位
4. 稳定关键点方向信息分配
5. 关键点描述
6. 特征点匹配

step1.构建高斯差分金字塔

图像金字塔

计算机视觉基础 尺度不变特征变换-SIFT_第6张图片
尺寸发生变化,分辨率也发生变换。

获得图像金字塔一般包括二个步骤:

  1. 利用滤波器平滑图像(高斯滤波)
  2. 对平滑图像进行抽样(采样)有两种采样方式——上采样(分辨率逐级升高)和下采样(分辨率逐级降低)

高斯金字塔

概念

*主要思想是通过对原始图像进行尺度变换,获得图像多尺度下的尺度空间表示序列,对这些序列进行尺度空间主轮廓的提取,并以该主轮廓作为一种特征向量,实现边缘、角点检测不同分辨率上的关键点提取等。各尺度下图像的模糊度逐渐变大,能够模拟人在距离目标由近到远时目标物体在视网膜上的形成过程。

尺度空间构建的基础是DOG金字塔,DOG金字塔构建的基础是高斯金字塔。

高斯金字塔式在Sift算子中提出来的概念,首先高斯金字塔并不是一个金字塔,而是有很多组(Octave)金字塔构成,并且每组金字塔都包含若干层(Interval)。

搭建过程

高斯金字塔构建过程:

  1. 先将原图像扩大一倍之后作为高斯金字塔的第1组第1层,将第1组第1层图像经高斯卷积(其实就是高斯平滑或称高斯滤波)之后作为第1组金字塔的第2层,高斯卷积函数为:
    在这里插入图片描述

对于参数σ,在Sift算子中取的是固定值1.6。

  1. 将σ乘以一个比例系数k,等到一个新的平滑因子σ=k*σ,用它来平滑第1组第2层图像,结果图像作为第3层。

  2. 如此这般重复,最后得到L层图像,在同一组中,每一层图像的尺寸都是一样的,只是平滑系数不一样。它们对应的平滑系数分别为:0,σ,kσ,k2σ,k3σ……k^(L-2)σ。

  3. 将第1组倒数第三层图像作比例因子为2的降采样,得到的图像作为第2组的第1层,然后对第2组的第1层图像做平滑因子为σ的高斯平滑,得到第2组的第2层,就像步骤2中一样,如此得到第2组的L层图像,同组内它们的尺寸是一样的,对应的平滑系数分别为:0,σ,kσ,k2σ,k3σ……k^(L-2)σ。但是在尺寸方面第2组是第1组图像的一半。

这样反复执行,就可以得到一共O组,每组L层,共计O*L个图像,这些图像一起就构成了高斯金字塔,结构如下:

不同人站在不同地方看同一颗树的感觉。
计算机视觉基础 尺度不变特征变换-SIFT_第7张图片
在同一组内,不同层图像的尺寸是一样的,后一层图像的高斯平滑因子σ是前一层图像平滑因子的k倍;
在不同组内,后一组第一个图像是前一组倒数第三个图像的二分之一采样,图像大小是前一组的一半;

高斯金字塔图像效果如下,分别是第1组的4层和第2组的4层:
计算机视觉基础 尺度不变特征变换-SIFT_第8张图片

尺度空间

计算机视觉基础 尺度不变特征变换-SIFT_第9张图片
尺度空间:试图在图像领域中模拟人眼观察物体的概念与方法。

图像的尺度空间解决的问题是如何对图像在所有尺度下描述的问题。

在高斯金字塔中一共生成O组L层不同尺度的图像,这两个量合起来(O,L)就构成了高斯金字塔的尺度空间,也就是说以高斯金字塔的组O作为二维坐标系的一个坐标,不同层L作为另一个坐标,则给定的一组坐标(O,L)就可以唯一确定高斯金字塔中的一幅图像。

尺度空间的形象表述:
计算机视觉基础 尺度不变特征变换-SIFT_第10张图片
计算机视觉基础 尺度不变特征变换-SIFT_第11张图片

差分金字塔[DOG金字塔]

差分金字塔,DOG(Difference of Gaussian)金字塔是在高斯金字塔的基础上构建起来的,其实生成高斯金字塔的目的就是为了构建DOG金字塔。

DOG金字塔的第1组第1层是由高斯金字塔的第1组第2层减第1组第1层得到的。以此类推,逐组逐层生成每一个差分图像,所有差分图像构成差分金字塔。概括为DOG金字塔的第o组第l层图像是有高斯金字塔的第o组第l+1层减第o组第l层得到的。

DOG金字塔的构建可以用下图描述:

计算机视觉基础 尺度不变特征变换-SIFT_第12张图片
差分金字塔
计算机视觉基础 尺度不变特征变换-SIFT_第13张图片
归一化
计算机视觉基础 尺度不变特征变换-SIFT_第14张图片

step2:空间极值点检测

计算机视觉基础 尺度不变特征变换-SIFT_第15张图片

计算机视觉基础 尺度不变特征变换-SIFT_第16张图片
s:每组图像中检测s个尺度的极值点。(例如,第一幅图中就是检测3个尺度的极值点)
对应关系:如果我们要检测3个尺度的极值点,那么DOG就要5层(3+2),高斯图像就要比DOG多1层,所以高斯金字塔要6层(举个例子就会了)

step3:稳定关键点的精确定位

DOG值对噪声和边缘比较敏感,所以在第2步的尺度空间中检测到的局部极值点还要经过进一步的筛
选,去除不稳定和错误检测出的极值点。
利用阈值的方法来限制,在opencv中为contrastThreshold

step4:稳定关键点方向信息分配

计算机视觉基础 尺度不变特征变换-SIFT_第17张图片
计算机视觉基础 尺度不变特征变换-SIFT_第18张图片

step5:关键点描述

计算机视觉基础 尺度不变特征变换-SIFT_第19张图片
计算机视觉基础 尺度不变特征变换-SIFT_第20张图片

step6:关键点匹配

计算机视觉基础 尺度不变特征变换-SIFT_第21张图片

代码实现

SIFT关键点:


import cv2
import numpy as np

img = cv2.imread("lenna.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#创建sift检测器,这个sift检测器主要是用于检测模板和待匹配图像的特征关键点点
sift = cv2.xfeatures2d.SIFT_create()
#利用创建好的特征点检测器去检测两幅图像的特征关键点,
# 其中keypoints含有角度、关键点坐标等多个信息,提取出坐标点的坐标
# descriptor是特征描述符,每一个特征点对应了一个特征描述符,由一维特征向量构成
keypoints, descriptor = sift.detectAndCompute(gray, None)

# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS对图像的每个关键点都绘制了圆圈和方向。
img = cv2.drawKeypoints(image=img, outImage=img, keypoints=keypoints,
                        flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,
                        color=(51, 163, 236))

# img=cv2.drawKeypoints(gray,keypoints,img)

cv2.imshow('sift_keypoints', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

SIFT特征匹配:

import cv2
import numpy as np
  
def drawMatchesKnn_cv2(img1_gray,kp1,img2_gray,kp2,goodMatch):
    h1, w1 = img1_gray.shape[:2]
    h2, w2 = img2_gray.shape[:2]
  
    vis = np.zeros((max(h1, h2), w1 + w2, 3), np.uint8)
    vis[:h1, :w1] = img1_gray
    vis[:h2, w1:w1 + w2] = img2_gray
  
    p1 = [kpp.queryIdx for kpp in goodMatch]
    p2 = [kpp.trainIdx for kpp in goodMatch]
  
    post1 = np.int32([kp1[pp].pt for pp in p1])
    post2 = np.int32([kp2[pp].pt for pp in p2]) + (w1, 0)
  
    for (x1, y1), (x2, y2) in zip(post1, post2):
        cv2.line(vis, (x1, y1), (x2, y2), (0,0,255))
  
    cv2.namedWindow("match",cv2.WINDOW_NORMAL)
    cv2.imshow("match", vis)
  
img1_gray = cv2.imread("iphone1.png")
img2_gray = cv2.imread("iphone2.png")
  
#sift = cv2.SIFT()
sift = cv2.xfeatures2d.SIFT_create()
#sift = cv2.SURF()
  
kp1, des1 = sift.detectAndCompute(img1_gray, None)
kp2, des2 = sift.detectAndCompute(img2_gray, None)
  
# BFmatcher with default parms
bf = cv2.BFMatcher(cv2.NORM_L2) #建立匹配关系

matches = bf.knnMatch(des1, des2, k = 2)#匹配描述子
  
goodMatch = []
for m,n in matches:
    if m.distance < 0.50*n.distance:
        goodMatch.append(m)
#cv2.drawMatchesKnn()使用的点对集good是一维的,(N,1);画出good中前几个点对连线;
drawMatchesKnn_cv2(img1_gray,kp1,img2_gray,kp2,goodMatch[:20])
  
cv2.waitKey(0)
cv2.destroyAllWindows()

你可能感兴趣的:(计算机视觉小白学习,计算机视觉,图像处理,opencv)