Sift特征

Posted 机器学习的小学生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sift特征相关的知识,希望对你有一定的参考价值。

说明:本篇博客只围绕sift描述子展开了学习。对于sift关键点检测涉及的内容并未进行详细的分析和学习。相关内容可参考本篇博客中的参考文献。

Sift特征

Sift特征包含两个部分,一个是关键点(frame或者keypoint),另外一个就是在关键点处的描述子(descriptor,或者Keypoint descriptor),更确切的说是关键点所在尺度空间的描述子。

很多文章中给出了两种尺度空间:高斯尺度空间GSS和高斯差分尺度空间DOG。可能会怀疑,到底描述子是在哪个尺度空间计算的?其实采用的是高斯尺度空间。如下图:GSS对图像使用[-1,4]不同尺度的高斯进行平滑得到图像,其索引号[-1,4]指明了不同的尺度,DOG索引号为[-1,3]只是表示与GSS索引号对应的关系,并且图中还给出了”DOG下极值的计算“的索引号,其为GSS的中间三个,即[0,2]。例如,如果我们在”DOG下极值的计算“,发现在其索引号为0尺度有满足条件的关键点,那么该关键点所处的尺度空间就是: s=0 的高斯尺度空间。

在面部特征点的检测中,经常提取Sift特征。这里的Sift特征指的就是Sift描述子,在一个点处提取的Sift特征一般为128维,即4*4*8=128,4*4表示4*4的区域,8表示每个区域统计的方向。

在Vfleat中:frame 表示Keypoint,descriptor 表示Keypoint descriptor

自定义关键点:

vl_sift函数可以自定义关键点,然后计算该关键点处的描述子。

例如我们可以计算关键点在(100,100),尺度为10,方向为 π8 的描述子:

fc=[100;100;10;-pi/8];
[f,d]=vl_sift(I,'frames',fc);

我们不指定方向,使用关键点的方向,即将方向参数设置为0,并通过参数’orientations’指定,则:

fc=[100;100;10;0];
[f,d]=vl_sift(I,'frames',fc,'orientations');

也可以将参数fc设置为矩阵的形式,一次计算多个关键点的描述子。特别的,一个关键点可能有多个方向,或者没有方向(图像区域为常数)

问题就来了,这里的尺度是什么?描述子的方向怎么计算的呢?如果方向是指描述子的主方向,那么通过直方图确定主方向时采用的邻域是多大呢?
如上面的函数,我们传入的尺度为10,是使用标准差为 σ=10 的高斯对图像进行平滑后,然后进行后面的处理吗?等等一连串的问题,使得我很模糊。
下图给出了高斯尺度示意图,其中左右表格内画红色的下划线的表示(这里我们下表都从0开始):第1层的第0个图像,是从第0层的第3个图像下采样得到,随后第1层的第1个图像是由第1层的第0个图像再经过高斯标准差为 σ2(1,0)σ2(1,1) 的高斯平滑后得到的,以次类推。。。

这里写图片描述

Vlfeat库的配置:

Vlfeat的源程序使用C语言编写,读起来和使用起来也着实让人费力。由于Vlfeat给出了能够计算给定关键点的描述子的Matlab接口函数。那么我们Matlab入口运行程序进行学习分析。
Vlfeat提供的两个版本:
(1).vlfeat-0.9.20-bin.tar.gz (编译好的二进制文件)
(2).vlfeat-0.9.20 (源文件)

1.下载完vlfeat-0.9.20后,将其解压到当前文件夹,在目录下,有个Makefile.mak文件。使用写字板或者Notepad打开,该文件内给出了需要修改的详细说明,即Customization(定制)部分。

#                                                        Customization
# --------------------------------------------------------------------
# To modify this script to run on your platform it is usually
# sufficient to modify the following variables:
#
# ARCH: Either win32 or win64 [win64]
# DEBUG: Set to yes to ativate debugging [no]
# MATLABROOT: Path to MATLAB
# MSVSVER: Visual Studio version (e.g. 80, 90, 100) [90 for VS 9.0]
# MSVCROOT: Visual C++ location [$(VCInstallDir)].
# WINSDKROOT: Windows SDK location [$(WindowsSdkDir)]
#
# Note that some of these variables depend on the architecture
# (either win32 or win64).

修改截图如下:
这里写图片描述
我们电脑上装了两个Matlab,R2014a是32位的,R2014b是64位的。

2.
方法1:双击vlfeat.vcproj打开,进入VS2010界面,点击直到完成后,在左侧的解决方案一栏,对vlfeat进行编译,即build即可。
方法2:在电脑程序目录下,找到Visio Studio Tools找到类似于Visual Studio x64 Win64 命令提示(2010)的工具,点击运行,然后在dos下,将目录切换到vlfeat-0.9.20目录,然后利用nmake命令:

nmake /f Makefile.mak

3.目的:将mex.c文件编译成供Matlab调用的二进制文件。
打开Matlab,将工程目录切换到vlfeat-0.9.20\\toolbox目录下,首先修改一下vl_compile.m文件,即将mex -o,修改为mex -g,如下:
这里写图片描述

调试Sift源文件

1.打开Matlab,当然首先是要设置好包含路径,主页-设置路径-添加并包含子文件夹,将vlfeat-0.9.20添加进去。我为了省事,一般都是直接将所有的添加进去,你可以选择只需要将toolbox/mex添加到Matlab路径中。然后书写简单的代码:

%clc;clearvars;
% prepare data
imgPath='E:\\data\\lfw\\imgs\\Aaron_Eckhart\\Aaron_Eckhart_0001.jpg';
bbox=[63 72 126+63 126+72];
landmark=[34 35; 53 38; 41 86; 75 90; 58 93; 59 87 ;72 40 ;94 43; 48 70; 72 72];
nlandmark=10;
isShow=false;
for i=1:nlandmark
    landmark(i,1)=landmark(i,1)+bbox(1);
    landmark(i,2)=landmark(i,2)+bbox(2);
end

if isShow
    figure(1);
    subplot(2,1,1);
    img=imread(imgPath);
    img_gray=rgb2gray(img);
    imshow(img_gray);
    hold on;
    for i=1:nlandmark
        plot(landmark(i,1),landmark(i,2),'.r','markersize',8);
    end
    % for box;
    rmpath('E:\\matlabworkplace\\headpose_with_block\\third_part\\vlfeat-0.9.20\\toolbox\\noprefix');
    plotbox(bbox,'r');
    addpath('E:\\matlabworkplace\\headpose_with_block\\third_part\\vlfeat-0.9.20\\toolbox\\noprefix');
end

% I = vl_impattern('roofs1') ;
% image(I) ;
% I = single(rgb2gray(I)) ;
% [f,d] = vl_sift(I) ;
% perm = randperm(size(f,2)) ;
% sel = perm(1:50) ;
% h1 = vl_plotframe(f(:,sel)) ;
% h2 = vl_plotframe(f(:,sel)) ;
% set(h1,'color','k','linewidth',3) ;
% set(h2,'color','y','linewidth',2) ;

pi=3.1415926;
img=imread(imgPath);
figure(1);
%subplot(1,2,1);
image(img);
img_gray=rgb2gray(img);
I=single(img_gray);
hold on;
ori=[pi/8 2*pi/8 3*pi/8 4*pi/8 5*pi/8 6*pi/8 7*pi/8 pi -pi/8 -2*pi/8];
%scale=[1 2 3 4 5 6 7 8 9 10];
scale=[1.6 1.6 1.6 1.6 1.6 1.6 1.6 1.6 1.6 1.6];
for i=1:10
    plot(landmark(i,1),landmark(i,2),'.r','markersize',16);
    fc=[landmark(i,1);landmark(i,2);scale(i);ori(i)];
    [f,d]=vl_sift(I,'frames',fc);
    h1=vl_plotframe(f(:,1));
    h2=vl_plotframe(f(:,1));
    set(h1,'color','k','linewidth',3);
    set(h2,'color','y','linewidth',2);
    name=num2str(i);
    text(landmark(i,1),landmark(i,2),name);
end
%%上面的代码可以不需要,只需要下面的代码。
figure(2);
img2 = vl_impattern('roofs1') ;
image(img2) ;
img2 = single(rgb2gray(img2)) ;
[f,d] = vl_sift(img2) ;
perm = randperm(size(f,2)) ;
sel = perm(1:50) ;
h1 = vl_plotframe(f(:,sel)) ;
h2 = vl_plotframe(f(:,sel)) ;
set(h1,'color','k','linewidth',3) ;
set(h2,'color','y','linewidth',2) ;
h3 = vl_plotsiftdescriptor(d(:,sel),f(:,sel)) ;
set(h3,'color','g') ;

2.打开VS2010,通过菜单中的文件-打开-文件,将vlfeat-0.9.20\\toolbox\\sift下的vl_sift.c和vlfeat-0.9.20\\vl下的sift.c添加到VS中,然后在两个文件中,设置断点就可以了。
3.在VS2010中设置为断点后,在VS菜单中工具-附加到进程,在可用进程中找到Matlab,然后双击即可。
4.运行Matlab程序,会自动跳转到VS2010设置的断点处,通过F5进行断点的切换。如下图:
这里写图片描述

参数说明

公式1: