SIFT算法之python实现

article/2025/10/26 12:38:50

0. 算法原理细节可参考:

  1. https://blog.csdn.net/abcjennifer/article/details/7639681
  2. https://blog.csdn.net/zddblog/article/details/7521424?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1
  3. https://www.bilibili.com/video/BV1Qb411W7cK?p=1
    本文参考了up主的代码,并在匹配阶段、金字塔输出方式等部分进行了重新设计,同时使代码实现完全对像素操作。

1. 算法流程

SIFT(Scale-invariant feature transform),即尺度不变特征变换,是一种检测图像局部特征并进行特征点匹配的算法。

算法流程如下:
在这里插入图片描述

2. python实现

OPENCV库中有SIFT函数,调用此函数很容易实现。下面的是直接对像素操作实现SIFT的源代码。
# coding: utf-8
import warningswarnings.filterwarnings("ignore")  # 忽略警告
import numpy as np
import matplotlib.pyplot as plt
from PIL import Imagedef convolve(kernel, img, padding, strides):''':param kernel:  输入的核函数:param img:    输入的图片:param padding:  需要填充的位置:param strides:   高斯核移动的步长:return:   返回卷积的结果'''result = Nonekernel_size = kernel.shapeimg_size = img.shapeif len(img_size) == 3:  # 三通道图片就对每通道分别卷积  dstack和并channel = []for i in range(img_size[-1]):pad_img = np.pad(img[:, :, i], ((padding[0], padding[1]), (padding[2], padding[3])), 'constant')temp = []for j in range(0, img_size[0], strides[1]):temp.append([])for k in range(0, img_size[1], strides[0]):val = (kernel * pad_img[j * strides[1]:j * strides[1] + kernel_size[0],k * strides[0]:k * strides[0] + kernel_size[1]]).sum()temp[-1].append(val)channel.append(np.array(temp))channel = tuple(channel)result = np.dstack(channel)elif len(img_size) == 2:channel = []pad_img = np.pad(img, ((padding[0], padding[1]), (padding[2], padding[3])),'constant')  # pad是填充函数 边界处卷积需要对边界外根据高斯核大小填0for j in range(0, img_size[0], strides[1]):  # 第j列 strides 是步长 本例步长为1 相当于遍历channel.append([])for k in range(0, img_size[1], strides[0]):  # 第i行val = (kernel * pad_img[j * strides[1]:j * strides[1] + kernel_size[0],k * strides[0]:k * strides[0] + kernel_size[1]]).sum()  # 卷积的定义 相当于用高斯核做加权和channel[-1].append(val)result = np.array(channel)return result# 函数1.1.1 undersampling
# 降采样,隔点取点
def undersampling(img, step=2):'''临近降采样:param img: 输入图片:param step: 降采样步长 默认为2(缩小两倍):return: 返回降采样结果'''return img[::step, ::step]# 函数1.1.2 GuassianKernel
# 产生高斯核
def GuassianKernel(sigma, dim):''':param sigma: 标准差:param dim: 高斯核的纬度(必须是个奇数):return: 返回高斯核'''temp = [t - (dim // 2) for t in range(dim)]  # 生成二维高斯的x与yassistant = []for i in range(dim):assistant.append(temp)assistant = np.array(assistant)temp = 2 * sigma * sigmaresult = (1.0 / (temp * np.pi)) * np.exp(-(assistant ** 2 + (assistant.T) ** 2) / temp)  # 二维高斯公式return result# 函数1.1,getDoG
# 得到高斯金字塔和高斯差分金字塔
def getDoG(img, n, sigma0, S=None, O=None):''':param img: 输入的图像:param sigma0: 输入的sigma:param n: 有几层用于提取特征:param S: 金字塔每层有几张gauss滤波后的图像:param O: 金字塔有几层:return: 返回差分高斯金字塔和高斯金字塔'''if S == None:S = n + 3  # 至少有4张 (第一张和最后一张高斯金字塔无法提取特征,差分以后的第一张和最后一张也无法提取特征)if O == None:O = int(np.log2(min(img.shape[0], img.shape[1]))) - 3  # 计算最大可以计算多少层 O=log2(min(img长,img宽))-3k = 2 ** (1.0 / n)sigma = [[(k ** s) * sigma0 * (1 << o) for s in range(S)] for o in range(O)]  # 每一层 sigma按照 k^1/s * sigama0  排列 下一层的sigma都要比上一层sigma大两倍sample = [undersampling(img, 1 << o) for o in range(O)]  # 降采样取图片作为该层的输入Guass_Pyramid = []for i in range(O):Guass_Pyramid.append([])  # 申明二维空数组for j in range(S):dim = int(6*sigma[i][j] + 1) # 上网查找相关信息 高斯核大小随sigma变化的效果更好#dim = int(9)if dim % 2 == 0:  # 防止输入的高斯核不是奇数dim += 1Guass_Pyramid[-1].append(convolve(GuassianKernel(sigma[i][j], dim), sample[i], [dim // 2, dim // 2, dim // 2, dim // 2], [1, 1]))  # 在第i层添加第j张 经过高斯卷积的 该图片四周扩展 5//2=2 用于高斯卷积DoG_Pyramid = [[Guass_Pyramid[o][s + 1] - Guass_Pyramid[o][s] for s in range(S - 1)] for o in range(O)]  #每一层中 上一张减去下一张得到高斯核return DoG_Pyramid, Guass_Pyramid, O  # 返回高斯金字塔和高斯差分金字塔# 函数2.1.1 adjustLocalExtrema
# 功能:通过泰勒展开精调位置精调位置
def adjustLocalExtrema(DoG, o, s, x, y, contrastThreshold, edgeThreshold, sigma, n, SIFT_FIXPT_SCALE):SIFT_MAX_INTERP_STEPS = 5SIFT_IMG_BORDER = 5point = []img_scale = 1.0 / (255 * SIFT_FIXPT_SCALE)deriv_scale = img_scale * 0.5second_deriv_scale = img_scalecross_deriv_scale = img_scale * 0.25img = DoG[o][s]i = 0while i < SIFT_MAX_INTERP_STEPS:if s < 1 or s > n or y < SIFT_IMG_BORDER or y >= img.shape[1] - SIFT_IMG_BORDER or x < SIFT_IMG_BORDER or x >= \img.shape[0] - SIFT_IMG_BORDER:return None, None, None, Noneimg = DoG[o][s]prev = DoG[o][s - 1]next = DoG[o][s + 1]dD = [(img[x, y + 1] - img[x, y - 1]) * deriv_scale,(img[x + 1, y] - img[x - 1, y]) * deriv_scale,(next[x, y] - prev[x, y]) * deriv_scale]v2 = img[x, y] * 2dxx = (img[x, y + 1] + img[x, y - 1] - v2) * second_deriv_scaledyy = (img[x + 1, y] + img[x - 1, y] - v2) * second_deriv_scaledss = (next[x, y] + prev[x, y] - v2) * second_deriv_scaledxy = (img[x + 1, y + 1] - img[x + 1, y - 1] - img[x - 1, y + 1] + img[x - 1, y - 1]) * cross_deriv_scaledxs = (next[x, y + 1] - next[x, y - 1] - prev[x, y + 1] + prev[x, y - 1]) * cross_deriv_scaledys = (next[x + 1, y] - next[x - 1, y] - prev[x + 1, y] + prev[x - 1, y]) * cross_deriv_scaleH = [[dxx, dxy, dxs],[dxy, dyy, dys],[dxs, dys, dss]]X = np.matmul(np.linalg.pinv(np.array(H)), np.array(dD))xi = -X[2]xr = -X[1]xc = -X[0]if np.abs(xi) < 0.5 and np.abs(xr) < 0.5 and np.abs(xc) < 0.5:breaky += int(np.round(xc))x += int(np.round(xr))s += int(np.round(xi))i += 1if i >= SIFT_MAX_INTERP_STEPS:return None, x, y, sif s < 1 or s > n or y < SIFT_IMG_BORDER or y >= img.shape[1] - SIFT_IMG_BORDER or x < SIFT_IMG_BORDER or x >= \img.shape[0] - SIFT_IMG_BORDER:return None, None, None, Nonet = (np.array(dD)).dot(np.array([xc, xr, xi]))contr = img[x, y] * img_scale + t * 0.5# 确定极值点位置第四步:舍去低对比度的点if np.abs(contr) * n < contrastThreshold:return None, x, y, s# 确定极值点位置第五步:边缘效应的去除。 利用Hessian矩阵的迹和行列式计算主曲率的比值tr = dxx + dyydet = dxx * dyy - dxy * dxyif det <= 0 or tr * tr * edgeThreshold >= (edgeThreshold + 1) * (edgeThreshold + 1) * det:return None, x, y, spoint.append((x + xr) * (1 << o))point.append((y + xc) * (1 << o))point.append(o + (s << 8) + (int(np.round((xi + 0.5)) * 255) << 16))point.append(sigma * np.power(2.0, (s + xi) / n) * (1 << o) * 2)return point, x, y, sdef 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 = 0for i in range(-radius, radius + 1):y = r + iif y <= 0 or y >= img.shape[0] - 1:continuefor j in range(-radius, radius + 1):x = c + jif x <= 0 or x >= img.shape[1] - 1:continuedx = (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 += 1length = kW = np.exp(np.array(W))Y = np.array(Y)X = np.array(X)Ori = np.arctan2(Y, X) * 180 / np.piMag = (X ** 2 + Y ** 2) ** 0.5# 计算直方图的每个binfor k in range(length):bin = int(np.round((BinNum / 360.0) * Ori[k]))if bin >= BinNum:bin -= BinNumif bin < 0:bin += BinNumtemphist[bin] += W[k] * Mag[k]# smooth the histogram# 高斯平滑temp = [temphist[BinNum - 1], temphist[BinNum - 2], temphist[0], temphist[1]]temphist.insert(0, temp[0])temphist.insert(0, temp[1])temphist.insert(len(temphist), temp[2])temphist.insert(len(temphist), temp[3])  # paddinghist = []for i in range(BinNum):hist.append((temphist[i] + temphist[i + 4]) * (1.0 / 16.0) + (temphist[i + 1] + temphist[i + 3]) * (4.0 / 16.0) +temphist[i + 2] * (6.0 / 16.0))# 得到主方向maxval = max(hist)return maxval, hist# 函数2.1 LocateKeyPoint
# 功能:关键点定位,共分为5步
def LocateKeyPoint(DoG, sigma, GuassianPyramid, n, BinNum=36, contrastThreshold=0.04, edgeThreshold=10.0):SIFT_ORI_SIG_FCTR = 1.52SIFT_ORI_RADIUS = 3 * SIFT_ORI_SIG_FCTRSIFT_ORI_PEAK_RATIO = 0.8SIFT_INT_DESCR_FCTR = 512.0# SIFT_FIXPT_SCALE = 48SIFT_FIXPT_SCALE = 1KeyPoints = []O = len(DoG)S = len(DoG[0])for o in range(O):for s in range(1, S - 1):# 第一步:设定阈值threshold = 0.5 * contrastThreshold / (n * 255 * SIFT_FIXPT_SCALE)# 用于阈值化,去噪img_prev = DoG[o][s - 1]img = DoG[o][s]img_next = DoG[o][s + 1]for i in range(img.shape[0]):for j in range(img.shape[1]):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())): # 如果某点大于阈值,并且 比周围8个点、上下2*9个点共26个点都大或都小,则认为是关键点# 第三步:精调位置,通过函数2.1.1 adjustLocalExtrema:实现point, x, y, layer = adjustLocalExtrema(DoG, o, s, i, j, contrastThreshold, edgeThreshold,sigma, n, SIFT_FIXPT_SCALE)if point == None:continuescl_octv = point[-1] * 0.5 / (1 << o)# GetMainDirection:(确定极值点的位置以后就)求主方向omax, hist = GetMainDirection(GuassianPyramid[o][layer], x, y,int(np.round(SIFT_ORI_RADIUS * scl_octv)),SIFT_ORI_SIG_FCTR * scl_octv, BinNum)mag_thr = omax * SIFT_ORI_PEAK_RATIOfor k in range(BinNum):if k > 0:l = k - 1else:l = BinNum - 1if k < BinNum - 1:r2 = k + 1else:r2 = 0if hist[k] > hist[l] and hist[k] > hist[r2] and hist[k] >= mag_thr:bin = k + 0.5 * (hist[l] - hist[r2]) / (hist[l] - 2 * hist[k] + hist[r2])if bin < 0:bin = BinNum + binelse:if bin >= BinNum:bin = bin - BinNumtemp = point[:]temp.append((360.0 / BinNum) * bin)KeyPoints.append(temp)return KeyPoints# calcSIFTDescriptor:更小的计算描述符函数
def calcSIFTDescriptor(img, ptf, ori, scl, d, n, SIFT_DESCR_SCL_FCTR=3.0, SIFT_DESCR_MAG_THR=0.2,SIFT_INT_DESCR_FCTR=512.0, FLT_EPSILON=1.19209290E-07):dst = []pt = [int(np.round(ptf[0])), int(np.round(ptf[1]))]  # 坐标点取整# 旋转到主方向cos_t = np.cos(ori * (np.pi / 180))  # 余弦值sin_t = np.sin(ori * (np.pi / 180))  # 正弦值bins_per_rad = n / 360.0exp_scale = -1.0 / (d * d * 0.5)hist_width = SIFT_DESCR_SCL_FCTR * scl# radius: 统计区域边长的一半radius = int(np.round(hist_width * 1.4142135623730951 * (d + 1) * 0.5))cos_t /= hist_widthsin_t /= hist_widthrows = img.shape[0]cols = img.shape[1]hist = [0.0] * ((d + 2) * (d + 2) * (n + 2))X = []Y = []RBin = []CBin = []W = []k = 0for i in range(-radius, radius + 1):for j in range(-radius, radius + 1):c_rot = j * cos_t - i * sin_tr_rot = j * sin_t + i * cos_trbin = r_rot + d // 2 - 0.5cbin = c_rot + d // 2 - 0.5r = pt[1] + ic = pt[0] + jif rbin > -1 and rbin < d and cbin > -1 and cbin < d and r > 0 and r < rows - 1 and c > 0 and c < cols - 1:dx = (img[r, c + 1] - img[r, c - 1])dy = (img[r - 1, c] - img[r + 1, c])X.append(dx)Y.append(dy)RBin.append(rbin)CBin.append(cbin)W.append((c_rot * c_rot + r_rot * r_rot) * exp_scale)k += 1length = kY = np.array(Y)X = np.array(X)Ori = np.arctan2(Y, X) * 180 / np.piMag = (X ** 2 + Y ** 2) ** 0.5W = np.exp(np.array(W))for k in range(length):rbin = RBin[k]cbin = CBin[k]obin = (Ori[k] - ori) * bins_per_radmag = Mag[k] * W[k]r0 = int(rbin)c0 = int(cbin)o0 = int(obin)rbin -= r0cbin -= c0obin -= o0if o0 < 0:o0 += nif o0 >= n:o0 -= n# histogram update using tri-linear interpolationv_r1 = mag * rbinv_r0 = mag - v_r1v_rc11 = v_r1 * cbinv_rc10 = v_r1 - v_rc11v_rc01 = v_r0 * cbinv_rc00 = v_r0 - v_rc01v_rco111 = v_rc11 * obinv_rco110 = v_rc11 - v_rco111v_rco101 = v_rc10 * obinv_rco100 = v_rc10 - v_rco101v_rco011 = v_rc01 * obinv_rco010 = v_rc01 - v_rco011v_rco001 = v_rc00 * obinv_rco000 = v_rc00 - v_rco001idx = ((r0 + 1) * (d + 2) + c0 + 1) * (n + 2) + o0hist[idx] += v_rco000hist[idx + 1] += v_rco001hist[idx + (n + 2)] += v_rco010hist[idx + (n + 3)] += v_rco011hist[idx + (d + 2) * (n + 2)] += v_rco100hist[idx + (d + 2) * (n + 2) + 1] += v_rco101hist[idx + (d + 3) * (n + 2)] += v_rco110hist[idx + (d + 3) * (n + 2) + 1] += v_rco111# finalize histogram, since the orientation histograms are circularfor i in range(d):for j in range(d):idx = ((i + 1) * (d + 2) + (j + 1)) * (n + 2)hist[idx] += hist[idx + n]hist[idx + 1] += hist[idx + n + 1]for k in range(n):dst.append(hist[idx + k])# copy histogram to the descriptor,# apply hysteresis thresholding# and scale the result, so that it can be easily converted# to byte arraynrm2 = 0length = d * d * nfor k in range(length):nrm2 += dst[k] * dst[k]thr = np.sqrt(nrm2) * SIFT_DESCR_MAG_THRnrm2 = 0for i in range(length):val = min(dst[i], thr)dst[i] = valnrm2 += val * valnrm2 = SIFT_INT_DESCR_FCTR / max(np.sqrt(nrm2), FLT_EPSILON) # 归一化for k in range(length):dst[k] = min(max(dst[k] * nrm2, 0), 255)return dst# calcDescriptors:计算描述符
def calcDescriptors(gpyr, keypoints, SIFT_DESCR_WIDTH=4, SIFT_DESCR_HIST_BINS=8):# SIFT_DESCR_WIDTH = 4,描述直方图的宽度# SIFT_DESCR_HIST_BINS = 8d = SIFT_DESCR_WIDTHn = SIFT_DESCR_HIST_BINSdescriptors = []# keypoints(x,y,低8位组数次8位层数,尺度,主方向)for i in range(len(keypoints)):kpt = keypoints[i]o = kpt[2] & 255  # 组序号s = (kpt[2] >> 8) & 255  # 该特征点所在的层序号scale = 1.0 / (1 << o)  # 缩放倍数size = kpt[3] * scale  # 该特征点所在组的图像尺寸ptf = [kpt[1] * scale, kpt[0] * scale]  # 该特征点在金字塔组中的坐标img = gpyr[o][s]  # 该点所在的金字塔图像descriptors.append(calcSIFTDescriptor(img, ptf, kpt[-1], size * 0.5, d, n))  # calcSIFTDescriptor:更小的计算描述符函数return descriptorsdef SIFT(img, showDoGimgs=False):# 1. 建立高斯差分金字塔,SIFT_SIGMA = 1.6SIFT_INIT_SIGMA = 0.5  # 假设的摄像头的尺度sigma0 = np.sqrt(SIFT_SIGMA ** 2 - SIFT_INIT_SIGMA ** 2) #初始sigma0n = 2######DoG, GuassianPyramid,octaves = getDoG(img, n, sigma0)  # 函数1.1,getDoG:得到高斯金字塔和高斯差分金字塔if showDoGimgs:plt.figure(1)for i in range(octaves):for j in range(n + 3):array = np.array(GuassianPyramid[i][j], dtype=np.float32)plt.subplot(octaves, n + 3, j + (i) * octaves + 1)plt.imshow(array.astype(np.uint8), cmap='gray')plt.axis('off')plt.show()plt.figure(2)for i in range(octaves):for j in range(n + 2):array = np.array(DoG[i][j], dtype=np.float32)plt.subplot(octaves, n + 3, j + (i) * octaves + 1)plt.imshow(array.astype(np.uint8), cmap='gray')plt.axis('off')plt.show()#2. 确定关键点位置,为关键点赋予方向KeyPoints = LocateKeyPoint(DoG, SIFT_SIGMA, GuassianPyramid, n)  # 函数2.1,LocateKeyPoint:关键点定位#3. 计算关键点的描述符discriptors = calcDescriptors(GuassianPyramid, KeyPoints)  # 函数3.1,calcDescriptors:计算描述符return KeyPoints, discriptorsdef Lines(img, info, color=(255, 0, 0), err=700):if len(img.shape) == 2:result = np.dstack((img, img, img))else:result = imgk = 0for i in range(result.shape[0]):for j in range(result.shape[1]):temp = (info[:, 1] - info[:, 0])A = (j - info[:, 0]) * (info[:, 3] - info[:, 2])B = (i - info[:, 2]) * (info[:, 1] - info[:, 0])temp[temp == 0] = 1e-9t = (j - info[:, 0]) / tempe = np.abs(A - B)temp = e < errif (temp * (t >= 0) * (t <= 1)).any():result[i, j] = colork += 1#print(k)return resultdef drawLines(X1, X2, Y1, Y2, dis, img, num=10):info = list(np.dstack((X1, X2, Y1, Y2, dis))[0])info = sorted(info, key=lambda x: x[-1])info = np.array(info)info = info[:min(num, info.shape[0]), :]img = Lines(img, info)# plt.imsave('./sift/3.jpg', img)if len(img.shape) == 2:plt.imshow(img.astype(np.uint8), cmap='gray')else:plt.imshow(img.astype(np.uint8))plt.axis('off')# plt.plot([info[:,0], info[:,1]], [info[:,2], info[:,3]], 'c')# fig = plt.gcf()# fig.set_size_inches(int(img.shape[0]/100.0),int(img.shape[1]/100.0))plt.savefig('result.jpg')plt.show()if __name__ == '__main__':origimg = plt.imread(r'01.jpg')  # 读第一张图片if len(origimg.shape) == 3:#如果是彩色图,就按照三通道取均值的方式转成灰度图img = origimg.mean(axis=-1)else:img = origimgkeyPoints, discriptors = SIFT(img)  # 用SIFT算法计算关键点(x坐标,y坐标,sigma,主方向,梯度幅值)和描述符(128维的向量)origimg2 = plt.imread(r'02.jpg')  # 读第二张图片if len(origimg.shape) == 3:img2 = origimg2.mean(axis=-1)else:img2 = origimg2ScaleRatio = img.shape[0] * 1.0 / img2.shape[0]img2 = np.array(Image.fromarray(img2).resize((int(round(ScaleRatio * img2.shape[1])), img.shape[0]), Image.BICUBIC))keyPoints2, discriptors2 = SIFT(img2)  # 用SIFT算关键点和描述符indexs = []deltas = []for i in range(len(keyPoints2)):ds = discriptors2[i]mindetal = 10000000index = -1detal = 0for j in range(len(keyPoints)):ds0 = discriptors[j]d = np.array(ds)-np.array(ds0)detal = d.dot(d)if( detal <= mindetal):mindetal = detalindex = jindexs.append(index)deltas.append(mindetal)keyPoints = np.array(keyPoints)[:,:2]keyPoints2 = np.array(keyPoints2)[:,:2]keyPoints2[:, 1] = img.shape[1] + keyPoints2[:, 1]origimg2 = np.array(Image.fromarray(origimg2).resize((img2.shape[1],img2.shape[0]), Image.BICUBIC))result = np.hstack((origimg,origimg2))keyPoints = keyPoints[indexs[:]]X1 = keyPoints[:, 1]X2 = keyPoints2[:, 1]Y1 = keyPoints[:, 0]Y2 = keyPoints2[:, 0]drawLines(X1,X2,Y1,Y2,deltas,result)#把匹配的结果放到这里画线

3. 算法结果

20点匹配结果如下:
在这里插入图片描述

最终展示ppt:

链接:https://pan.baidu.com/s/1Y1Os2imDhRvNptHwWShdBw
提取码:2n0s


http://chatgpt.dhexx.cn/article/Ps7RYtvw.shtml

相关文章

Python实现SIFT算法,附详细公式推导和代码

SIFT特征点提取算法 1、算法简介 尺度不变特征转换即SIFT (Scale-invariant feature transform)是一种计算机视觉的算法。它用来侦测与描述影像中的局部性特征&#xff0c;它在空间尺度中寻找极值点&#xff0c;并提取出其位置、尺度、旋转不变量&#xff0c;此算法由 David …

图像特征匹配方法——SIFT算法原理及实现

传统图像处理中图像特征匹配有三个基本步骤&#xff1a;特征提取、特征描述和特征匹配。特征提取就是从图像中提取出关键点&#xff08;或特征点、角点&#xff09;等。特征描述就是用一组数学向量对特征点进行描述&#xff0c;其主要保证不同的向量和不同的特征点之间是一种对…

SIFT算法原理介绍

本文转自&#xff1a;https://blog.csdn.net/qq_37374643/article/details/88606351 SIFT算法 SIFT即尺度不变特征变换&#xff0c;是用于图像处理领域的一种描述。这种描述具有尺度不变性&#xff0c;可在图像中检测出关键点&#xff0c;是一种局部特征描述子。 一、SIFT算…

SIFT算法的个人理解

SIFT算法的个人理解——理论篇 1. 前言 本人目前共使用过两个版本的sift算法: &#xff08;1&#xff09;Matlab中的sift算法&#xff0c;可以从http://www.cs.ubc.ca/~lowe/keypoints/下载Lowe团队写的sift演示代码&#xff1b; &#xff08;2&#xff09;opencv中的sift…

SIFT算法原理解析

首先找到图像中的一些“稳定点”&#xff0c;这些点是一些十分突出的点不会因光照条件的改变而消失&#xff0c;比如角点、边缘点、暗区域的亮点以及亮区域的点&#xff0c;既然两幅图像中有相同的景物&#xff0c;那么使用某种方法分别提取各自的稳定点&#xff0c;这些点之间…

SIFT算法步骤梳理

简介&#xff1a;SIFT算法是检测和描述局部特征的一种方法&#xff0c;具有尺度不变性&#xff0c;对于光线&#xff0c;噪声等的容忍度相当高。即便少数几个物体也可以产生大量SIFT特征。 SIFT算法实质上是在不同尺度空间上查找关键点&#xff0c;并计算出关键点的方向。 算…

SIFT算法原理详解及代码实现(笔记)

一、SIFT算法概述&#xff1a; SIFT&#xff08;Scale Invariant Feature Transform&#xff09;全称尺度不变特征变换&#xff0c;SIFT算子是把图像中检测到的特征点用一个128维的特征向量进行描述&#xff0c;因此一幅图像经过SIFT算法后表示为一个128维的特征向量集&#xf…

SIFT算法 特征匹配

目录 一、SIFT算法DOG尺度空间构造&#xff08;Difference of Gaussian&#xff09;关键点搜索与定位方向赋值、关键点描述 二、特征匹配 一、SIFT算法 参考链接 【OpenCV】SIFT原理与源码分析 DOG尺度空间构造&#xff08;Difference of Gaussian&#xff09; 首先是对原特…

SIFT算法详解——图像特征提取与匹配

文章目录 前言一、建立高斯差分金字塔1、建立高斯金字塔2、建立高斯差分金字塔3、建塔过程中参数的设定及相关细节问题 二、关键点(key points)位置确定1、阈值化2、在高斯差分金字塔中找极值点3、调整极值点位置4、舍去低对比度的点5、边缘效应的去除&#xff08;难点&#xf…

非常详细的sift算法原理解析

尺度不变特征变换匹配算法详解 Scale Invariant Feature Transform(SIFT) Just For Fun 转自&#xff1a;http://blog.csdn.net/zddblog/article/details/7521424 对于初学者&#xff0c;从David G.Lowe的论文到实现&#xff0c;有许多鸿沟&#xff0c;本文帮你跨越。 1、SIFT综…

【Python】:SIFT算法的实现

✨博客主页&#xff1a;米开朗琪罗~&#x1f388; ✨博主爱好&#xff1a;羽毛球&#x1f3f8; ✨年轻人要&#xff1a;Living for the moment&#xff08;活在当下&#xff09;&#xff01;&#x1f4aa; &#x1f3c6;推荐专栏&#xff1a;【图像处理】【千锤百炼Python】【深…

SIFT算法原理

SIFT算法 SIFT即尺度不变特征变换&#xff0c;是用于图像处理领域的一种描述。这种描述具有尺度不变性&#xff0c;可在图像中检测出关键点&#xff0c;是一种局部特征描述子。 一、SIFT算法特点&#xff1a; 1、具有较好的稳定性和不变性&#xff0c;能够适应旋转、尺度缩放…

计算机视觉——SIFT算法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、SIFT算法特点二、SIFT算法实质三、SIFT算法实现特征匹配主要有以下流程&#xff1a;1、**特征点位置和尺度的提取**&#xff1a;2、**特征点方向的提取**3、…

SIFT(尺度不变特征变换)算法

目录 SIFT 1、生成高斯差分金字塔&#xff0c;尺度空间构建 2、空间极值点检测 3、稳定关键点的精确定位 4、稳定关键点方向信息分配 5、关键点描述 6、特征点匹配 SIFT SIFT&#xff1a;Scale-Invariant Feature Trainsform即尺度不变特征变换&#xff0c;这是一种图像…

SIFT算法

1. SIFT简介 尺度不变特征转换(Scale-invariant feature transform或SIFT)是一种电脑视觉的算法用来侦测与描述影像中的局部性特征&#xff0c;它在空间尺度中寻找极值点&#xff0c;并提取出其位置、尺度、旋转不变量&#xff0c;此算法由 David Lowe在1999年所发表&#xff…

SIFT算法详解(附有完整代码)

说明&#xff1a;本文旨在给出 SIFT 算法的具体实现&#xff0c;而在 SIFT 详解上只是做出简单介绍&#xff0c;在这里可以给大家推荐一篇好文&#xff1a;https://blog.csdn.net/zddblog/article/details/7521424&#xff1b;结合这篇文章和下文的具体代码实现&#xff0c;我相…

SIFT算法详解

大纲 引言一、高斯金字塔二、高斯差分金字塔三、特征点处理1.阈值化2.非极大值抑制3. 二阶泰勒修正4.低对比度去除5.边缘效应去除 四、特征点描述子1. 确定特征点区域方向2. 特征点区域描述子 总结参考&#xff1a; 引言 SIFT算法是为了解决图片的匹配问题&#xff0c;想要从图…

全网最详细SIFT算法原理实现

文章目录 一、SIFT算法1.1什么是SIFT算法&#xff1f;1.2SIFT算法特点 二、SIFT算法实质2.1SIFT算法实现特征匹配主要有以下三个流程&#xff1a; 三、SIFT算法原理3.1图像金字塔3.2创建图像高斯金字塔3.3高斯金字塔创建总图 四、尺度空间五、高斯差分金字塔5.1极值点(Key poin…

uniapp如何下拉刷新?其实简简单单

uniapp如何上拉刷新&#xff1f;其实简简单单 不论是微信小程序和app上拉刷新功能都是非常常用的&#xff0c;可以说是每个app的标配。 文章目录 uniapp如何上拉刷新&#xff1f;其实简简单单第一步&#xff1a;1.1app全局开启下拉刷新1.2 app中单个页面开启下拉刷新 第二步2.…

uni-app(9)— 下拉刷新以及关闭下拉刷新,上拉加载(页面触底)

此文为uni-app总结笔记&#xff08;9&#xff09;— 下拉刷新以及关闭下拉刷新&#xff0c;上拉加载&#xff08;页面触底&#xff09; 下拉刷新 开启下拉刷新 在uni-app中有三种方式开启下拉刷新 方法一&#xff1a; 需要在 pages.json 里&#xff0c;找到的当前页面的pag…