sift是目前常用的local feature的描述子。sift特徵匹配算法可以處理兩幅圖像之間發生一些平移、旋轉、仿射等匹配問題。因爲早前自己要做一個圖像拼接的問題,所以用到了sift。寫這篇blog,是因爲自己準備向CV進軍,開始着手寫blog來積累知識,這也是我第一篇blog,雖然這篇blog很簡陋,純屬向sift致敬,但也方便一些初學者使用吧。以後也會不定期對自己的一些在CV的見解進行發表,希望能通過這個和大家相互討論。如果您想對其原理有個透徹的理解,可以參考下面這篇blog,博主寫的非常詳盡 —— [ sift算法詳解 ]
代碼分析
首先,你可以從David Lowe的個人網站http://www.cs.ubc.ca/~lowe/keypoints/” target = “-blank”>[website]找到代碼的Version4,download後可以得到有4個m函數,主要看match.m,我對其進行了中文註解:
% num = match(image1, image2)
%
% This function reads two images, finds their SIFT features, and
% displays lines connecting the matched keypoints. A match is accepted
% only if its distance is less than distRatio times the distance to the
% second closest match.
% It returns the number of matches displayed.
%
% Example: match('scene.pgm','book.pgm');
% 上面是英文註解,大概意思就是這個函數是找出兩幅圖能匹配的特徵點的個數
% 你可以在該目錄下輸入:match('scene.pgm','book.pgm');
% 便可以得到該文件夾下的兩個圖像匹配點有多少對。
function num = match(image1, image2)
% Find SIFT keypoints for each image
% 下面兩條語句就是找兩個圖像的sift特徵點,其中對於image1而言
% im1爲灰度圖像,des1爲128維向量,loc1是位置信息
[im1, des1, loc1] = sift(image1);
[im2, des2, loc2] = sift(image2);
% 這個值非常重要,在這裏你可以簡單理解爲它是匹配的一個閾值
% 或者這樣說,distRatio值越大,能匹配的點越多,當然錯匹配點也越多
% 你可以試一下把distRatio改爲1時看會怎樣
distRatio = 0.6;
% For each descriptor in the first image, select its match to second image.
% 每一層循環就是把image1的每個特徵點的128維向量與image2所有向量做一個內積,
% 對所求得到的數求反cos值並且升序排序後,當前兩個值之間的大小差距在由distRatio確定的範圍內
% 則image1的這個特徵點在image2中有對應的匹配點,match(i)賦值爲1
% 因爲sort會保留下標自然也就找到這個匹配點的座標
des2t = des2'; % Precompute matrix transpose
for i = 1 : size(des1,1)
dotprods = des1(i,:) * des2t; % Computes vector of dot products
[vals,indx] = sort(acos(dotprods)); % Take inverse cosine and sort results
% Check if nearest neighbor has angle less than distRatio times 2nd.
if (vals(1) < distRatio * vals(2))
match(i) = indx(1);
else
match(i) = 0;
end
end
% Create a new image showing the two images side by side.
% appendimages就是把兩張圖像在一個figure中一塊顯示出來,沒什麼好解釋
im3 = appendimages(im1,im2);
% Show a figure with lines joining the accepted matches.
figure('Position', [100 100 size(im3,2) size(im3,1)]);
colormap('gray');
imagesc(im3);
hold on;
cols1 = size(im1,2);
% 以下語句就是在匹配的兩點之間畫條線
for i = 1: size(des1,1)
if (match(i) > 0)
line([loc1(i,2) loc2(match(i),2)+cols1], ...
[loc1(i,1) loc2(match(i),1)], 'Color', 'c');
end
end
hold off;
num = sum(match > 0);
fprintf('Found %d matches.\n', num);
你可以在command window中輸入: match(‘scene.pgm’,’book.pgm’);
便可以得到下圖:
sift.m因爲主要的求解方式被C混編了,所以看不到,所以只給出該函數返回的參數:
% image:灰度圖像
% descriptors:對特徵點進行描述的128維向量
% locs:是一個4維向量組,前兩維爲特徵點的座標,第三維是尺度,第四維爲方向,詳細可以看showkeys.m
% showkeys(image, locs)
%
% This function displays an image with SIFT keypoints overlayed.
% Input parameters:
% image: the file name for the image (grayscale)
% locs: matrix in which each row gives a keypoint location (row,
% column, scale, orientation)
% 該函數是對提取出來的sift特徵點在圖像上進行一個顯示
% 你可以在command window中先輸入[image,descritors,locs] = sift('image's path');
% showkeys(image,locs);
% 如果你的圖像是彩色的,則可以再進行一次讀入
% img = imread('image's path');
% showkeys(image,locs);
function showkeys(image, locs)
disp('Drawing SIFT keypoints ...');
% Draw image with keypoints
% 下面這是對出來的figure進行一些參數輸入,這個不重要
figure('Position', [50 50 size(image,2) size(image,1)]);
colormap('gray');
imagesc(image);
hold on;
imsize = size(image);
% 畫出每一個座標,還記得前面說的locs是四維向量,前兩個是橫縱座標,
% 第三個是尺度,第四個是方向,ok,那麼就可以畫出來了喲。
for i = 1: size(locs,1)
% Draw an arrow, each line transformed according to keypoint parameters.
% 這裏的Transform函數在後面定義,知道爲什麼一個點要畫三次麼,
% 因爲它要畫一個箭頭,即------>這樣是需要畫3條線
TransformLine(imsize, locs(i,:), 0.0, 0.0, 1.0, 0.0);
TransformLine(imsize, locs(i,:), 0.85, 0.1, 1.0, 0.0);
TransformLine(imsize, locs(i,:), 0.85, -0.1, 1.0, 0.0);
end
hold off;
% ------ Subroutine: TransformLine -------
% Draw the given line in the image, but first translate, rotate, and
% scale according to the keypoint parameters.
%
% Parameters:
% Arrays:
% imsize = [rows columns] of image
% keypoint = [subpixel_row subpixel_column scale orientation]
%
% Scalars:
% x1, y1; begining of vector
% x2, y2; ending of vector
% 給出的
function TransformLine(imsize, keypoint, x1, y1, x2, y2)
% The scaling of the unit length arrow is set to approximately the radius
% of the region used to compute the keypoint descriptor.
% 長度放大6倍
len = 6* keypoint(3);
% Rotate the keypoints by 'ori' = keypoint(4)
s = sin(keypoint(4));
c = cos(keypoint(4));
% Apply transform
%畫一條線需要起點和終點,兩個點所以搞出四個座標
r1 = keypoint(1) - len * (c * y1 + s * x1);
c1 = keypoint(2) + len * (- s * y1 + c * x1);
r2 = keypoint(1) - len * (c * y2 + s * x2);
c2 = keypoint(2) + len * (- s * y2 + c * x2);
line([c1 c2], [r1 r2], 'Color', 'c');
給出一張彩色的showkeys的效果:
blending.m就是把兩張圖片在同一個figure中展示,這個就不需要過多解釋了。
第一篇博文,水是水了點,慢慢會改善。希望學習CV的博友多加好友,共同學習。