匹配幾何校驗
一、 任務描述
- 給定一對圖像,利用提取好的SIFT特徵文件,根據距離閾值準則(跨圖像的局部SIFT特徵距離小於0.4),得到圖像間的初始局部特徵匹配關係;
- 基於上述初步匹配結果,實現spatial coding方法,進行匹配校驗,確定幾何不一致的匹配;
- 將幾何一致的匹配和不一致的匹配在圖像上畫出來,分別用藍色和紅色進行區分。
二、 實驗步驟
- 尋找匹配對:尋找並提取第1張圖與第2張圖的SIFT描述子匹配對的(x,y)座標點集,分別放進維數爲(2*對應點數)的矩陣Map1,Map2中。
- 生成空間映射:根據Map1,Map2每個點相對其他點座標的左右上下位置關係,以及k種(本實驗中取k=4)旋轉角度,生成由0、1構成的維數爲(對應點數對應點數k)的空間編碼矩陣GX1,GY1,GX2,GY2中。
- 計算不一致性矩陣:將空間編碼矩陣GX1與GX2,GY1與GY2進行邏輯異或操作得到不一致性矩陣Vx,Vy。
- 計算不一致性總和Sx,Sy: 矩陣Vx,Vy各行元素求和,再對k個方向各行元素和求總和,得到Sx,Sy,維數爲(匹配點數*1)
- 檢查Sx,Sy,識別錯誤匹配項:首先基於Vx,計算Sx,找到對應的i*, 然後從Vx和Vy中把對應的第i行、第i列全部刪掉(或者mask掉,本實驗中以置零方式進行mask),隨後立即更新紅藍連線;然後基於更新後的Vy,計算Sy,找到對應的j*, 然後從Vx和Vy中把對應的第j行、第j列全部刪掉(或者mask掉,本實驗中以置零方式進行mask),隨後立即更新紅藍連線。 對更新後的Vx和Vy重複上面兩步,直到收斂(本實驗取不一致性總和的閾值爲(0.8*匹配對數)取整)。
三、 實驗效果
四、 實驗代碼
其中本實驗對圖像特徵描述子的讀取通過已準備好的“.sift”文件直接讀進matlab中,也可以自己在matlab中讀取“.jpg”圖片後轉爲SIFT格式的描述子數據,matlab代碼如下:
%% Set path and parameters
clear;
close all;
clc;
src_1 = './test images/37967br1.jpg';
src_2 = './test images/791.jpg';
% src_1 = './test images/4.jpg';
% src_2 = './test images/Apollo-266.jpg';
% src_1 = './test images/771.jpg';
% src_2 = './test images/305.jpg';
% src_1 = './test images/Apollo-49.jpg';
% src_2 = './test images/Apollo-266.jpg';
ext = '.sift'; % extension name of SIFT file
siftDim = 128;
maxAxis = 400;
%% Load image
im_1 = imread(src_1);
if max(size(im_1)) > maxAxis
im_1 = imresize(im_1, maxAxis / max(size(im_1)));
end
im_2 = imread(src_2);
if max(size(im_2)) > maxAxis
im_2 = imresize(im_2, maxAxis / max(size(im_2)));
end
%% Load SIFT feature from file
featPath_1 = [src_1, ext];
featPath_2 = [src_2, ext];
fid_1 = fopen(featPath_1, 'rb');
featNum_1 = fread(fid_1, 1, 'int32');
SiftFeat_1 = zeros(siftDim, featNum_1);
paraFeat_1 = zeros(4, featNum_1);
for i = 1 : featNum_1
SiftFeat_1(:, i) = fread(fid_1, siftDim, 'uchar');
paraFeat_1(:, i) = fread(fid_1, 4, 'float32');
end
fclose(fid_1);
fid_2 = fopen(featPath_2, 'rb');
featNum_2 = fread(fid_2, 1, 'int32');
SiftFeat_2 = zeros(siftDim, featNum_2);
paraFeat_2 = zeros(4, featNum_2);
for i = 1 : featNum_2
SiftFeat_2(:, i) = fread(fid_2, siftDim, 'uchar');
paraFeat_2(:, i) = fread(fid_2, 4, 'float32');
end
fclose(fid_1);
%%Normalization
SiftFeat_1 = SiftFeat_1 ./ repmat(sqrt(sum(SiftFeat_1.^2)), size(SiftFeat_1, 1), 1);
SiftFeat_2 = SiftFeat_2 ./ repmat(sqrt(sum(SiftFeat_2.^2)), size(SiftFeat_2, 1), 1);
%% Check match based on distances between SIFT descriptors across images
normVal = mean(sqrt(sum(SiftFeat_1.^2)));
matchInd = zeros(featNum_1, 1);
matchDis = zeros(featNum_1, 1);
validDis = [];
gridDisVec = [];
ic = 0;
for i = 1 : featNum_1 %以第一張圖描述子數量爲基準進行匹配
tmpFeat = repmat(SiftFeat_1(:, i), 1, featNum_2); % repmat(A,m,n),將矩陣 A 複製 m×n 塊,即128*featNum_2
d = sqrt(sum((tmpFeat - SiftFeat_2).^2)) / normVal; % L2 distance,圖1第i個描述子與圖2所有描述子的距離向量
matchDis(i) = min(d);
[v, ind] = sort(d);
if v(1) < 0.4 % 最小距離小於0.4,則認爲構成一對匹配
matchInd(i) = ind(1);
ic = ic + 1;
validDis(ic, 1 : 3) = [v(1), v(2), v(1) / v(2)];
tmp = (SiftFeat_1(:, i) - SiftFeat_2(:, ind(1))).^2;
tmp2 = reshape(tmp(:), 8, 16);
gridDisVec(ic, 1 : 16) = sqrt(sum(tmp2)); % 第ic個匹配描述子的L2距離
end
end
figure; stem(matchDis); ylim([0, 1.2]); %繪製莖狀圖
figure; stem(matchDis(matchInd > 0)); ylim([0, 1.2]);
%% 實現spatial coding方法,進行匹配校驗準備
Map1 = [];
Map2 = [];
m= 1;
for i = 1 : featNum_1
if matchInd(i) > 0
Map1 = [Map1, paraFeat_1(1:2, i)];
Map2 = [Map2, paraFeat_2(1:2, matchInd(i))];
end
end
% xys = paraFeat_1(:, i);
% xys2 = paraFeat_2(:, matchInd(i));
r = 4;
GX1(ic, ic, r) = 0;
GY1(ic, ic, r) = 0;
GX2(ic, ic, r) = 0;
GY2(ic, ic, r) = 0;
for k = 1:r
%將其分解爲r個獨立的子區域,旋轉k個單位的座標集
theta = (k-1)*pi/(2*r);
G1(1:2, 1:ic, k) = [cos(theta), -sin(theta); sin(theta), cos(theta)]*Map1;
G2(1:2, 1:ic, k) = [cos(theta), -sin(theta); sin(theta), cos(theta)]*Map2;
%獲取空間編碼01矩陣
for i = 1:ic
for j = 1:ic
if G1(1, i, k) >= G1(1, j, k)
GX1(j, i, k) = 1;
end
if G1(2, i, k) >= G1(2, j, k)
GY1(i, j, k) = 1;
end
if G2(1, i, k) >= G2(1, j, k)
GX2(j, i, k) = 1;
end
if G2(2, i, k) >= G2(2, j, k)
GY2(i, j, k) = 1;
end
end
end
end
Vx = xor(GX1, GX2);
Vy = xor(GY1, GY2);
%% Show the local matching results on RGB image
[row, col, cn] = size(im_1);
[r2, c2, n2] = size(im_2);
imgBig = 255 * ones(max(row, r2), col + c2, 3);
imgBig(1 : row, 1 : col, :) = im_1;
imgBig(1 : r2, col + 1 : end, :) = im_2;
% np = 40;
% thr = linspace(0,2*pi,np) ;
% Xp = cos(thr);
% Yp = sin(thr);
paraFeat_2(1, :) = paraFeat_2(1, :) + col; %爲了讓兩幅圖畫面並排,使右側圖x座標右移col個單位
figure(3); imshow(uint8(imgBig)); axis on;
hold on;
matchCount = 0;
for i = 1 : featNum_1
if matchInd(i) > 0
matchCount = matchCount + 1;
xys = paraFeat_1(:, i);
xys2 = paraFeat_2(:, matchInd(i));
figure(3);
% hold on;
% plot(xys(1) + Xp * xys(3) * 6, xys(2) + Yp * xys(3) * 6, 'r'); %圖1匹配描述子紅圈
% plot(xys2(1) + Xp * xys2(3) * 6, xys2(2) + Yp * xys2(3) * 6, 'r'); %圖2匹配描述子紅圈
hold on; plot([xys(1), xys2(1)], [xys(2), xys2(2)], '-b', 'LineWidth', 0.8);
end
end
%% 幾何匹配校驗
Map2(1, :) = Map2(1, :) + col; %爲了讓兩幅圖畫面並排,使右側圖x座標右移col個單位
threshold = floor(ic*0.8);
for i = 1:ic
Sx = sum(sum(Vx, 2), 3); %矩陣各行元素求和,再對k個方向各行元素和求總和
[Cx, Ix] = max(Sx(:, :), [], 1); %求出第k個方向的列最大值
if Cx>threshold
Vx(Ix, :, :) = 0; %把最不匹配的描述子mask
Vx(:, Ix, :) = 0;
Vy(Ix, :, :) = 0; %把最不匹配的描述子mask
Vy(:, Ix, :) = 0;
hold on;plot([Map1(1, Ix), Map2(1, Ix)], [Map1(2, Ix), Map2(2, Ix)], '-r', 'LineWidth', 0.8); %不匹配的描述點對連線
end
Sy = sum(sum(Vy, 2), 3); %矩陣對各行元素求和
[Cy, Iy] = max(Sy(:, :), [], 1);
if Cy>threshold
Vx(Iy, :, :) = 0; %把最不匹配的描述子mask
Vx(:, Iy, :) = 0;
Vy(Iy, :, :) = 0; %把最不匹配的描述子mask
Vy(:, Iy, :) = 0;
hold on;plot([Map1(1, Iy), Map2(1, Iy)], [Map1(2, Iy), Map2(2, Iy)], '-r', 'LineWidth', 0.8); %不匹配的描述點對連線
end
end
figure(3);
title(sprintf('Total local matches : %d (%d-%d)', length(find(matchInd)), featNum_1 ,featNum_2));
hold off;
五、參考文獻
代碼及資料
Wengang Zhou, Yijuan Lu, Houqiang Li, Y. Song, and Qi Tian, “Spatial coding for large scale partial-duplicate web image search,” ACM International Conference on Multimedia (MM), pp.131-140, 2010.