SIFT

  1. 简介

SIFT(scale invariant feature transform)——尺度不变特征转换,用来检测和描述局部特征,运用范围包括object recognition(目标检测), robotic mapping and navigation(机器人地图感知与导航), image stitching(图像拼接), 3D modeling(3D建模), gesture recognition(手势识别), video tracking(视频追踪), individual identification of wildlife(野生物个体识别) and match moving(动作匹配)

     2.  特点   

           (1)Sift特征是图像的局部特征,对平移、旋转、尺度缩放、亮度变化、遮挡和噪声等具有良好的不变性,对视觉变化、仿射变换也保持一定程度的稳定性。

           (2)独特性好,信息量丰富,适用于在海量特征数据库中进行快速、准确的匹配。

           (3)多量性,即使少数的几个物体也可以产生大量Sift特征向量。

           (4)速度相对较快,经优化的Sift匹配算法甚至可以达到实时的要求。

           (5)可扩展性强,可以很方便的与其他形式的特征向量进行联合。

     3.  算法

           3.1. 构造高斯差分空间图像。

  Sift特征点的检测时在DOG(difference of gausssian)图像上进行的,DOG图像是将相邻尺度空间图像相减得到的。且金字塔的每一层都要构造一个DOG空间图像。默认参数是金字塔4层,即4个octave,每一个octave中有5张不同尺度的图片,不同octave的图片尺寸大小不同,所以每一层中就会得到4幅DOG图像。

高斯金字塔的第1层第1副原图像是将原图像放大2倍且sigma(sigma=1.6)模糊,第2幅图像是k*sigma(k等于根号2)模糊,第3幅是k*k*sigma模糊,后面类推…

     高斯金字塔第2层第1幅图是选择金字塔上一层(这里是第1层)中尺度空间参数为k*k*sigma的那幅图(实际上是2倍的尺度空间)进行降采样(尺寸大小为原来的1/4倍)得到,如果k不等于根号2,那么取原图的2*sigma降采样得到。第2层第2幅图是在本层第一幅图尺度模糊系数增加k倍模糊后的图像,后面类似…

  示意图如下所示:

  SIFT_第1张图片

3.2、寻找极大极小值点。

  将每个像素点与其所在的那幅图像邻域的8个像素,它所在的向量尺度空间上下2幅图对应位置邻域各9个点,总共26个点进行像素值比较,如果该点是最大或者最小点,则改点就暂时列为特征点。

  其邻图如下:

  SIFT_第2张图片

 

  3.3、精确定位极值点

  子像素级极值点:

  由于上面找到的近似极值点落在像素点的位置上,实际上我们在像素点附近如果用空间曲面去拟合的话,很多情况下极值点都不是恰好在像素点上,而是在附近。所以sift算法提出的作者用泰勒展开找到了亚像素级的特征点。这种点更稳定,更具有代表性。

  消除对比度低的特征点:

  对求出亮度比较低的那些点直接过滤点,程序中的阈值为0.03.

  消除边界上的点:

  处理方法类似harrs角点,把平坦区域和直线边界上的点去掉,即对于是边界上的点但又不是直角上的点,sift算法是不把这些点作为特征点的。

 

  3.4、选取特征点主方向

  在特征点附近选取一个区域,该区域大小与图图像的尺度有关,尺度越大,区域越大。并对该区域统计36个bin的方向直方图,将直方图中最大bin的那个方向作为该点的主方向,另外大于最大bin80%的方向也可以同时作为主方向。这样的话,由于1个特征点有可能有多个主方向,所以一个特征点有可能有多个128维的描述子。如下图所示:

  SIFT_第3张图片

 

     3.5、 构造特征点描述算子。

     以特征点为中心,取领域内16*16大小的区域,并把这个区域分成4*4个大小为4*4的小区域,每个小区域内计算加权梯度直方图,该权值分为2部分,其一是该点的梯度大小,其二是改点离特征点的距离(二维高斯的关系),每个小区域直方图分为8个bin,所以一个特征点的维数=4*4*8=128维。示意图如下(该图取的领域为8*8个点,因此描述子向量的维数为32维):

  SIFT_第4张图片

 4.  在opencv中的使用

      

// opencv_empty_proj.cpp : 定义控制台应用程序的入口点。
//


#include <opencv2/opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
#include<opencv2/nonfree/nonfree.hpp>
#include<opencv2/legacy/legacy.hpp>
#include<vector>
using namespace std;
using namespace cv;
int main()
{
	const char* imagename = "SIFT.bmp";

	//从文件中读入图像
	Mat img = imread(imagename);
	Mat img2=imread("SIFT1.bmp");

	//如果读入图像失败
	if(img.empty())
	{
		fprintf(stderr, "Can not load image %s\n", imagename);
		return -1;
	}
	if(img2.empty())
	{
		fprintf(stderr, "Can not load image %s\n", imagename);
		return -1;
	}
	//显示图像
	imshow("image before", img);
	imshow("image2 before",img2);


	//sift特征检测
	SiftFeatureDetector  siftdtc;
	vector<KeyPoint>kp1,kp2;
	
	siftdtc.detect(img,kp1);
	Mat outimg1;
	drawKeypoints(img,kp1,outimg1);
	imshow("image1 keypoints",outimg1);
	KeyPoint kp;

	vector<KeyPoint>::iterator itvc;
	for(itvc=kp1.begin();itvc!=kp1.end();itvc++)
	{
		cout<<"angle:"<<itvc->angle<<"\t"<<itvc->class_id<<"\t"<<itvc->octave<<"\t"<<itvc->pt<<"\t"<<itvc->response<<endl;
	}

	siftdtc.detect(img2,kp2);
	Mat outimg2;
	drawKeypoints(img2,kp2,outimg2);
	imshow("image2 keypoints",outimg2);


	SiftDescriptorExtractor extractor;
	Mat descriptor1,descriptor2;
	BruteForceMatcher<L2<float>> matcher;
	vector<DMatch> matches;
	Mat img_matches;
	extractor.compute(img,kp1,descriptor1);
	extractor.compute(img2,kp2,descriptor2);


	imshow("desc",descriptor1);
	cout<<endl<<descriptor1<<endl;
	matcher.match(descriptor1,descriptor2,matches);

	drawMatches(img,kp1,img2,kp2,matches,img_matches);
	imshow("matches",img_matches);

	//此函数等待按键,按键盘任意键就返回
	waitKey();
	return 0;
}

  

 

你可能感兴趣的:(if)