特征点检测之SIFT

目录

一、sift简介

二、计算方法

1. 尺度空间极值点

1.1 高斯核

1.2 高斯金子塔

1.3 DOG(diff of  gaussian) 高斯差分金字塔

1.4 极值点检测

2. 关键点确定

2.1  离散差分法

2.2  消除边界效应

2.3  有限差分法求导

3. 关键点方向分配

3.1 方向和梯度计算

3.2 直方图统计最大幅值

4. 特征点的描述

4.1 确定描述子采样区域

4.2 生成描述子

4.3 生成特征匹配点

三、问题

总结



一、sift简介

图像匹配将同一目标在不同时间、不同分辨率、不同光照、不同位姿情况下所成的像相对应。David G.Lowe 教授提出了一种**基于尺度空间的**、对**图像缩放**、**旋转**甚至**仿射变换**保持不变性的图像局部特征描述算子—— **SIFT(尺度不变特征变换)Scale invariant feature transform

SIFT算法在一定程度上可解决:

A: 目标的旋转、缩放、平移(RST)

B: 图像仿射/投影变换(视点viewpoint)

C: 光照影响(illumination)

D: 目标遮挡(occlusion)杂物场景(clutter)

二、计算方法

1. 尺度空间极值点

1.1 高斯核

高斯核是唯一可以产生多尺度空间的核,在低通滤波中高斯平滑滤波无论是时域还是频域都十分有效卷积的结果使原始像素值有最大的权重,距离中心越远的相邻像素值权重也越小。

高斯函数的可分离性是指使用二维矩阵变换得到的效果也可以通过在水平方向进行一维高斯矩阵变换加上竖直方向的一维高斯矩阵变换得到。

1.2 高斯金子塔

将照片降采样,得到了不同分辨率下的图像金字塔。再对每层图像进行高斯卷积这样一来,原本的图像金字塔每层只有一张图像,而卷积后,每层又增加了多张不同模糊程度下的照片。

高斯核模拟的图像不同的尺度空间,类型cnn的感受野。物体由远及近,前者比较清晰,后者比较模糊,前者比较大,后者比较小,通过前者能看到图像的一些细节信息,通过后者能看到图像的一些轮廓的信息,这就是图像的尺度。

def GuassianKernel(sigma , dim):
    '''
    :param sigma: Standard deviation
    :param dim: dimension(must be positive and also an odd number)
    :return: return the required Gaussian kernel.
    '''
    temp = [t - (dim//2) for t in range(dim)]
    assistant = []
    for i in range(dim):
        assistant.append(temp)
    assistant = np.array(assistant)
    temp = 2*sigma*sigma
    result = (1.0/(temp*np.pi))*np.exp(-(assistant**2+(assistant.T)**2)/temp)
    return result

channel = []
pad_mat = np.pad(mat, ((padding[0], padding[1]), (padding[2], padding[3])), 'constant')
for j in range(0, mat_size[0], strides[1]):
    channel.append([])
    for k in range(0, mat_size[1], strides[0]):
        val = (filter * pad_mat[j:j + filter_size[0],k:k + filter_size[1]]).sum()
        channel[-1].append(val)

1.3 DOG(diff of  gaussian) 高斯差分金字塔

对同一个组内的两幅相邻的图像做差得到插值图像,所有组内的这些插值图像的集合,就构成了差分高斯金字塔。

DoG = [[GuassianPyramid[o][s+1] - GuassianPyramid[o][s] for s in range(S - 1)] for o in range(O)]

1.4 极值点检测

极值点由Dog空间极值点组成,即每个像素和相邻的点进行比较,每个像素点和相邻点进行比较。检测到的点是离散空间的极值点,需确定关键点的位置和尺度,同时去除低对比度和不确定的边缘相应点。

val = img[i,j]
eight_neiborhood_prev = img_prev[max(0, i - 1):min(i + 2, img_prev.shape[0]), max(0, j - 1):min(j + 2, img_prev.shape[1])]
eight_neiborhood = img[max(0, i - 1):min(i + 2, img.shape[0]), max(0, j - 1):min(j + 2, img.shape[1])]
eight_neiborhood_next = img_next[max(0, i - 1):min(i + 2, img_next.shape[0]), max(0, j - 1):min(j + 2, img_next.shape[1])]
if np.abs(val) > threshold and \
    ((val > 0 and (val >= eight_neiborhood_prev).all() and (val >= eight_neiborhood).all() and (val >= eight_neiborhood_next).all())
    or (val < 0 and (val <= eight_neiborhood_prev).all() and (val <= eight_neiborhood).all() and (val <= eight_neiborhood_next).all())):

2. 关键点确定

2.1  离散差分法

离散空间的极值点不一定是真正的极值点,利用已知的离散点差值得到连续的空间点的方法是子像素的差值。

2.2  消除边界效应

DOG算子产生较强的边缘效应,需要剔除不稳定的边缘相应点。可以构建特征点处的hessian矩阵,即x方向和y方向对的梯度,检测矩阵tr对角线的和(矩阵迹trace)和det(行列式determine)。

H的特征值α和β代表x和y方向的梯度,在两个特征值相等时最小,随着的增大而增大。值越大,说明两个特征值的比值越大,即在某一个方向的梯度值越大,而在另一个方向的梯度值越小,而边缘恰恰就是这种情况。所以为了剔除边缘响应点,需要让该比值小于一定的阈值 。

# 利用Hessian矩阵的迹和行列式计算主曲率的比值
tr = dxx + dyy
det = dxx * dyy - dxy * dxy
if det <= 0 or tr * tr * edgeThreshold >= (edgeThreshold + 1) * (edgeThreshold + 1) * det:
    return None,x,y,s

point.append((x + xr) * (1 << o))
point.append((y + xc) * (1 << o))

2.3  有限差分法求导

有限差分法以变量离散取值后对应的函数值来近似微分方程中独立变量的连续取值。利用多元泰勒展开式,可得任意偏导的近似差分表示。

3. 关键点方向分配

3.1 方向和梯度计算

为了使描述符具有旋转不变性,需要利用图像的局部特征为给每一个关键点分配一个基准方向。使用图像梯度的方法。对于在DOG金字塔中检测出的关键点,采集其所在高斯金字塔图像3σ邻域窗口内像素的梯度和方向分布特征。

3.2 直方图统计最大幅值

利用直方图统计领域内像素对应的梯度和幅值:梯度方向角为横轴刻度,取45度为一个单位,那么横轴就有8个刻度;纵轴是对应梯度的幅值累加值。方向直方图的峰值则代表了该特征点处邻域梯度的方向,以直方图中最大值作为该关键点的主方向。为了增强匹配的鲁棒性,只保留峰值大于主方向峰值80%的方向作为该关键点的辅方向。

def GetMainDirection(img,r,c,radius,sigma,BinNum):
    expf_scale = -1.0 / (2.0 * sigma * sigma)

    X = []
    Y = []
    W = []
    temphist = []

    for i in range(BinNum):
        temphist.append(0.0)

    # 图像梯度直方图统计的像素范围
    k = 0
    for i in range(-radius,radius+1):
        y = r + i
        if y <= 0 or y >= img.shape[0] - 1:
            continue
        for j in range(-radius,radius+1):
            x = c + j
            if x <= 0 or x >= img.shape[1] - 1:
                continue

            dx = (img[y, x + 1] - img[y, x - 1])
            dy = (img[y - 1, x] - img[y + 1, x])

            X.append(dx)
            Y.append(dy)
            W.append((i * i + j * j) * expf_scale)
            k += 1


    length = k

    W = np.exp(np.array(W))
    Y = np.array(Y)
    X = np.array(X)
    Ori = np.arctan2(Y,X)*180/np.pi
    Mag = (X**2+Y**2)**0.5

    # 计算直方图的每个bin
    for k in range(length):
        bin = int(np.round((BinNum / 360.0) * Ori[k]))
        if bin >= BinNum:
            bin -= BinNum
        if bin < 0:
            bin += BinNum
        temphist[bin] += W[k] * Mag[k]

4. 特征点的描述

4.1 确定描述子采样区域

特征描述子与特征点所在的尺度有关,因此对梯度的求取应在特征点对应的高斯图像上进行。如下是旋转后直径的变化。

4.2 生成描述子

将原图像x轴转到与主方向相同的方向,在特征点附近邻域图像梯度的位置和方向旋转后,再以特征点为中心,在旋转后的图像中更新梯度方向。中图和右图为什么每个像素点的方向不一样?其实要明确一点,你所选的小区域,是关键点旋转后的小区域,右图的区域跟旋转前的区域不一样了,右图是重新选取得区域,但是区域大小没变。

4.3 生成特征匹配点

在每子区域内计算8个方向的梯度方向直方图,绘制每个梯度方向的累加值,形成一个种子点。与求特征点主方向时有所不同,此时,每个子区域的梯度方向直方图将0°~360°划分为8个方向范围,每个范围为45°,这样,每个种子点共有8个方向的梯度强度信息。由于存在4X4(Bp X Bp)个子区域,所以,共有4X4X8=128个数据,最终形成128维的SIFT特征矢量
 

三、问题

A:  实时性

B:  有效特征点少

C:  对边缘光滑的目标无法准确提取特征点


总结

Opencv提供FeatureDetector实现特征点检测。

哈哈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值