1. 程式人生 > >影象演算法之三:特徵提取運算元之SIFT

影象演算法之三:特徵提取運算元之SIFT

SIFT(Scale-invariant feature transform)是一種檢測區域性特徵的演算法,該演算法通過求一幅圖中的特徵點(interest points,or corner points)及其有關scale 和 orientation 的描述子得到特徵並進行影象特徵點匹配,獲得了良好效果,詳細解析如下:

1、演算法描述
SIFT特徵不只具有尺度不變性,即使改變旋轉角度,影象亮度或拍攝視角,仍然能夠得到好的檢測效果。整個演算法分為以下幾個部分:
(1)構造尺度空間:DoG尺度空間
(2)檢測DoG尺度空間極值點
(3)去除不好的特徵點
(4)給特徵點賦值一個128維的方向引數。每個關鍵點都包含三個資訊:位置、尺度和方向。
(5)關鍵點描述子的生成:
首先將座標軸旋轉為關鍵點的方向,以確保旋轉不變性。以關鍵點為中心取8×8的視窗。
(6)最後進行特徵匹配。當兩幅影象的SIFT特徵向量(128維)生成後,採用關鍵點特徵向量的歐式聚類來作為相似性判定度量。
取影象1中的某個關鍵點,並找出其與影象2中歐式距離最近的前兩個關鍵點,在這兩個關鍵點中,如果最近的距離除以次近的距離少於某個比例閾值,則接受這一對匹配點。降低這個比例閾值,SIFT匹配點數目會減少,但更加穩定。

2、演算法實現:
(一) SIFT的Matlab程式碼實現:

% [image, descriptors, locs] = sift(imageFile)
%
% This function reads an image and returns its SIFT keypoints.
%   Input parameters:
%     imageFile: the file name for the image.
%
%   Returned:
%     image: the image array in double format
%     descriptors: a K-by
-128 matrix, where each row gives an invariant % descriptor for one of the K keypoints. The descriptor is a vector % of 128 values normalized to unit length. % locs: K-by-4 matrix, in which each row has the 4 values for a % keypoint location (row, column, scale, orientation). The % orientation is
in the range [-PI, PI] radians. % % Credits: Thanks for initial version of this program to D. Alvaro and % J.J. Guerrero, Universidad de Zaragoza (modified by D. Lowe) function [image, descriptors, locs] = sift(imageFile) % Load image image = imread(imageFile); % If you have the Image Processing Toolbox, you can uncomment the following % lines to allow input of color images, which will be converted to grayscale. % if isrgb(image) % image = rgb2gray(image); % end [rows, cols] = size(image); % Convert into PGM imagefile, readable by "keypoints" executable f = fopen('tmp.pgm', 'w'); if f == -1 error('Could not create file tmp.pgm.'); end fprintf(f, 'P5\n%d\n%d\n255\n', cols, rows); fwrite(f, image', 'uint8'); fclose(f); % Call keypoints executable if isunix command = '!./sift '; else command = '!siftWin32 '; end command = [command ' <tmp.pgm >tmp.key']; eval(command); % Open tmp.key and check its header g = fopen('tmp.key', 'r'); if g == -1 error('Could not open file tmp.key.'); end [header, count] = fscanf(g, '%d %d', [1 2]); if count ~= 2 error('Invalid keypoint file beginning.'); end num = header(1); len = header(2); if len ~= 128 error('Keypoint descriptor length invalid (should be 128).'); end % Creates the two output matrices (use known size for efficiency) locs = double(zeros(num, 4)); descriptors = double(zeros(num, 128)); % Parse tmp.key for i = 1:num [vector, count] = fscanf(g, '%f %f %f %f', [1 4]); %row col scale ori if count ~= 4 error('Invalid keypoint file format'); end locs(i, :) = vector(1, :); [descrip, count] = fscanf(g, '%d', [1 len]); if (count ~= 128) error('Invalid keypoint file value.'); end % Normalize each input vector to unit length descrip = descrip / sqrt(sum(descrip.^2)); descriptors(i, :) = descrip(1, :); end fclose(g);

使用方法:
1.尋找影象中的sift特徵:

[image,descrips,locs] = sift('scene.pgm');
showkeys(image,locs);

這裡寫圖片描述
scene.pgm
這裡寫圖片描述
book.pgm

2、對兩幅圖中的sift特徵進行匹配
這裡寫圖片描述

match(‘scene.pgm’,’book.pgm’);
由於scene和book兩幅圖中有相同的一本書,但是方向和尺度都不同,從匹配結果可以看出去sift特徵匹配檢測效果非常好滴!

(二)SIFT的Python實現:

import cv2
import numpy as np
import pdb
pdb.set_trace()#turn on the pdb prompt

#read image
img = cv2.imread('E:\OpenCV\Picture\sky.jpg',cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('origin',img);

#SIFT
detector = cv2.SIFT() #呼叫SIFT特徵描述子
keypoints = detector.detect(gray,None)#檢測興趣點
img = cv2.drawKeypoints(gray,keypoints)#畫出興趣點
#img = cv2.drawKeypoints(gray,keypoints,flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('test',img);
cv2.waitKey(0)
cv2.destroyAllWindows()

測試:

實驗結果:
這裡寫圖片描述

(三)SIFT的OpenCV實現

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main(void)
{
       cout << "當前使用的OpenCV版本:" << CV_VERSION << endl;
       Mat image = imread("scene.pgm");
       Mat image2 = imread("book.pgm");
       if (image.empty())
       {
              fprintf(stderr, "Cannot load image %s \n", "scene.pgm");
              return -1;
       }
       if (image2.empty())
       {
              fprintf(stderr, "Cannot load image %s \n", "book.pgm");
              return -1;
       }
       //顯示影象
       imshow("image before", image);
       waitKey(10);
       imshow("image2 before", image2);
       waitKey(10);
       //sift特徵點檢測
       SiftFeatureDetector siftdtc;
       vector<KeyPoint> kp1, kp2;
       siftdtc.detect(image, kp1);
       Mat outimg1;
       drawKeypoints(image, kp1, outimg1);
       imshow("image1 keypoints", outimg1);
       siftdtc.detect(image2, kp2);
       Mat outimg2;
       drawKeypoints(image2, kp2, outimg2);
       imshow("image2 keypoints", outimg2);
       //生成描述子
       SiftDescriptorExtractor ext;
       Mat descp1, descp2;
       BruteForceMatcher<L2<float>> matcher;
       vector<DMatch> matches;
       Mat img_matches;
       ext.compute(image, kp1, descp1);
       ext.compute(image2, kp2, descp2);
       imshow("desc", descp1);
       waitKey(10);
       //cout << endl << descp1 << endl;
       matcher.match(descp1, descp2, matches);

       drawMatches(image, kp1, image2, kp2, matches, img_matches);
       imshow("matches", img_matches);
       waitKey(10);
       //namedWindow("My Image");
       //imshow("My Image",image);
       //waitKey(0);
       //Mat result,image2,image3;
       //result = image;
       //image2 = result;
       //result.copyTo(image3);
       //flip(image, result, 1);//正數水平翻轉,0表示垂直翻轉,負數表示既有水平也有垂直翻轉
       //namedWindow("Output window");
       //imshow("Output window", result);
       //namedWindow("1");
       //imshow("1", image2);
       //namedWindow("2");
       //imshow("2", image3);
       waitKey(0);
       return 0;
}

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述