目录
一、理论基础
图像配准就是找到一幅图像像素到另一幅图像像素间的空间映射关系。这些图像可以是不同时间(多时间配准),不同传感器在不同地方拍摄(多模式配准)。图像配准主要使用基于特征的方法。这些方法有三个步骤:关键点检测和特征描述,特征匹配,图像变换。简单的说,我们选择两个图像中的感兴趣点,将参考图像(reference image)与感测图像(sensed image)中的等价感兴趣点进行关联,然后变换感测图像使两个图像对齐。
关键点就是感兴趣点,它表示图像中重要或独特的内容(边角,边缘等)。每个关键点由描述符表示,关键点基本特征的特征向量。描述符应该对图像变换(定位,缩放,亮度等)具有鲁棒性。许多算法使用关键点检测和特征描述:
SIFTScale-invariant feature transform)是用于关键点检测的原始算法,但它不能免费用于商业用途。SIFT特征描述符对于均匀缩放,方向,亮度变化和对仿射失真不变的部分不会发生变化。SURF(Speeded Up Robust Features)是一个受SIFT启发的探测器和描述符。它的优点是非常快。它同样是有专利的。ORB[6](Oriented FAST and Rotated BRIEF)是一种快速的二进制描述符,它基于 FAST(Features from Accelerated Segment Test)关键点检测和 BRIEF(Binary robust independent elementary features)描述符的组合。它具有旋转不变性和对噪声的鲁棒性。它由OpenCV实验室开发,是SIFT有效的免费替代品。AKAZE(Accelerated-KAZE)是KAZE[10]快速版本。它为非线性尺度空间[11]提供了快速的多尺度特征检测和描述方法,具有缩放和旋转不变性。这些算法都可以在OpenCV中轻松使用。在下面的例子中,我们使用了AKAZE的OpenCV实现。其他算法的代码大致相同,只需要修改算法的名称。
SIFT算法得到了图像中的特征点以及相应的特征描述,如何把两张图像中的特征点匹配起来呢?一般的可以使用K近邻(KNN)算法。K近邻算法求取在空间中距离最近的K个数据点,并将这些数据点归为一类。在进行特征点匹配时,一般使用KNN算法找到最近邻的两个数据点,如果最接近和次接近的比值大于一个既定的值,那么我们保留这个最接近的值,认为它和其匹配的点为good match(有Lowe在SIFT论文中提出)。
SIFT(Scale invariant feature transform),即尺度不变特征变换描述子,其可以从图像中提取稳定的特征数据,其对图像的旋转、阴影干扰、噪声干扰、移动以及空间扭曲等影响有着较好的不变性。基于SIFT的图像特征提取原理如下:
步骤一、图像转换到尺度空间。图像的尺度空间表示方式通常情况下是将图像和高斯核函数进行卷积计算,其计算公式如下:
步骤二、尺度空间极值点的计算。在SIFT算法中,一般采用差分图像来计算尺度空间极值,其计算公式如下:
SIFT (Scale-invariant feature transform), 尺度不变特征转换,是一种图像局部特征提取算法,它通过在不同的尺度空间中寻找极值点(特征点,关键点)的精确定位和主方向,构建关键点描述符来提取特征。SIFT提取的关键点具有尺度不变性、旋转不变性,而且不会因光照、仿射变换和噪音等因素而干扰。
SIFT所查找到的关键点是一些十分突出、不会因光照、仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。
二、核心程序
function [frames,descriptors,scalespace,difofg]=do_sift(I,varargin)
%% file: sift.m
% author: Noemie Phulpin
% description: SIFT algorithm
warning off all;
[M,N,C] = size(I) ;
% Lowe's choices
S=3 ;
omin= 0 ;
%O=floor(log2(min(M,N)))-omin-4 ; % Up to 16x16 images
O = 4;
sigma0=1.6*2^(1/S) ;
sigmaN=0.5 ;
thresh = 0.2 / S / 2 ; % 0.04 / S / 2 ;
r = 18 ;
NBP = 4 ;
NBO = 8 ;
magnif = 3.0 ;
% Parese input
compute_descriptor = 0 ;
discard_boundary_points = 1 ;
verb = 0 ;
% Arguments sanity check
if C > 1
error('I 应该是灰度图') ;
end
frames = [] ;
descriptors = [] ;
%
% 开始工作
%
fprintf('---------------------------- 开始 SIFT: 从图像中提取SIFT特征 ------------------------------\n') ; tic ;
fprintf('SIFT: 用DoG构造尺度空间 ...\n') ; tic ;
scalespace = do_gaussian(I,sigmaN,O,S,omin,-1,S+1,sigma0) ;
fprintf(' 高斯尺度空间计时: (%.3f s)\n',toc) ; tic ;
difofg = do_diffofg(scalespace) ;
fprintf(' 构建相减尺度空间: (%.3f s)\n',toc) ;
for o=1:scalespace.O
fprintf('CS5240 -- SIFT: 计算 “组” %d\n', o-1+omin) ;
tic ;
% DOG octave 的局部极值检测
oframes1 = do_localmax( difofg.octave{o}, 0.8*thresh, difofg.smin ) ;
oframes2 = do_localmax( -difofg.octave{o}, 0.8*thresh, difofg.smin ) ;
oframes = [oframes1 ,oframes2 ] ;
fprintf('CS5240 -- SIFT: 初始化关键点 # %d. \n', ...
size(oframes, 2)) ;
fprintf(' 用时 (%.3f s)\n', ...
toc) ;
tic ;
if size(oframes, 2) == 0
continue;
end
% 移除靠近边界的关键点
rad = magnif * scalespace.sigma0 * 2.^(oframes(3,:)/scalespace.S) * NBP / 2 ;
sel=find(...
oframes(1,:)-rad >= 1 & ...
oframes(1,:)+rad <= size(scalespace.octave{o},2) & ...
oframes(2,:)-rad >= 1 & ...
oframes(2,:)+rad <= size(scalespace.octave{o},1) ) ;
oframes=oframes(:,sel) ;%把不是靠近边界点的极值点重新放入oframes中
fprintf('CS5240 -- SIFT: 移除靠近边界关键点后 # %d \n', size(oframes,2)) ;
tic ;
% 精简局部, 阈值强度 和移除边缘关键点
oframes = do_extrefine(...
oframes, ...
difofg.octave{o}, ...
difofg.smin, ...
thresh, ...
r) ;
fprintf('CS5240 -- SIFT: 移除低对比度和边缘上关键点后 # %d \n',size(oframes,2)) ;
fprintf(' Time (%.3f s)\n', toc) ;
tic ;
fprintf('CS5240 -- SIFT: 计算特征点方向\n');
% 计算方向
oframes = do_orientation(...
oframes, ...
scalespace.octave{o}, ...
scalespace.S, ...
scalespace.smin, ...
scalespace.sigma0 ) ;
fprintf(' 用时: (%.3f s)\n', toc);tic;
% Store frames
x = 2^(o-1+scalespace.omin) * oframes(1,:) ;
y = 2^(o-1+scalespace.omin) * oframes(2,:) ;
sigma = 2^(o-1+scalespace.omin) * scalespace.sigma0 * 2.^(oframes(3,:)/scalespace.S) ; %图像的尺度
frames = [frames, [x(:)' ; y(:)' ; sigma(:)' ; oframes(4,:)] ] ;
fprintf('CS5240 -- SIFT:计算方向后的特征点 # %d \n', size(frames,2)) ;
% Descriptors
fprintf('CS5240 -- SIFT: 计算 描述子...\n') ;
tic ;
sh = do_descriptor(scalespace.octave{o}, ...
oframes, ...
scalespace.sigma0, ...
scalespace.S, ...
scalespace.smin, ...
'Magnif', magnif, ...
'NumSpatialBins', NBP, ...
'NumOrientBins', NBO) ;
descriptors = [descriptors, sh] ;%每一组计算描述子向量后补充到descriptors数组中
fprintf(' 用时: (%.3f s)\n\n\n',toc) ;
end
fprintf('CS5240 -- SIFT: 关键点总数: %d \n\n\n', size(frames,2)) ;
up138