SIFT简述 |
您所在的位置:网站首页 › 金字塔金字塔 › SIFT简述 |
第一步,计算高斯差分金字塔
1.1 高斯卷积核
首先需要了解高斯卷积核的概念。一个高斯卷积核如下图所示,他是一个中间大,四周小的矩阵。把这个卷积核拿去对原图进行卷积,得到的图像就是高斯模糊后的结果。 高斯卷积核每个位置的数值参考以下公式来计算,可见,该函数的输入有:σ、x、y,其中xy与卷积核的尺寸大小有关,因此只要确定了σ,整个高斯卷积核就确定了。 其中,坐标x,y并不是矩阵中常用的以左上角为(0,0),它其实是以中间为(0,0)原点的。就像这样: 根据上述公式,计算可得一个3*3,σ为2的高斯卷积核如下: 但这不对,把这9个数据加起来,是比1小的,换言之,最终得到的卷积结果会小,整个照片会向(0,0,0)变化,就变黑了。因此还需要进行高斯卷积核的归一化。先计算9个数的和为0.30419247439225205,每个数都除去这个 可以看出,σ变大后,卷积核中的数值趋于平均,此时对原图的模糊效果就会变大。因此 参数 σ越大,高斯模糊的程度越大。 1.2 高斯模糊效果从左到右慢慢变模糊,此处留一个小坑,待之后回来补。 按理说,高斯卷积核参数σ决定了模糊程度,但我在实验的时候发现,使用3*3或者其他固定尺寸的卷积核时,改变σ并没有改变模糊程度,反而是改变尺寸的时候,对模糊程度影响更大。而我们知道,当卷积核相对于原图来说过小的时候,卷积效果不明显(比如3 *3的卷积核,对4k图像进行卷积) 这就衍生一个问题,原图尺寸与卷积核尺寸如何对应?该选取多大的卷积核尺寸来对图片进行卷积? 2022.3.20更新回答: 在高斯金字塔时,需要逐渐加大σ来获取不同程度的高斯模糊效果,但此时不能单纯的加大σ,还需要同时增加卷积核尺寸,卷积核尺寸dim计算方法如下: dim=int(6*sigma+1) if dim % 2 == 0: #确保卷积核尺寸是奇数 dim += 1这个公式不一定正确,不过我看到的时这样的。 1.3 差分差分(Dog)很好理解,将高斯模糊前的图片与模糊后的图片直接相减,得到的结果就是差分。 可以预见,高斯模糊是把原图进行平滑操作,那两者相减的结果就是原图中不平滑的部分,是比较突出的部分,也就是特征处。 我们有N张高斯模糊照片的时候,只能得到N-1个差分图像,这很好理解吧? 代码实现非常简单,读取文件进来,然后直接相减就行。 img1 = cv2.imread("img1.jpg") img2 = cv2.imread("img2.jpg") img3 = cv2.imread("img3.jpg") img4 = cv2.imread("img4.jpg") cv2.imwrite("img1-2.jpg",img1-img2) cv2.imwrite("img2-3.jpg",img2-img3) cv2.imwrite("img3-4.jpg",img3-img4) 1.4 高斯金字塔高斯金字塔的应用非常常见,但我们却不知道这是高斯金字塔。 比如图像缩放,一个100 * 100的图像怎么缩小成 25 * 25? 每相邻的2*2区域,取其中一个点来代表这个区域,遍历整个图像,就缩小了4倍。这个过程叫降采样 但如果直接对原图进行降采样,往往会导致图像出现噪点、锐化,因此可以选择先进行一次高斯模糊,让相邻的2 * 2区域之中变平滑,然后再取其中一个点,或者取平均值作为降采样的结果。 1.5 高斯差分金字塔 1.5.1 计算步骤1、对原图进行不同σ的高斯模糊,得到一组图片,称为一个Octave。每个Octave内的图片尺寸相同,高斯参数σ不同; 2、对第一个Octave内的图片进行差分操作,得到一组差分数据; 3、再对第一个Octave中最上面的图片进行高斯降采样,得到尺寸稍小的图片,同样对该图片进行不同σ的高斯模糊,得到一组尺寸稍小的图片。这一组图片与上一组相比,尺寸不同。 4、再对第二个Octave内的图片进行差分操作,得到一组差分数据; 5、重复操作,建立起高斯差分金字塔。 1.5.2 参数设定O、S设定: 假设,共有 n 张图片需要提取特征,原图大小是 M * N,每个Octave中有 S 层不同 σ 的图片,整个金字塔共有 O 组, 原则上,S、O 都是可以自己随便设定的,但是SIFT论文中给出的参考值如下: σ设定: 对于σ0,即第一组第一层,最先开始的高斯卷积核参数为σ0,它的取值是一个固定的常数: σ0 = sqrt(1.6 * 1.6 - 0.5 * 0.5)对于系数k,有: 第一组第二层:σ = k * σ0, 第一组第三层,σ = k * k * σ0, 第一组第四层,σ = k * k * k * σ0, …… 以此类推,得到整个第一组,每组总共有n+3层,取第n+1层(就是倒数第三层)的参数 k ^ n 作为下一组第一层的σ,并不断重复这个过程。 1.5.2 代码实现废话不多说,直接上代码,注意,我的电脑是8核16线程,32G的内存,所以干脆开了一堆线程加速计算。 import cv2 import numpy as np from multiprocessing import Pool def GuassianKernel(sigma,dim): ''' 高斯卷积核 :param sigma: 高斯模糊参数 :param dimension: 卷积核大小,例如3*3的卷积核,dim为3 :return: ''' temp_sigma = 2*sigma*sigma #先求2σ²,减少运算 ass_item = [t-(dim//2) for t in range(dim)] ass=[] for i in range(dim): ass.append(ass_item) ass = np.array(ass) result = (1.0/(temp_sigma*np.pi))*np.exp(-(ass**2+(ass.T)**2)/temp_sigma)#高斯计算公式 result = result/np.sum(result) #归一化 return result def convolve(filter,mat,padding,strides): """ 卷积函数 :param filter: 卷积核 :param mat: 图片 :param padding: 边缘留多大空间 :param strides: 边缘填充方案 :return: """ result = None filter_size = filter.shape mat_size = mat.shape if len(filter_size) == 2: if len(mat_size) == 3: channel = [] for i in range(mat_size[-1]): pad_mat = np.pad(mat[:,:,i], ((padding[0], padding[1]), (padding[2], padding[3])), 'constant') temp = [] for j in range(0,mat_size[0],strides[1]): temp.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() temp[-1].append(val) channel.append(np.array(temp)) channel = tuple(channel) result = np.dstack(channel) elif len(mat_size) == 2: 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) result = np.array(channel) return result def getGuassianPyramidandDog(img,n): #计算高斯差分金字塔 ''' :param img: 图片 :param n: 有多少张图片需要提取特征 :return: 高斯差分金字塔,高斯金字塔 ''' sigma0 = np.sqrt(1.6*1.6-0.5*0.5) S = n + 3 O = int(np.log2(min(img.shape[0],img.shape[1])))-3 k = 2 ** (1.0 / n) print("共有:",(O,S),"个卷积任务") sigma_list = [[(k**s)*sigma0*(1 |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |