纯MATLAB版本 SIFT代码

先贴几个链接:

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 邮箱:[email protected]

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

时间: 2024-10-06 00:58:36

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

【转载】 Faster-RCNN+ZF用自己的数据集训练模型(Matlab版本)

说明:本博文假设你已经做好了自己的数据集,该数据集格式和VOC2007相同.下面是训练前的一些修改. (做数据集的过程可以看http://blog.csdn.net/sinat_30071459/article/details/50723212) Faster-RCNN源码下载地址: Matlab版本:https://github.com/ShaoqingRen/faster_rcnn Python版本:https://github.com/rbgirshick/py-faster-rcnn 本

如何在Android App中使用matlab的神经网络代码

整个过程大概可以分成这么几步: 首先你要在matlab中写一个完整的神经网络 获取样本 样本导入 神经网络建模 神经网络训练 神经网络测试(优化建模) 然后你要在matlab中重写一个神经网络,第二个神经网络的特殊之处是 首先这个神经网络必须写成函数,具体有几个细节 把第一个神经网络的训练结果net网络保存成mat文件 把相关需要用的但无法直接写入代码的数据也保存成mat文件(比如数据归一化的参数) 然后在函数中把上面几个mat文件导入,基本上就是一个完整的神经网络模型了 再加上一个神经网络计算

libsvm的使用(exe版和matlab版本)

libsvm是台湾国立大学的林智仁开发的svm工具箱,有matlab,C++,python,java的接口.本文对exe版本和matlab版本的使用进行说明. libsvm可以在 http://www.csie.ntu.edu.tw/~cjlin/libsvm/ 官网上进行下载,我下载的是libsvm-3.12 exe 版本 libsvm的exe版本在windows文件夹下,主要包含3个exe, svm-train.exe,  svm-scale.exe,  svm-predict.exe (1

Windchill 设置大版本的代码

public static void setVersion(final Versioned versioned, String version) throws WTException { try { if (version == null || version.trim().length() == 0) { // If the version ID string is null then the load file did not // specify it. version = null; i

纯手写wcf代码,wcf入门,wcf基础教程

<pre name="code" class="cpp">/* 中颖EEPROM,使用比较方便,但有个注意点,就是每次无论你写入 什么数据或者在哪个地址写数据,都需要将对 对应的块擦除,擦 除后才能写入成功. */ #define SSPWriteFlag 0x5A #define SSPEraseFlag 0xA5 //数据区 扇形区1 #define ADDR_START1 (uint16)0x100 //数据存储区起始地址 #define ADDR

7、Cocos2dx 3.0游戏开发找小三之3.0版本的代码风格

重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27691337 Cocos2d-x代码风格 前面我们已经多次提到 Cocos2d-x 源自于 Cocos2d-iPhone.Cocos2d-iPhone 是一个十分出色的游戏引擎,许多优秀的 iOS平面游戏都基于 Cocos2d-iPhone 开发,而它的实现语言是 Objective-C.因此,Cocos2d-x 也就沿袭了 Objective-C 的

k-means算法MATLAB和opencv代码

上一篇博客写了k-means聚类算法和改进的k-means算法,这篇博客就贴出对应的MATLAB和C++代码. 以下是MATLAB代码,实现用k-means进行分割: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 功能:实现如何利用Kmeans聚类实现图像的分割: 时间:2015-07 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function kmeans_segmentation() clear;c

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

球体的双目视觉定位(matlab,附代码) 标签(空格分隔): 机器视觉 引言 双目视觉定位是我们的一个课程设计,最近刚做完,拿出来与大家分享一下,实验的目的是在拍摄的照片中识别球体,并求出该球体到相机的实际距离吗,我们要求需要用matlab,但是matlab调用双目摄像头(一个USB口)却老是只能调用双目摄像头中的一个,但是利用Python的OpenCV库却可以同时调用两个,因此我们选用了Python用于拍摄图片. 1.基本流程 备注:因为根据得出的视差图识别出圆球略困难,我们没有采用视差图深

ecos matlab版本安装

官网链接 github地址 1.注意不仅要下载matlab版本,同时还要下载c版本,因为matlab版本缺少第三方软件,将两个版本解压缩后将c版本下的文件夹external,ecos_bb,include,src考到matlab版本下的ecos文件夹中 2.在matlab下打开ecos的matlab版本,并进入他的bin文件,在命令行输入 makemex 3.添加路径 addpath 'D:\ecos\ecos-matlab-master\ecos-matlab-master\bin' 4.如果