了解
SIFT算法可以应用于图像拼接的例子上。通过SIFT,可以将多张图片拼接成全景图片。
定义
Sift(尺度不变特征变换),全称是Scale Invariant Feature Transform Sift提取图像的局部特征,在尺度空间寻找极值点,并提取出其位置、尺度、方向信息。
特点
- 对旋转、尺度缩放、亮度变化保持不变性,对视角变化、噪声等也存在一定程度的稳定性;
- 独特性,信息量丰富,适用于在海量特征数据中进行快速,准确的匹配;
- 多量性,即使少数几个物体也可以产生大量的Sfit特征向量;
- 可扩展性,可以很方便的与其他形式的特征向量进行联合;
应用
Sfit的应用范围包括物体辨别、机器人地图感知与导航、影像拼接、3D模型建立、手势识别、影像追踪等。
实质
Note:SIFT函数注册了专利,在商业用途上是收费的。将在opencv > 3.4.3中,不再提供。【可以降低python版本或者交钱】
Sift算法原理
大致步骤
1.生成高斯差分金字塔(DOG金字塔),尺度空间构建 2. 空间极值点检测(关键点的初步查探) 3. 稳定关键点的精确定位 4. 稳定关键点方向信息分配 5. 关键点描述 6. 特征点匹配
step1.构建高斯差分金字塔
图像金字塔
尺寸发生变化,分辨率也发生变换。
获得图像金字塔一般包括二个步骤:
- 利用滤波器平滑图像(高斯滤波)
- 对平滑图像进行抽样(采样)有两种采样方式——上采样(分辨率逐级升高)和下采样(分辨率逐级降低)
高斯金字塔
概念
*主要思想是通过对原始图像进行尺度变换,获得图像多尺度下的尺度空间表示序列,对这些序列进行尺度空间主轮廓的提取,并以该主轮廓作为一种特征向量,实现边缘、角点检测不同分辨率上的关键点提取等。各尺度下图像的模糊度逐渐变大,能够模拟人在距离目标由近到远时目标物体在视网膜上的形成过程。
尺度空间构建的基础是DOG金字塔,DOG金字塔构建的基础是高斯金字塔。
高斯金字塔式在Sift算子中提出来的概念,首先高斯金字塔并不是一个金字塔,而是有很多组(Octave)金字塔构成,并且每组金字塔都包含若干层(Interval)。
搭建过程
高斯金字塔构建过程:
- 先将原图像扩大一倍之后作为高斯金字塔的第1组第1层,将第1组第1层图像经高斯卷积(其实就是高斯平滑或称高斯滤波)之后作为第1组金字塔的第2层,高斯卷积函数为:
对于参数σ,在Sift算子中取的是固定值1.6。
-
将σ乘以一个比例系数k,等到一个新的平滑因子σ=k*σ,用它来平滑第1组第2层图像,结果图像作为第3层。 -
如此这般重复,最后得到L层图像,在同一组中,每一层图像的尺寸都是一样的,只是平滑系数不一样。它们对应的平滑系数分别为:0,σ,kσ,k2σ,k3σ……k^(L-2)σ。 -
将第1组倒数第三层图像作比例因子为2的降采样,得到的图像作为第2组的第1层,然后对第2组的第1层图像做平滑因子为σ的高斯平滑,得到第2组的第2层,就像步骤2中一样,如此得到第2组的L层图像,同组内它们的尺寸是一样的,对应的平滑系数分别为:0,σ,kσ,k2σ,k3σ……k^(L-2)σ。但是在尺寸方面第2组是第1组图像的一半。
这样反复执行,就可以得到一共O组,每组L层,共计O*L个图像,这些图像一起就构成了高斯金字塔,结构如下:
不同人站在不同地方看同一颗树的感觉。 在同一组内,不同层图像的尺寸是一样的,后一层图像的高斯平滑因子σ是前一层图像平滑因子的k倍; 在不同组内,后一组第一个图像是前一组倒数第三个图像的二分之一采样,图像大小是前一组的一半;
高斯金字塔图像效果如下,分别是第1组的4层和第2组的4层:
尺度空间
尺度空间:试图在图像领域中模拟人眼观察物体的概念与方法。
图像的尺度空间解决的问题是如何对图像在所有尺度下描述的问题。
在高斯金字塔中一共生成O组L层不同尺度的图像,这两个量合起来(O,L)就构成了高斯金字塔的尺度空间,也就是说以高斯金字塔的组O作为二维坐标系的一个坐标,不同层L作为另一个坐标,则给定的一组坐标(O,L)就可以唯一确定高斯金字塔中的一幅图像。
尺度空间的形象表述:
差分金字塔[DOG金字塔]
差分金字塔,DOG(Difference of Gaussian)金字塔是在高斯金字塔的基础上构建起来的,其实生成高斯金字塔的目的就是为了构建DOG金字塔。
DOG金字塔的第1组第1层是由高斯金字塔的第1组第2层减第1组第1层得到的。以此类推,逐组逐层生成每一个差分图像,所有差分图像构成差分金字塔。概括为DOG金字塔的第o组第l层图像是有高斯金字塔的第o组第l+1层减第o组第l层得到的。
DOG金字塔的构建可以用下图描述:
差分金字塔 归一化
step2:空间极值点检测
s:每组图像中检测s个尺度的极值点。(例如,第一幅图中就是检测3个尺度的极值点) 对应关系:如果我们要检测3个尺度的极值点,那么DOG就要5层(3+2),高斯图像就要比DOG多1层,所以高斯金字塔要6层(举个例子就会了)
step3:稳定关键点的精确定位
DOG值对噪声和边缘比较敏感,所以在第2步的尺度空间中检测到的局部极值点还要经过进一步的筛 选,去除不稳定和错误检测出的极值点。 利用阈值的方法来限制,在opencv中为contrastThreshold。
step4:稳定关键点方向信息分配
step5:关键点描述
step6:关键点匹配
代码实现
SIFT关键点:
import cv2
import numpy as np
img = cv2.imread("lenna.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
sift = cv2.xfeatures2d.SIFT_create()
keypoints, descriptor = sift.detectAndCompute(gray, None)
img = cv2.drawKeypoints(image=img, outImage=img, keypoints=keypoints,
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,
color=(51, 163, 236))
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.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1_gray, None)
kp2, des2 = sift.detectAndCompute(img2_gray, None)
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)
drawMatchesKnn_cv2(img1_gray,kp1,img2_gray,kp2,goodMatch[:20])
cv2.waitKey(0)
cv2.destroyAllWindows()
|