图像特征(二)

图像的尺度空间

在正式开启今天的学习之前,先来了解一下尺度空间。在一定的范围内,无论大小,我们都可以将眼睛看到的事物分辨出来,然而计算机却很难拥有这样的能力。当图像的大小、位置等信息发生变化时,机器对图片内容的认知可能就会出现偏差。想要让计算机能够对物体在不同尺度下有一个统一的认识,就需要考虑图像在不同的尺度下都存在的特点,进而通过这些不变的特点识别图像内容。
尺度空间的获取通常使用高斯模糊来实现,所谓的高斯模糊,就是制作一个元素值服从某种二维正态分布的卷积核,比如:
在这里插入图片描述
然后再利用这个卷积核与原图像做卷积:
在这里插入图片描述
不难发现,G(x,y,σ)是一个标准二维正态分布的概率密度函数表达式,σ代表了标准差。当我们把标准差设置的较小时,意味着数据的分布比较集中,即卷积核的中心区域所占的权重越大,边缘区域所占的权重较小,因此卷积结果受边缘像素值影响小,卷积结果与原图对应位置像素的相似度越高,图像会保持较为清晰;反之,如果把σ选的过大,意味着中心区域所占的权重较小,受到周边点的影响较大,卷积结果与原图的相似度较低,.不同的σ对图像的平滑程度的影响如下图所示:
在这里插入图片描述

多分辨率金字塔

为了确保计算机识别图片特征,我们需要让计算机“记住”各种大小的图片特征,这个过程需要使用高斯金字塔。图像金字塔之前已经有详述,这里不再详述。我们只需要知道构建多分辨率金字塔过程就是不断地压缩图片,让图片尽量保留特征的条件下缩小其尺寸。因为我们针对一张图片要做五次σ不同的高斯模糊,所以图像金字塔的每一层都要有五个模糊程度不同的图片:
在这里插入图片描述

高斯差分金字塔(DOG)

这一部分,我们还是要构建图像金字塔,只不过这次构建金字塔的原料是上一个金字塔。多分辨率金字塔每一层都有五个大小相等但模糊程度不同的图片,高斯差分金字塔就是利用每层多分辨率金字塔的不同模糊图片作差,将结果重新储存:
在这里插入图片描述
因此,DOG的定义式即为:
在这里插入图片描述

DOG空间极值检测

为了寻找尺度空间的极值点,每个像素点要和其图像域(同一张图片上周边的各点)和相邻尺度域(临近的图片相同位置的各点)进行比较,比较范围如下:
在这里插入图片描述
可以看到,一个像素点应该与26个点进行比较,如果该点比这二十六个点都大,即为极大值,如果该点比这二十六个点都小,即为最小值。但是还有一个问题需要注意,我们构建的DOG如果每层只有四个图片,那么最高处和最低处的图片是没有办法进行极值检测的:
在这里插入图片描述
也就是说,如果我们有n张图做了空间极值检测,那么DOG每层有n+2张图。

关键点定位

接下来,我们来看另一个问题。因为我们的极值是从27个点中找到的一个,所以这些极值点也都是离散点,自然也就意味着如果放在连续函数上,这些点可能不是真正意义上的极值(真正的极值在压缩图片尺寸时被删掉了),然而精确定位极值点却是我们所必须做的一个工作。为了达到这个目的,我们通常需要对尺度空间DOG函数进行曲线拟合,最大程度恢复连续曲线的原貌并实现关键点的精确定位。我们以一维连续函数的采样为例:
在这里插入图片描述
因为我们拿到的是离散函数,那么如何将它恢复成连续函数呢?这就需要利用泰勒级数(演示中取到二阶)了:
在这里插入图片描述
离散函数的导数近似求法大家可以自取。假如我们想要把采样点1处恢复成连续函数,就可以先近似求出f’(1)和f’'(1),带入到泰勒级数之中即可求出一个近似的连续函数表达式,以此类推,我们将全部的点附近都恢复成连续函数,再拼接到一起,就是拟合结果啦。拟合曲线虽然一定会和真实的函数有所出入,但我们依然可以认为它就是真实函数,它的极值点就是真实函数的极值点。
将以上的内容推广到三维(因为DOG函数有三个自变量),我们获得的部分区域连续函数表达式即可写成:
在这里插入图片描述

消除边界响应

在我们得到极值点位置之后,还要对这些位置进行判断和过滤。由于是使用高斯滤波处理原图,边界响应可能会被加重。因此我们需要对其加以消除。消除方法和前篇讲到的角点检测基本是一致的,首先构建一个Hessian矩阵:
在这里插入图片描述
依然认为α是最大的特征值,β是最小特征值,那么我们设置以下关系:
在这里插入图片描述
当主曲率比值(γ)大于10时,特征点会被删除,边界响应即被消除。

特征方向

提到特征方向,就需要大家回忆一下之前讲过的图像梯度的概念。对于尺度空间中的矩阵而言,几乎每一个点都是具有梯度的,因此,我们可以用一下公式求出每一个点L(x,y)的梯度模m和方向θ:
在这里插入图片描述
那么我们的每一个特征点也都可以得到三个信息:即位置,尺度和方向((x,y),σ,θ)。

生成特征描述

在计算完关键点的梯度之后,我们还是要统计关键点邻域内的像素点梯度和方向。首先我们确定邻域的大小(这里选择8×8),然后照例只统计八个梯度方向(可以把梯度进行正交分解,也可以只取近似),过程如图所示:
在这里插入图片描述
统计完成后,我们把占主导地位(值最大)的方向。当然,有时候我们会遇到有多个方向与最大值差距很小的情况,这样的情况下我们可以把该关键点视为有多个方向的关键点,可以把它复制成多份,将方向值分别赋值给复制后的特征点。这样就可以产生多个坐标、尺度相同(近似)但方向不同的特征点。
为了保证特征矢量的旋转不变性,我们要以特征点为中心,将邻域范围内的像素点整个旋转θ°(主方向角度的大小),即将坐标轴转为特征点的主方向:
在这里插入图片描述
注:图像的原点是左上方第一个点,因此原x方向向右,原y方向向下
旋转之后,再利用高斯窗口对其进行加权运算,把这个8×8区域拆成四个4x4的小块,然后每个小块内绘制8个方向的梯度直方图,计算每个梯度方向的累加值,形成一个种子点,这样8×8的区域就可以分出4个种子点,每个种子点都有8个方向的向量信息。Lowe在论文中建议每个关键点使用16个种子描述,也就是特征点邻域范围选择16×16的大小,这样一个关键点就可以产生(16×8)维SIFT特征向量:
在这里插入图片描述

opencv SIFT函数

虽然理论学起来十分复杂,但是SIFT的代码实现并不困难,我们只需要直接使用定义好的类进行操作即可:

import cv2
import numpy as np

img = cv2.imread('test1.jpg')
img2 = img.copy()
gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 实例化sift算法
sift = cv2.xfeatures2d.SIFT_create()
# 传入灰度图,得到关键点的信息。kp是封装好的类型,没办法直接显示。
kp = sift.detect(gray, None)

# 由于kp不能查看,我们就不能自己去画关键点了。
# opencv提供了一个drawKeypoints函数为我们绘制关键点
# drawKeypoints(gray, kp, img2)会把特征点绘制在灰度图上,然后覆盖img2原来的内容
# 不写“img2=”是不会影响输出结果的
img2=cv2.drawKeypoints(gray, kp, img2)

cv2.imshow('drawKeypoints', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

看看关键点标记的情况:
在这里插入图片描述
当然,仅仅标记了关键点还是不够的,我们的关注点并不在关键点在哪,我们经常会需要对关键点做一些额外的处理操作,也就是我们需要把关键点特征计算出来:

import cv2
img = cv2.imread('test1.jpg')
img2 = img.copy()
img2=cv2.drawKeypoints(gray, kp, img2)
# 获得关键点信息以及每个关键点对应的128维SIFT向量
kp, des = sift.compute(gray, kp)
print(des[0],len(des[0]),sep='\n')

这样就可以查看特征向量了:
在这里插入图片描述
今天的内容就讲述到这里了,虽然理论推道比较多,但是代码的使用却是比较简单的,看不懂的小伙伴可以先学会使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值