算法基本思想是使用一个固定窗口在图像上进行任意方向上的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有着较大灰度变化,那么我们可以认为该窗口中存在角点。
角点(corner points):
将图像窗口平移[u,v]产生灰度变化E(u,v)
w(x,y)是窗口函数,最简单情形就是窗口内的所有像素所对应的w权重系数均为1。但有时候,我们会将w(x,y)函数设定为以窗口中心为原点的二元正态分布。如果窗口中心点是角点时,移动前与移动后,该点的灰度变化应该最为剧烈,所以该点权重系数可以设定大些,表示窗口移动时,该点在灰度变化贡献较大;而离窗口中心(角点)较远的点,这些点的灰度变化几近平缓,这些点的权重系数,可以设定小点,以示该点对灰度变化贡献较小,那么我们自然想到使用二元高斯函数来表示窗口函数。
根据泰勒展开,E(u,v)表达式可以更新为:
其中M是 2*2 矩阵,可由图像的导数求得:
通过M的两个特征值的大小对图像点进行分类:
可以定义角点响应函数R:
SIFT,(Scale-invariant feature transform,SIFT),尺度不变特征转换。是用于图像处理领域的一种特征描述,具有旋转不变性、尺度不变性、亮度变化保持不变性,也就是说在图片发生旋转、伸缩、明暗变化时,图片的SIFT特征都保持稳定。
SIFT是一种局部特征,可在图像中检测出关键点,SIFT特征提取分为在图片上寻找关键点和提取关键点邻域信息两部分,在提取特征时只关注稳定的关键点及其附近的信息,使得特征更加具有描述性。
实质可以归为在不同尺度空间上查找特征点(关键点)的问题。
尺度空间理论是通过对一张原始图像进行尺度变换,获得多张图像,多尺度下的尺度空间表示序列,对这些序列进行尺度空间主轮廓的提取,并以该主轮廓作为一种特征向量,实现边缘、角点检测和不同分辨率上的特征提取等。
在对有噪声的图像求取边缘点时,可以先用平滑滤波器对图像平滑,然后再对平滑后的图像求两阶微分,并检测局部极值点.
高斯卷积核是实现尺度变换的唯一线性核, 所以SIFT算法中使用了高斯滤波器对图像进行平滑处理
对原始图像做多次的高斯平滑处理,也就得到了一个多尺度图像金字塔
高斯金字塔的构建过程可分为两步:
DoG在计算上只需相邻高斯平滑后图像相减,因此简化了计算。
可以通过高斯差分图像看出图像上的像素值变 化情况。(如果没有变化,也就没有特征。特征必须是变化尽可能多的点。)DOG图像描 绘的是目标的轮廓。
特征点是由DOG空间的局部极值点组成的。为了寻找DoG函数的极值点, 每一个像素点要和它所有的相邻点比较,看其是否比它的图像域和尺度域 的相邻点大或者小。
中间的检测点和它同尺度的8个相邻点和上下相邻尺度对应的9×2个 点共26个点比较,以确保在尺度空间和二维图像空间都检测到极值点。
由于DoG函数在图像边缘有较强的边缘响应,因此需要排除边缘响应。 DoG函数的峰值点在边缘方向有较大的主曲率,而在垂直边缘的方向有 较小的主曲率。主曲率可以通过计算在该点位置尺度的2×2的Hessian矩 阵得到,导数由采样点相邻差来估计:
D的主曲率和H的特征值成正比,令为α最大特征值,β为最小的特征值,则公式的值在两个特征值相等时最小,随着的增大而增大。值越大,说明两个特征值的比值越大,即在某一个方向的梯度值越大,而在另一个方向的梯度值越小,而边缘恰恰就是这种情况。所以为了剔除边缘响应点,需要让该比值小于一定的阈值,因此,为了检测主曲率是否在某域值r下,只需检测
通过尺度不变性求极值点,可以使其具有缩放不变的性质。而利用关 键点邻域像素的梯度方向分布特性,可以为每个关键点指定方向参数方向, 从而使描述子对图像旋转具有不变性。
确定关键点的方向采用梯度直方图统计法, 统计以关键点为原点,一定区域内的图像像 素点对关键点方向生成所作的贡献。
通过以上步骤,对于每一个关键点,拥有三个信息:位置、尺度以及方向。接下来就是为每个关键点建立一个描述符,用一组向量将这个关键点描述出来,使其不随各种变化而改变,比如光照变化、视角变化等等。这个描述子不但包括关键点,也包含关键点周围对其有贡献的像素点,并且描述符应该有较高的独特性,以便于提高特征点正确匹配的概率。
SIFT描述子是关键点邻域高斯图像梯度统计结果的一种表示。通过对关键点周围图像区域分块,计算块内梯度直方图,生成具有独特性的向量,这个向量是该区域图像信息的一种抽象,具有唯一性。
关键点的匹配可以采用穷举法来完成,但是这样耗费的时间太 多,一般都采用kd树的数据结构来完成搜索。搜索的内容是以 目标图像的关键点为基准,搜索与目标图像的特征点最邻近的 原图像特征点和次邻近的原图像特征点。
import cv2
import numpy as np
# 读入图像并转化为float类型,用于传递给harris函数
img = cv2.imread("school1.jpg")
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray_img = np.float32(gray_img)
# 对图像执行harris
blockSize = 2 # 邻域半径
apertureSize = 3 # 邻域大小
Harris_detector = cv2.cornerHarris(gray_img, blockSize, apertureSize, 0.04)
# 腐蚀harris结果
dst = cv2.dilate(Harris_detector, None)
# 设置阈值
thres = 0.01 * dst.max()
img[dst > thres] = [255, 0, 0]
cv2.imshow('show', img)
cv2.waitKey()
#这部分主要是提取图像中的SIFT特征点,并在原图中绘制出来。
import cv2
img_path = r'./img1.jpg'
img = cv2.imread(img_path)
# print(img.shape)
# img = cv2.resize(img,(136 * 3,512 * 3))
cv2.imshow("original",img)
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
#使用SIFT
sift = cv2.xfeatures2d.SIFT_create()
keypoints, descriptor = sift.detectAndCompute(gray,None)
cv2.drawKeypoints(image = img,
outImage = img,
keypoints = keypoints,
flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,
color = (51,163,236))
cv2.imshow("SIFT",img)
img = cv2.imread(img_path)
# img = cv2.resize(img,(136 * 3,76 * 3))
cv2.waitKey(0)
cv2.destroyAllWindows()
#这部分代码是提取图像中的SIFT特征点,并利用PCA(主成分分析)进行降维,并提取特征值。注:SIFT提取出来的特征是一个128维的矩阵,我在这里利用PCA将其降成100维。
import cv2
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
img_path = r'./photo/2-5-1250-1.bmp'
img = cv2.imread(img_path)
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
#使用SIFT
sift = cv2.xfeatures2d.SIFT_create()
keypoints, descriptor = sift.detectAndCompute(gray,None)
# print(descriptor.shape)
# m,n=descriptor.shape
# print(m,n)
descriptor = StandardScaler().fit_transform(descriptor)
pca = PCA(n_components = 100)
pca.fit(descriptor)
print(pca.singular_values_)#查看特征值
print(pca.components_)#打印查看特征值对应的特征向量
# print(pca.components_.shape)
cv2.drawKeypoints(image = img,
outImage = img,
keypoints = keypoints,
flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,
color = (255,0,255))
cv2.imshow("SIFT",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
SIFT特征匹配主要包括2个阶段:
SIFT特征的生成一般包括以下几个步骤: