先贴几个链接:

http://blog.csdn.net/abcjennifer/article/details/7639681  Rachel-Zhang的

http://blog.csdn.net/manji_lee/article/details/8922474

David G. Lowe的两篇标志性的文章分别叫 Object recognition from local scale-invariant features 和

Distinctive Image Features from Scale-Invariant Keypoints

其实我就是想在博客里保存下网上下载的纯MATLAB版本的sift代码

%% 功能:提取灰度图像的尺度不变特征(SIFT特征)
% 输入:
% im - 灰度图像,该图像的灰度值在0到1之间(注意:应首先对输入图像的灰度值进行归一化处理)
% octaves - 金字塔的组数:octaves (默认值为4).
% intervals - 该输入参数决定每组金字塔的层数(默认值为 2).
% object_mask - 确定图像中尺度不变特征点的搜索区域,如果没有特别指出,则算法将搜索整个图像
% contrast_threshold - 对比度阈值(默认值为0.03).
% curvature_threshold - 曲率阈值(默认值为10.0).
% interactive - 函数运行显示标志,将其设定为1,则显示算法运行时间和过程的相关信息;
% 如果将其设定为2,则仅显示最终运行结果(default = 1).
%
% 输出:
% pos - Nx2 矩阵,每一行包括尺度不变特征点的坐标(x,y)
% scale - Nx3 矩阵,每一行包括尺度不变特征点的尺度信息
% (第一列是尺度不变特征点所在的组,
% 第二列是其所在的层,
% 第三列是尺度不变特征点的sigma).
% orient - Nx1 向量,每个元素是特征点的主方向,其范围在 [-pi,pi)之间.
% desc - N x 128 矩阵,每一行包含特征点的特征向量. %% 步骤0:载入图像后归一化,并扩充成 2xN-1 大小
% 用于彻底搞懂SIFT的MATLAB版本代码的一个测试文件
clear all;clc;close all;
% im = rgb2gray(imread('nest.png'));
im = imread('nest.png');
im = scjMatMap(im,0,1); antialias_sigma = 0.5;
signal = im; [X Y] = meshgrid( 1:0.5:size(signal,2), 1:0.5:size(signal,1) );
signal = interp2( signal, X, Y, '*linear' ); % im被扩充成 2 x N - 1 了 subsample = [0.5]; % 降采样率
%% 步骤1:生成高斯和差分高斯(DOG)金字塔
% 这两个金字塔的数据分别存储在名为
% gauss_pyr{orient,interval}和DOG_pyr{orient,interval}
% 的元胞数组中。高斯金字塔含有s+3层,差分高斯金字塔含有s+2层。 preblur_sigma = sqrt(sqrt(2)^2 - (2*antialias_sigma)^2); g = gaussian_filter( preblur_sigma ); gauss_pyr{1,1} = conv2( g, g, signal, 'same' );
clear signal; % 完成了初始化工作 % 第一组第一层的sigma
initial_sigma = sqrt( (2*antialias_sigma)^2 + preblur_sigma^2 ); octaves = 4; % 有4层金字塔
intervals = 2; % 每一层有2张图片 s+3
% 之所以+3,是因为:生成DOG时会减少一个图片,在计算极值的时候
% 第一个和最后一个图片不能使用,所以要+3.
% 为了保证差分高斯金字塔DOG在每一层至少有一张图片可用来寻找极值点
% 必须让高斯金字塔有+3张图片
% 最后会有octaves层,每层intervals+3张图片 % 记录每一层和每一个尺度的sigma
absolute_sigma = zeros(octaves,intervals+3);
absolute_sigma(1,1) = initial_sigma * subsample(1); % 记录产生金字塔的滤波器的尺寸和标准差
filter_size = zeros(octaves,intervals+3);
filter_sigma = zeros(octaves,intervals+3); % 生成高斯和差分高斯金字塔
for octave = 1:octaves
sigma = initial_sigma;
g = gaussian_filter(sigma);
filter_size(octave,1) = length(g);
filter_sigma(octave,1) = sigma;
DOG_pyr{octave} = ...
zeros(size(gauss_pyr{octave,1},1),size(gauss_pyr{octave,1},2),intervals+2);
for interval = 2:(intervals+3)
sigma_f = sqrt(2^(2/intervals) - 1)*sigma;
g = gaussian_filter( sigma_f );
sigma = (2^(1/intervals))*sigma; % 记录sigma的值
absolute_sigma(octave,interval) = sigma * subsample(octave); % 记录滤波器的尺寸和标准差
filter_size(octave,interval) = length(g);
filter_sigma(octave,interval) = sigma; gauss_pyr{octave,interval} = conv2(g,g,gauss_pyr{octave,interval-1}, 'same' );
DOG_pyr{octave}(:,:,interval-1) = ...
gauss_pyr{octave,interval} - gauss_pyr{octave,interval-1};
end
if octave < octaves
sz = size(gauss_pyr{octave,intervals+1});
[X Y] = meshgrid( 1:2:sz(2), 1:2:sz(1) );
gauss_pyr{octave+1,1} = interp2(gauss_pyr{octave,intervals+1},X,Y,'*nearest');
absolute_sigma(octave+1,1) = absolute_sigma(octave,intervals+1);
subsample = [subsample subsample(end)*2];
end
end
%% 步骤2:查找差分高斯金字塔中的局部极值,并通过曲率和照度进行检验
contrast_threshold = 0.02;
curvature_threshold = 10.0; curvature_threshold = ((curvature_threshold + 1)^2)/curvature_threshold; % 二阶微分核
xx = [ 1 -2 1 ];
yy = xx';
xy = [1 0 -1;
0 0 0;
-1 0 1]/4; raw_keypoints = [];
contrast_keypoints = [];
curve_keypoints = []; object_mask = ones(size(im)); % 在高斯金字塔中查找局部极值
loc = cell(size(DOG_pyr));
for octave = 1:octaves
for interval = 2:(intervals+1)
keypoint_count = 0;
contrast_mask = abs(DOG_pyr{octave}(:,:,interval)) >= contrast_threshold;
loc{octave,interval} = zeros(size(DOG_pyr{octave}(:,:,interval))); edge = ceil(filter_size(octave,interval)/2); for y=(1+edge):(size(DOG_pyr{octave}(:,:,interval),1)-edge)
for x=(1+edge):(size(DOG_pyr{octave}(:,:,interval),2)-edge)
if object_mask(round(y*subsample(octave)),round(x*subsample(octave))) == 1
interactive = 1;
if( (interactive >= 2) | (contrast_mask(y,x) == 1) ) % 注意!
% 通过空间核尺度检测最大值和最小值
tmp = DOG_pyr{octave}((y-1):(y+1),(x-1):(x+1),(interval-1):(interval+1));
pt_val = tmp(2,2,2);
if( (pt_val == min(tmp(:))) | (pt_val == max(tmp(:))) )
% 存储对灰度大于对比度阈值的点的坐标
raw_keypoints = [raw_keypoints; x*subsample(octave) y*subsample(octave)];
if abs(DOG_pyr{octave}(y,x,interval)) >= contrast_threshold
contrast_keypoints = [contrast_keypoints; raw_keypoints(end,:)];
% 计算局部极值的Hessian矩阵
Dxx = sum(DOG_pyr{octave}(y,x-1:x+1,interval) .* xx);
Dyy = sum(DOG_pyr{octave}(y-1:y+1,x,interval) .* yy);
Dxy = sum(sum(DOG_pyr{octave}(y-1:y+1,x-1:x+1,interval) .* xy));
% 计算Hessian矩阵的直迹和行列式.
Tr_H = Dxx + Dyy;
Det_H = Dxx*Dyy - Dxy^2;
% 计算主曲率.
curvature_ratio = (Tr_H^2)/Det_H;
if ((Det_H >= 0) & (curvature_ratio < curvature_threshold))
% 存储主曲率小于阈值的的极值点的坐标(非边缘点)
curve_keypoints = [curve_keypoints; raw_keypoints(end,:)];
% 将该点的位置的坐标设为1,并计算点的数量.
loc{octave,interval}(y,x) = 1;
keypoint_count = keypoint_count + 1;
end
end
end
end
end
end
end fprintf( 2, '%d keypoints found on interval %d\n', keypoint_count, interval ); end
end
clear raw_keypoints contrast_keypoints curve_keypoints;
%% 步骤3:计算特征点的主方向.
% 在特征点的一个区域内计算其梯度直方图
g = gaussian_filter( 1.5 * absolute_sigma(1,intervals+3) / subsample(1) );
zero_pad = ceil( length(g) / 2 ); % 计算高斯金字塔图像的梯度方向和幅值
mag_thresh = zeros(size(gauss_pyr));
mag_pyr = cell(size(gauss_pyr));
grad_pyr = cell(size(gauss_pyr)); for octave = 1:octaves
for interval = 2:(intervals+1) % 计算x,y的差分
diff_x = 0.5*(gauss_pyr{octave,interval}(2:(end-1),3:(end))-gauss_pyr{octave,interval}(2:(end-1),1:(end-2)));
diff_y = 0.5*(gauss_pyr{octave,interval}(3:(end),2:(end-1))-gauss_pyr{octave,interval}(1:(end-2),2:(end-1))); % 计算梯度幅值
mag = zeros(size(gauss_pyr{octave,interval}));
mag(2:(end-1),2:(end-1)) = sqrt( diff_x .^ 2 + diff_y .^ 2 ); % 存储高斯金字塔梯度幅值
mag_pyr{octave,interval} = zeros(size(mag)+2*zero_pad);
mag_pyr{octave,interval}((zero_pad+1):(end-zero_pad),(zero_pad+1):(end-zero_pad)) = mag; % 计算梯度主方向
grad = zeros(size(gauss_pyr{octave,interval}));
grad(2:(end-1),2:(end-1)) = atan2( diff_y, diff_x );
grad(find(grad == pi)) = -pi; % 存储高斯金字塔梯度主方向
grad_pyr{octave,interval} = zeros(size(grad)+2*zero_pad);
grad_pyr{octave,interval}((zero_pad+1):(end-zero_pad),(zero_pad+1):(end-zero_pad)) = grad;
end
end clear mag grad
%% 步骤4:确定特征点的主方向
% 方法:通过寻找每个关键点的子区域内梯度直方图的峰值(注:每个关键点的主方向可以有不止一个) % 将灰度直方图分为36等分,每隔10度一份
num_bins = 36;
hist_step = 2*pi/num_bins; % 步进值
hist_orient = [-pi:hist_step:(pi-hist_step)]; % 步进方向 % 初始化关键点的位置、方向和尺度信息
pos = [];
orient = [];
scale = []; % 给关键点确定主方向
for octave = 1:octaves
for interval = 2:(intervals + 1)
keypoint_count = 0; % 构造高斯加权掩模
g = gaussian_filter( 1.5 * absolute_sigma(octave,interval)/subsample(octave) );
hf_sz = floor(length(g)/2);
g = g'*g; loc_pad = zeros(size(loc{octave,interval})+2*zero_pad);
loc_pad((zero_pad+1):(end-zero_pad),(zero_pad+1):(end-zero_pad)) = loc{octave,interval}; [iy ix]=find(loc_pad==1);
for k = 1:length(iy) x = ix(k);
y = iy(k);
wght = g.*mag_pyr{octave,interval}((y-hf_sz):(y+hf_sz),(x-hf_sz):(x+hf_sz));
grad_window = grad_pyr{octave,interval}((y-hf_sz):(y+hf_sz),(x-hf_sz):(x+hf_sz));
orient_hist=zeros(length(hist_orient),1);
for bin=1:length(hist_orient)
diff = mod( grad_window - hist_orient(bin) + pi, 2*pi ) - pi;
orient_hist(bin) = ...
orient_hist(bin)+sum(sum(wght.*max(1 - abs(diff)/hist_step,0)));
end % 运用非极大抑制法查找主方向直方图的峰值
peaks = orient_hist;
rot_right = [ peaks(end); peaks(1:end-1) ];
rot_left = [ peaks(2:end); peaks(1) ];
peaks( find(peaks < rot_right) ) = 0;
peaks( find(peaks < rot_left) ) = 0; % 提取最大峰值的值和其索引位置
[max_peak_val ipeak] = max(peaks); % 将大于等于最大峰值80% 的直方图的也确定为特征点的主方向
peak_val = max_peak_val;
while( peak_val > 0.8*max_peak_val ) % 最高峰值最近的三个柱值通过抛物线插值精确得到
A = [];
b = [];
for j = -1:1
A = [A; (hist_orient(ipeak)+hist_step*j).^2 (hist_orient(ipeak)+hist_step*j) 1];
bin = mod( ipeak + j + num_bins - 1, num_bins ) + 1;
b = [b; orient_hist(bin)];
end
c = pinv(A)*b;
max_orient = -c(2)/(2*c(1));
while( max_orient < -pi )
max_orient = max_orient + 2*pi;
end
while( max_orient >= pi )
max_orient = max_orient - 2*pi;
end % 存储关键点的位置、主方向和尺度信息
pos = [pos; [(x-zero_pad) (y-zero_pad)]*subsample(octave) ];
orient = [orient; max_orient];
scale = [scale; octave interval absolute_sigma(octave,interval)];
keypoint_count = keypoint_count + 1; peaks(ipeak) = 0;
[peak_val ipeak] = max(peaks);
end
end
fprintf( 2, '(%d keypoints)\n', keypoint_count );
end
end
clear loc loc_pad
%% 步骤5:特征向量生成
orient_bin_spacing = pi/4;
orient_angles = [-pi:orient_bin_spacing:(pi-orient_bin_spacing)]; grid_spacing = 4;
[x_coords y_coords] = meshgrid( [-6:grid_spacing:6] );
feat_grid = [x_coords(:) y_coords(:)]';
[x_coords y_coords] = meshgrid( [-(2*grid_spacing-0.5):(2*grid_spacing-0.5)] );
feat_samples = [x_coords(:) y_coords(:)]';
feat_window = 2*grid_spacing; desc = []; for k = 1:size(pos,1)
x = pos(k,1)/subsample(scale(k,1));
y = pos(k,2)/subsample(scale(k,1)); % 将坐标轴旋转为关键点的方向,以确保旋转不变性
M = [cos(orient(k)) -sin(orient(k)); sin(orient(k)) cos(orient(k))];
feat_rot_grid = M*feat_grid + repmat([x; y],1,size(feat_grid,2));
feat_rot_samples = M*feat_samples + repmat([x; y],1,size(feat_samples,2)); % 初始化特征向量.
feat_desc = zeros(1,128); for s = 1:size(feat_rot_samples,2)
x_sample = feat_rot_samples(1,s);
y_sample = feat_rot_samples(2,s); % 在采样位置进行梯度插值
[X Y] = meshgrid( (x_sample-1):(x_sample+1), (y_sample-1):(y_sample+1) );
G = interp2( gauss_pyr{scale(k,1),scale(k,2)}, X, Y, '*linear' ); % 耗时太长
G(find(isnan(G))) = 0;
diff_x = 0.5*(G(2,3) - G(2,1));
diff_y = 0.5*(G(3,2) - G(1,2));
mag_sample = sqrt( diff_x^2 + diff_y^2 );
grad_sample = atan2( diff_y, diff_x );
if grad_sample == pi
grad_sample = -pi;
end % 计算x、y方向上的权重
x_wght = max(1 - (abs(feat_rot_grid(1,:) - x_sample)/grid_spacing), 0);
y_wght = max(1 - (abs(feat_rot_grid(2,:) - y_sample)/grid_spacing), 0);
pos_wght = reshape(repmat(x_wght.*y_wght,8,1),1,128); diff = mod( grad_sample - orient(k) - orient_angles + pi, 2*pi ) - pi;
orient_wght = max(1 - abs(diff)/orient_bin_spacing,0);
orient_wght = repmat(orient_wght,1,16); % 计算高斯权重
g = exp(-((x_sample-x)^2+(y_sample-y)^2)/(2*feat_window^2))/(2*pi*feat_window^2); feat_desc = feat_desc + pos_wght.*orient_wght*g*mag_sample;
end % 将特征向量的长度归一化,则可以进一步去除光照变化的影响.
feat_desc = feat_desc / norm(feat_desc); feat_desc( find(feat_desc > 0.2) ) = 0.2;
feat_desc = feat_desc / norm(feat_desc); % 存储特征向量.
desc = [desc; feat_desc];
tmp = mod(k,25);
if ( tmp == 0 )
fprintf( 2, '.' );
end
end % 调整采样偏差
sample_offset = -(subsample - 1);
for k = 1:size(pos,1)
pos(k,:) = pos(k,:) + sample_offset(scale(k,1));
end if size(pos,1) > 0
scale = scale(:,3);
end hh = display_keypoints( pos, scale, orient);

调用了

function g = gaussian_filter(sigma)

% 功能:生成一维高斯滤波器
% 输入:
% sigma – 高斯滤波器的标准差
% 输出:
% g – 高斯滤波器 sample = 7.0/2.0;
n = 2*round(sample * sigma)+1;
x = 1:n;
x = x - ceil(n/2); g = exp(-(x.^2)/(2*sigma^2))/(sigma*sqrt(2*pi));

原作者是Xiaochuan ZHAO 邮箱:zhaoxch@bit.edu.cn

我去除了他的代码中一些无关紧要的部分。

纯MATLAB版本 SIFT代码的更多相关文章

  1. RobHess的SIFT代码解析步骤三

    平台:win10 x64 +VS 2015专业版 +opencv-2.4.11 + gtk_-bundle_2.24.10_win32 主要参考:1.代码:RobHess的SIFT源码 2.书:王永明 ...

  2. k-means算法MATLAB和opencv代码

    上一篇博客写了k-means聚类算法和改进的k-means算法.这篇博客就贴出相应的MATLAB和C++代码. 下面是MATLAB代码,实现用k-means进行切割: %%%%%%%%%%%%%%%% ...

  3. MATLAB版本(2012b 64bit),在尝试调用svmtrain函数时报错

    问题:MATLAB版本(2012b 64bit),在尝试调用svmtrain函数时报错: 解决方案:参照https://blog.csdn.net/TIME_LEAF/article/details/ ...

  4. 一道在CF上WA了9次才AC的A题题目与10个版本的代码代码

    题目(题目链接:https://codeforces.com/problemset/problem/733/A):   A. Grasshopper And the String time limit ...

  5. 球体的双目视觉定位(matlab,附代码)

    球体的双目视觉定位(matlab,附代码) 标签(空格分隔): 机器视觉 引言 双目视觉定位是我们的一个课程设计,最近刚做完,拿出来与大家分享一下,实验的目的是在拍摄的照片中识别球体,并求出该球体到相 ...

  6. RobHess的SIFT代码解析步骤四

    平台:win10 x64 +VS 2015专业版 +opencv-2.4.11 + gtk_-bundle_2.24.10_win32 主要参考:1.代码:RobHess的SIFT源码 2.书:王永明 ...

  7. H5+ 重写在线升级版本比较代码

    重写h5+在线升级版本比较代码 hello h5+版本在线升级提供了如下的版本比较方法,逻辑比较繁琐,相关判断多余,非常不宜读. 先判断新旧版本有无, 接着分割为数组比较数组项大小,而且还只取了前四项 ...

  8. sift代码实现详解

    1.创建高斯金字塔第-1组 1.1.将源图片转成灰度图 void ConvertToGray(const Mat& src, Mat& dst) { cv::Size size = s ...

  9. ie使用已安装的最高版本ie代码,及ie下不要在结尾处写多余的逗号“,”

    ie使用已安装的最高版本ie代码 <meta http-equiv = "X-UA-Compatible" content = "IE=7,IE=9" & ...

随机推荐

  1. opencv3中SurfFeatureDetector、SurfDescriptorExtractor、BruteForceMatcher的使用

    opencv2中SurfFeatureDetector.SurfDescriptorExtractor.BruteForceMatcher在opencv3中发生了改变.具体如何完成特征点匹配呢?示例如 ...

  2. String的intern()方法详解

    https://blog.csdn.net/soonfly/article/details/70147205  :图解 https://blog.csdn.net/wjzhang5514/articl ...

  3. 在java中(==)的用法

  4. mongodb集群性能优化

    mongodb集群性能优化 在前面两篇文章,我们介绍了如何去搭建mongodb集群,这篇文章我们将介绍如何去优化mongodb的各项配置,以达到最优的效果. 警告 不做任何的优化,集群搭建完成之后,使 ...

  5. java的数组和arraylist

    1.数组 1.0   一开始就错了 int a[8];   //没有像C在内存中开辟了8个区域 改: int a[] = {1,2,3} ; System.out.println(a.length); ...

  6. linux日志管理

    //有关当前登录用户的信息记录在文件utmp中 //登录进入和退出纪录在文件wtmp中 [root@bogon python]# who //who命令查询utmp文件并报告当前登录的每个用户 /va ...

  7. Unity 5 Game Optimization (Chris Dickinson 著)

    1. Detecting Performance Issues 2. Scripting Strategies 3. The Benefits of Batching 4. Kickstart You ...

  8. DevExpress的DateEdit控件正确显示日期的周名称

    DevExpress 的控件相当好看而且很好用,但 DateEdit 在是显示周名时,只能显示一个“星”字. 以下是解决方法,此解决方法不需修改其源码,所以免去了重新编译的必要,可直接使用其发布的标准 ...

  9. Java基础语法 第2节 Java语言基本语法

    一.标识符和关键字 1.标识符 1)java中标识符用来为程序的白能量.常量.方法.类.接口和包名命名,标识符由字母.数字.下划线.美元符号组成,且第一个字符不能是数字: 2)标志符命名规则:见名知意 ...

  10. tensorflow object detection

    Follow guidelin from https://github.com/tensorflow/models/blob/master/research/object_detection/g3do ...