前言:首先你還是要了解一下sift的原理,這裏就不多做贅述了!我之前的博客裏有介紹,也有一些大佬的博客,講得特別好!!!大家可以看一下!
話不多說,本人就是菜鳥!所以從最簡單的入門開始!一點點敲代碼!
clc;
clear;
% 讀取兩個要匹配的圖像
% Input1 = imread('DIPbook1.png');
% Input2 = imread('DIPbook2.png');
% 自己的兩個圖片
Input1 = imread('IMG_cup1.jpg');
Input2 = imread('IMG_cup2.jpg');
下面是我要測試的兩張圖片!建議圖像不要太大,不然電腦內存有點受不了!
IMG_cup1.jpg IMG_cup2.jpg
圖片已經到位,接下來就是提取圖像的SIFT
[Imagedb1,Kpt1,Dsp1] = SIFT(Input1);
fprintf('Found %d SIFT points.\n',size(Kpt1,1));
[Imagedb2,Kpt2,Dsp2] = SIFT(Input2);
fprintf('Found %d SIFT points.\n',size(Kpt2,1));
參數:Imagedb1代表擴大了2倍的灰度圖像,你可以用imshow()展示一下,就是灰度圖像,Kpt1代表圖像的關鍵點,Dsp1表示關鍵點的描述子,對於Input2的情況是一樣的;還有就是對於關鍵點,這裏keypoints數據每行爲所在的1組、2層、3行、4列、以及(5層、6行、7列)的微小偏差、8主方向角度;下圖是Kpt1
如何獲取上面的關鍵點和描述子呢?下面看一下SIFT主函數(SIFT.m)
這裏參考了這位大佬的YangHongbo表示感謝!
function [Imagedb Keypoint Descriptors] = sift(Input1)
% Keypiont 每行爲所在1組、2層、3行、4列、以及(5層、6行、7列)的微小偏差、8主方向角度
% Descriptors每行爲Keypoint中某一行對應的d*d*n爲特徵向量描述符(Lowe給出的是4*4*8=128)
% 判斷是否是3維圖像,如果是轉爲灰度圖
if ndims(Input1)==3
Imagegray = rgb2gray(Input1);
else
Imagegray = Input1;
end
% 接下來就是提前聲明一些全局變量,matlab中是global聲明
% global camera_sigma sigma0;
% global enlarge
% global Octave Layers;
% global sigma;
% 1、全局數據管理,並返回灰度圖的浮點數數據Imagedb(0~1之間)
% 後續的參數修改主要就是在這個函數中進行修改
Imagedb = Define(Imagegray);
% 2、創建高斯金字塔
gausspyr = buildgausspyr(Imagedb);
% 3、根據高斯金字塔創建DoG金字塔
Dogpyr = buildDogpyr(gausspyr,Dogpyr);
% 4、根據高斯金字塔和DoG金字塔然後求極值點,不懂得還是看一下論文感覺比較好
Keypoint = findExtrma(gausspyr,Dogpyr);
% 用於保存獲取的描述子
Descriptors = [];
% 遍歷所有的關鍵點的行,如果是2則代表列
% size(x,0/1))代表行和列
for i = 1:size(Keypoint,1)
kpt = Keypoint(i,:);
descriptors = calcDescriptors(gausspyr,kpt);
% a = [a;b] 的意思就是一行一行的接在下面進行保存;這裏要求a和b的維度必須一致
% a = [a,b] 則是b接在a的尾部,稱爲一個新的a
Descriptors = [Descriptors;descriptors];
end
end
1、全局參數設置
% 全局變量的定義,matlab中使用global將變量聲明爲全局變量
% 必要的全局變量的定義,所有全局變量將在各個子程序中調用。
% sigma_num():得到本組內,層之間的尺度關係以及本組內實際尺度
function Imagedb = Define(Imagegray)
ifelse=@(a,b,c)(a~=0)*b+(a==0)*c; %生成三目運算符
global enlarge
enlarge = 1; %是否放大原始圖片,等於0則不放大
% logical()將數值轉換爲邏輯值:True / false 1/0
if ( logical(enlarge) )
% imresize()調整圖像的大小,是在灰度圖的基礎上,雙線性插值的基礎上
% 圖像轉換爲雙精度
Imagedb = im2double(imresize(Imagegray,2,'bilinear')); %圖片放大2倍
else
Imagedb = im2double(Imagegray);
end
global camera_sigma sigma0;
camera_sigma = 0.5; %原始輸入圖片定義尺度爲camera_sigma;
sigma0 = 1.6; % 高斯最下面一組最下一層的尺度
global Octave Layers;
Layers = 3; % 高斯金字塔爲Layers+3層,Dog爲Layers+2層
Octave = -1; % 定義高斯塔的組數目,其值>0則通過自動獲取,否則按照圖片尺寸確定
% 以下代碼爲組數的計算,是自定義還是根據圖像(有無放大原圖像)尺寸確定組的數量
Octave = ifelse(Octave >0,Octave,ifelse(logical(enlarge), ...
log(min(size(Imagegray)))/log(2)-1,log(min(size(Imagegray)))/log(2)-2));
Octave = round(Octave);
global sigma;
sigma = zeros(2,Layers+3);
sigma = sigma_num(); %第1行返回本層尺度與上一層尺度的平方差開根號,第2行返回在本組中的實際尺度
global SIFT_Img_Border;
SIFT_Img_Border = 6; %在Dog金字塔中去掉四周的像素數量SIFT_Img_Borde-1
global ExtrThreshold;
% 在極值點精確定位前爲1/2*ExtrThreshold,精確定位閾值爲ExtrThreshold;
ExtrThreshold = 0.03;%lowe 建議值0.03,但是這個值是歸一化0-1中間的
global edgegama; %hessian矩陣中用於判斷是否屬於邊界點的閾值
edgegama = 10;
global SIFT_STEP;
SIFT_STEP = 5;
global IterationMax; %極值點精確查找過程中偏移量過大值,則認爲極值點不穩定
IterationMax = 3;
global SIFT_ORI_HIST_BINS; %定義主方向柱數量
SIFT_ORI_HIST_BINS = 36;
global SIFT_ORI_SIG_FCTR; % 主方向半徑爲SIFT_ORI_RADIUS*SIFT_ORI_SIG_FCTR*所在組內尺度(包含層偏移小數)
SIFT_ORI_SIG_FCTR = 1.5;
global SIFT_ORI_RADIUS;
SIFT_ORI_RADIUS = 3;
global SIFT_ORI_PEAK_RATIO; %多個主方向,爲最大值主方向的閾值
SIFT_ORI_PEAK_RATIO = 0.8;
global boolParabolicFit;
boolParabolicFit = 0; %主方向柱通過拋物線擬合方法或者中心偏移方法
global SIFT_DESCR_WIDTH;
SIFT_DESCR_WIDTH = 4; %特徵點描述符 分爲SIFT_DESCR_WIDTH *SIFT_DESCR_WIDTH 個正方形
global SIFT_DESCR_HIST_BINS; %特徵點描述符 正方形內方向柱數量:SIFT_DESCR_HIST_BINS
SIFT_DESCR_HIST_BINS = 8; %128維 = SIFT_DESCR_WIDTH * SIFT_DESCR_WIDTH * SIFT_DESCR_HIST_BINS
global SIFT_DESCR_SCL_FCTR;
SIFT_DESCR_SCL_FCTR = 3; %特徵點周圍SIFT_DESCR_SCL_FCTR*(d+1)範圍。備註:還需要擴大1.414倍
global SIFT_DESCR_MAG_THR;
SIFT_DESCR_MAG_THR = 0.2; % 特徵點描述符中,大於該閾值的點被置爲固定值
2、創建高斯金字塔
% 創建高斯金字塔
% OpenCV中內核的大小計算方法。
% ksize.height = cvRound(sigma2*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
% CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 &&
% ksize.height > 0 && ksize.height % 2 == 1 );//確保核寬和核高爲正奇數
% cell 解決數組問題
% A = cell(numArrays,1);
% for n = 1:numArrays
% A{n} = magic(n);
% end
function gausspyr = buildgausspyr(Imagedb)
global Octave Layers;
global sigma;
Oct = Octave;S = Layers+3;
gausspyr = cell(Oct,1) ;
for oct = 1:1:Oct
clear gausspyr_oct gauss_at_1;
for lay = 1:1:S
ksize = 2*sigma(1,lay)*3+1; % 濾波內核範圍
ksize = 2*round(ksize/2-0.5)+1; % 濾波內核確保爲奇數
at = lay;
if oct == 1 && lay == 1
w=fspecial('gaussian',[ksize ksize],sigma(1,lay));
gausspyr_oct(:,:,at) = imfilter(Imagedb,w,'same');
else if oct >= 1 && lay >= 2
w=fspecial('gaussian',[ksize ksize],sigma(1,lay));
gausspyr_oct(:,:,at) = imfilter(gausspyr_oct(:,:,at-1),w,'same');
else if oct >= 2 && lay == 1
gauss_at_1 = gausspyr{oct-1}(:,:,S-2) ; % 前一組倒數第三層
gauss_at = imresize(gauss_at_1,0.5,'bilinear');
gausspyr_oct(:,:,at) = gauss_at;
end
end
end
end
gausspyr{oct} = gausspyr_oct;
end
3、根據高斯金字塔創建DoG金字塔
% 創建Dog金字塔
function Dogpyr = buildDogpyr(gausspyr)
global Octave Layers;
Oct = Octave;D = Layers+2;
Dogpyr = cell(Oct,1) ;
for oct = 1:1:Oct
for lay = 1:1:D
% 圖片數據如何歸一化 ???
% 圖片不歸一化目的是後面的極值點判斷時,歸一化以後原來在0附近的點都被錯誤的線性化了。
Dogpyr{oct}(:,:,lay) = gausspyr{oct}(:,:,lay+1) - gausspyr{oct}(:,:,lay);
% 將圖片歸一化到(0-1) 如果想顯示並查看Dog金字塔圖像 歸一化顯示否則不歸一化的圖片很可能將顯示的一片黑
% % laymax = max(max(Dogpyr{oct}(:,:,lay)));
% % laymin = min(min(Dogpyr{oct}(:,:,lay)));
% % [oct lay laymax laymin] %用於查看dog塔中各層之間的最大最小值,便於人工通過數據感官其穩定性
% % 因爲有過考慮畢竟不是Log圖,擔心Dog層與層之間相差一個常數(k-1)sigma*sigma,從而引起極值點都跑到某一個層裏面
% % 經過實驗對比發現貌似擔心是多餘的,但還沒有嚴格的數學證明
% Dogpyr{oct}(:,:,lay) = (Dogpyr{oct}(:,:,lay)-laymin)/(laymax-laymin);
% Dogpyr{oct}(:,:,lay) = 2*(Dogpyr{oct}(:,:,lay)-laymin)/(laymax-laymin)-1;
end
end
4、根據高斯金字塔和DoG金字塔然後求極值點
% 尋找極值點
% adjustExtrPoint(Dogpyr,) 調整極值點位置,確定精確點
% oritHist 返回主方向統計圖
function keypoint = findExtrma(gausspyr,Dogpyr)
keypoint = [];
global Octave Layers;
global SIFT_Img_Border;
global ExtrThreshold;
global SIFT_ORI_PEAK_RATIO; %多個主方向,爲最大值主方向的閾值
global SIFT_ORI_HIST_BINS; %定義主方向柱數量
n = SIFT_ORI_HIST_BINS;
global boolParabolicFit; %主方向柱通過拋物線擬合方法或者中心偏移方法
for oct = 1:1:Octave
for lay = 2:1:Layers+1
[rows cols] = size(Dogpyr{oct}(:,:,lay));
laymax = max(max(Dogpyr{oct}(:,:,lay)));
laymin = min(min(Dogpyr{oct}(:,:,lay)));
Extr_lay = 1/2*ExtrThreshold*max( abs(laymax),abs(laymin) );
% 邊界各去掉SIFT_Img_Border-1個元素
for r = SIFT_Img_Border:1:rows-SIFT_Img_Border+1
for c = SIFT_Img_Border:1:cols-SIFT_Img_Border+1
cub1 = Dogpyr{oct}(r-1:r+1,c-1:c+1,lay-1);
cub2 = Dogpyr{oct}(r-1:r+1,c-1:c+1,lay);
cub3 = Dogpyr{oct}(r-1:r+1,c-1:c+1,lay+1);
cub = [cub1(:) ; cub2(:) ;cub3(:)]; %在r,c附近的立方體共27個元素
% 先去掉本身不穩定的極值點
if abs(Dogpyr{oct}(r,c,lay)) > Extr_lay && ...
( Dogpyr{oct}(r,c,lay) == max(cub) || Dogpyr{oct}(r,c,lay) == min(cub) )
r1 = r; c1 =c; lay1 = lay;
%kpt所在的組、層、行、列、以及(層、行、列)的微小偏差
[flagbool kpt] = adjustExtrPoint(Dogpyr,gausspyr,oct,lay1,r1,c1);
if flagbool == 1 %極值點位置進一步判斷條件成立以及精確定位
[maxval hist] = oritHist(gausspyr,kpt);
for j = 1:1:n
j_pre = j-1;
j_pre(j_pre<1) = n;
j_next = j+1;
j_next(j_next>n) = 1;
if hist(j)>hist(j_pre) && hist(j)>hist(j_next) && hist(j)>=SIFT_ORI_PEAK_RATIO*maxval
% 拋物線擬合方程
if boolParabolicFit
bin = j+0.5*(hist(j_pre)-hist(j_next))/(hist(j_pre)+hist(j_next)-2*hist(j));
else
% 我個人認爲直觀的解釋或許下面這個更合適
bin = j+(hist(j_next)-hist(j_pre))/(hist(j_pre)+hist(j)+hist(j_next));
end
angle = (bin-1)*360/n;
%keypoint爲所在的1組、2層、3行、4列、以及(5層、6行、7列)的微小偏差、8主方向角度
keypoint = [keypoint;kpt angle];
end
end
end
end
end
end
end
end
代碼中涉及到的一些函數:
(1)計算特徵描述符calcDescriptors.m
% 計算特徵描述符
function descriptors= calcDescriptors(gausspyr,Keypoint)
%keypoint爲所在的1組、2層、3行、4列、以及(5層、6行、7列)的微小偏差、8主方向角度
global SIFT_DESCR_WIDTH; %特徵點描述符 分爲SIFT_DESCR_WIDTH *SIFT_DESCR_WIDTH 個正方形
d = SIFT_DESCR_WIDTH;
global SIFT_DESCR_HIST_BINS; %特徵點描述符 正方形內方向柱數量:SIFT_DESCR_HIST_BINS
n = SIFT_DESCR_HIST_BINS ; % d*d*n = 128維
dst = zeros(1,d*d*n);
deg_per_bin = 360/n;
global SIFT_DESCR_SCL_FCTR; %SIFT_DESCR_SCL_FCTR = 3;
global sigma;
global SIFT_DESCR_MAG_THR;
oct = Keypoint(1); % 組
lay = Keypoint(2); % 層
gauss_sigma0 = sigma(2,lay); % 高斯塔所在層的sigma
hist_width = SIFT_DESCR_SCL_FCTR * gauss_sigma0 ;
radius = round(hist_width * sqrt(2)/2*(d+1));
ori = Keypoint(8); % 主方向角度
cos_ori = cosd(ori);
sin_ori = sind(ori);
[rows cols] = size(gausspyr{oct}(:,:,lay));
exp_scale = -2/(d*d); %高斯權重相當於爲d/2;
cubhist = zeros(d+2,d+2,n+1);
k = 0;
for ri = -radius:1:radius
for ci = -radius:1:radius
rcd = [cos_ori -sin_ori;sin_ori cos_ori] *[ri;ci]; %旋轉
rd_ = rcd(1)/hist_width; %旋轉後的行 d
cd_ = rcd(2)/hist_width; %旋轉後的列 d
% 移位到左上角
rbin = rd_ + d/2-0.5; %旋轉移位後的行 d
cbin = cd_ + d/2-0.5; %旋轉移位後的列 d
% r = gausspyr{oct} (Keypoint(3),Keypoint(4),lay);
r = Keypoint(3)+ri; %旋轉前的行座標
c = Keypoint(4)+ci; %旋轉前的列座標
if rbin>-1 && rbin<d && cbin>-1 && cbin<d && ...
r>=2 && r<=rows-1 && c>=2 && c<=cols-1
k=k+1;
dx = gausspyr{oct}(r,c+1,lay)-gausspyr{oct}(r,c-1,lay);
dy = gausspyr{oct}(r+1,c,lay)-gausspyr{oct}(r-1,c,lay);
Dx(k) =dx;Dy(k) =dy;
Rbin(k) = rbin;Cbin(k) =cbin;
W(k) = exp((rd_^2+cd_^2)*exp_scale); %權重
end
end
end
len = k;
Mag = sqrt(Dx.*Dx + Dy.*Dy); %梯度幅值;
orik = rad2deg( atan2(Dy,Dx) ); %atan2(a,b)是4象限反正切,它的取值不僅取決於正切值a/b,還取決於點 (b, a) 落入哪個象限:
orik(orik<0) = orik(orik<0)+360; % 將-180~180轉換爲 0~360;該語句在ori>0時不執行;
for k=1:1:len
rbin =Rbin(k);cbin =Cbin(k); %旋轉移位後的行列 d
ori1 = orik(k)-ori;
ori1(ori1<0) = ori1+360; %將-360-360轉換爲 0-360°
obin = ori1/deg_per_bin;
mag = Mag(k)*W(k);
r0 = floor(rbin);c0 = floor(cbin); %取值範圍爲 [-1~d-1]
ob0 = floor(obin); %取值範圍爲 [0~8]
ob0(ob0==8) = 0; %取值範圍爲 [0~7]
rbin = rbin-r0; % 小數部分
cbin = cbin-c0;
obin = obin-ob0;
% 爲了防止超出邊界
histc = c0+2; % c0 取值範圍爲 [-1~d-1]
histr = r0+2; % r0 取值範圍爲 [-1~d-1]
histo = ob0+1; % ob0 取值範圍爲 [0~7]
%
cubhist(histc,histr,histo) = (1-cbin)*(1-rbin)*(1-obin)*mag + ...
cubhist(histc,histr,histo);
cubhist(histc,histr,histo+1) = (1-cbin)*(1-rbin)*obin*mag + ...
cubhist(histc,histr,histo+1);
cubhist(histc,histr+1,histo) = (1-cbin)*rbin*(1-obin)*mag + ...
cubhist(histc,histr+1,histo);
cubhist(histc,histr+1,histo+1) = (1-cbin)*rbin*obin*mag + ...
cubhist(histc,histr+1,histo+1);
cubhist(histc+1,histr,histo) = cbin*(1-rbin)*(1-obin)*mag + ...
cubhist(histc+1,histr,histo);
cubhist(histc+1,histr,histo+1) = cbin*(1-rbin)*obin*mag + ...
cubhist(histc+1,histr,histo+1);
cubhist(histc+1,histr+1,histo) = cbin*rbin*(1-obin)*mag + ...
cubhist(histc+1,histr+1,histo);
cubhist(histc+1,histr+1,histo+1) = cbin*rbin*obin*mag + ...
cubhist(histc+1,histr+1,histo+1);
end
% cs = [sum(Mag.*W) sum(cubhist(:))]
cubhist(:,:,1) = cubhist(:,:,1) +cubhist(:,:,n+1); %在0°和360°數據合併
for i=1:1:d % 行r
for j=1:1:d %列c
for k=1:1:n %方向柱1~n
dst(((i-1)*d+j-1)*n+k) = cubhist(i+1,j+1,k);
end
end
end
descriptors =dst/sqrt(sumsqr(dst));
% 大於閾值則被置爲閾值值
descriptors(descriptors>SIFT_DESCR_MAG_THR) = SIFT_DESCR_MAG_THR;
descriptors =descriptors/sqrt(sumsqr(descriptors));
(2) 極值點位置處方向統計oritHist.m
% 極值點位置處方向統計
%
function [maxval Hist] = oritHist(gausspyr,kpt) % kpt所在的1組、2層、3行、4列、以及(5層、6行、7列)的微小偏差
global SIFT_ORI_HIST_BINS; %定義主方向柱數量
n = SIFT_ORI_HIST_BINS; %
global SIFT_ORI_SIG_FCTR; % 主方向半徑爲SIFT_ORI_RADIUS*SIFT_ORI_SIG_FCTR*所在組內尺度(包含層偏移小數)
global SIFT_ORI_RADIUS;
global sigma0;
global Layers;
oct = kpt(1);lay = kpt(2);
sgm = sigma0*power(2,1/Layers*(lay+kpt(5))); %相對於本組的尺度
radius = round(SIFT_ORI_RADIUS*SIFT_ORI_SIG_FCTR*sgm); %主方向統計鄰域半徑
expf_scale = -1/(2*(sgm*SIFT_ORI_SIG_FCTR)*(sgm*SIFT_ORI_SIG_FCTR)); % 正態權重e指數部分
[rows cols] = size(gausspyr{oct}(:,:,lay));
k = 0;
for i=-radius:1:radius
r = kpt(3)+i;
if r<2 || r>rows-1 %行超出範圍
continue;
end
for j=-radius:1:radius
c = kpt(4)+j;
if c<2 || c>cols-1 %列超出範圍
continue;
end
% 因爲只需要比值,故差分的分母取消不要
dx = gausspyr{oct}(r,c+1,lay)-gausspyr{oct}(r,c-1,lay);
dy = gausspyr{oct}(r+1,c,lay)-gausspyr{oct}(r-1,c,lay);
k = k+1;
Dx(k) = dx; Dy(k) = dy;W(k) = (i*i+j*j)*expf_scale;
end
end
len = k; %實際統計的數量因爲超出範圍有可能並沒有真正在正負radius 的範圍內
clear Mag ori exp_W;
Mag = sqrt(Dx.*Dx + Dy.*Dy); %梯度幅值;
ori = rad2deg( atan2(Dy,Dx) ); %atan2(a,b)是4象限反正切,它的取值不僅取決於正切值a/b,還取決於點 (b, a) 落入哪個象限:
ori(ori<0) = ori(ori<0)+360; % 將-180~180轉換爲 0~360;該語句在ori>0時不執行;
exp_W = exp(W); % 權重沒必要歸一化,因爲每個柱子都是相同比例放大或縮小
temphist = zeros(1,n+1);
for k = 1:1:len
bin = round(ori(k)/360*n);
temphist(bin+1) = temphist(bin+1)+exp_W(k)*Mag(k);
end
temphist(1) = temphist(1)+temphist(1+n);%第i柱子的角度範圍爲 (i-1)*10-5 ~ (i-1)*10+5
lvbhist = zeros(1,n+4);
lvbhist = [temphist(n-1) temphist(n) temphist(1:n) temphist(1) temphist(2)];
Hist = zeros(1,n);
for i=1:1:n
ilb=i+2;
Hist(i) = 6/16*lvbhist(ilb)+4/16*(lvbhist(ilb+1)+lvbhist(ilb-1))+1/16*(lvbhist(ilb+2)+lvbhist(ilb-2)); %第i柱子的角度範圍爲 (i-1)*10-5 ~ (i-1)*10+5
end
maxval = max(Hist(:));
(3) 圖像拼接 appendimages.m
% 這個函數來源於LOWE的主頁,別害怕!僅僅是個最簡單的圖片拼接
function im = appendimages(image1, image2)
% Select the image with the fewest rows and fill in enough empty rows
% to make it the same height as the other image.
rows1 = size(image1,1);
rows2 = size(image2,1);
if (rows1 < rows2)
image1(rows2,1) = 0; %雖然只增補最後的一行,實際上中間的區域也自動補零。
else
image2(rows1,1) = 0;
end
% Now append both images side-by-side.
im = [image1 image2];
最後添上主函數:matches.mlx
clc;
clear;
% 讀取兩個要匹配的圖像
% Input1 = imread('DIPbook1.png');
% Input2 = imread('DIPbook2.png');
% 自己的兩個圖片
Input1 = imread('IMG_cup1.jpg');
Input2 = imread('IMG_cup2.jpg');
[Imagedb1,Kpt1,Dsp1] = SIFT(Input1);
fprintf('Found %d SIFT points.\n',size(Kpt1,1));
[Imagedb2,Kpt2,Dsp2] = SIFT(Input2);
fprintf('Found %d SIFT points.\n',size(Kpt2,1));
% keypoints數據每行爲所在的1組、2層、3行、4列、以及(5層、6行、7列)的微小偏差、8主方向角度
distRatio = 0.6;
% Kpt1*Kpt2';
k = 0;
for i = 1:size(Dsp1,1)
% 以度爲單位的反餘弦運算,將值轉換爲角度
angle = acosd(Dsp1(i,:)*Dsp2');
[angle,indx] = sort(angle);
if angle(1)<distRatio*angle(2)
k = k + 1;
match(k,1:2) = [i indx(1)];
end
end
len = k;
fprintf('Found %d matches.\n',len);
twoPic = appendimages(Imagedb1,Imagedb2);
imshow(twoPic);
hold on;
% match()信號匹配的邏輯表達,返回0或者1
% round()四捨五入到最近的小數
cols1 = size(Imagedb1,2);
SIFT_pos1 = [];
SIFT_pos2 = [];
for i = 1:len
zb1 = [Kpt1(match(i,1),3) + Kpt1(match(i,1),6) Kpt1(match(i,1),4) + Kpt1(match(i,1),7)];
zb2 = [Kpt2(match(i,2),3) + Kpt2(match(i,2),6) Kpt2(match(i,2),4) + Kpt2(match(i,2),7)];
zb1_img = round(zb1*2^(Kpt1(match(i,1),1)-1));
zb2_img = round(zb2*2^(Kpt2(match(i,2),1)-1));
% line([起點橫座標,終點橫座標],[起點縱座標,終點縱座標]),
line([zb1_img(2) zb2_img(2) + cols1],...
[zb1_img(1) zb2_img(1)],'linestyle',':','Color','c');
% text向數據點添加文字說明
text(zb1_img(2),zb1_img(1),num2str(i),'color','red');
text(zb2_img(2)+cols1,zb2_img(1),num2str(i),'color','red');
SIFT_pos1 = [SIFT_pos1;zb1_img(2) zb1_img(1)]; % 點橫座標x以及縱座標y
SIFT_pos2 = [SIFT_pos2;zb2_img(2) zb2_img(1)]; % 點橫座標x以及縱座標y
end
[trsArray,indx,piancha] = affinity(SIFT_pos1,SIFT_pos2);
輸出結果:Found 829 SIFT points
Found 715 SIFT points
Found 45 matches.
以上的代碼來源於:SIFT程序實現 有需要的可以自己去下載,也可以按照上面的代碼一點點敲;感謝這位大佬的講解!