您的位置:首页 > 运维架构

opencv下SIFT使用

2015-03-12 10:52 295 查看
OPENCV下SIFT特征点提取与匹配的大致流程如下:

读取图片-》特征点检测(位置,角度,层)-》特征点描述的提取(16*8维的特征向量)-》匹配-》显示

其中,特征点提取主要有两个步骤,见上行黄子部分。下面做具体分析。

1、使用opencv内置的库读取两幅图片

2、生成一个SiftFeatureDetector的对象,这个对象顾名思义就是SIFT特征的探测器,用它来探测衣服图片中SIFT点的特征,存到一个KeyPoint类型的vector中。简而言之最重要的一点在于:

keypoint只是保存了opencv的sift库检测到的特征点的一些基本信息,但sift所提取出来的特征向量其实不是在这个里面,特征向量通过SiftDescriptorExtractor 提取,结果放在一个Mat的数据结构中。这个数据结构才真正保存了该特征点所对应的特征向量。具体见后文对SiftDescriptorExtractor 所生成的对象的详解。

就因为这点没有理解明白耽误了一上午的时间。哭死!

3、对图像所有KEYPOINT提取其特征向量:

得到keypoint只是达到了关键点的位置,方向等信息,并无该特征点的特征向量,要想提取得到特征向量就还要进行SiftDescriptorExtractor 的工作,建立了SiftDescriptorExtractor 对象后,通过该对象,对之前SIFT产生的特征点进行遍历,找到该特征点所对应的128维特征向量。通过这一步后,所有keypoint关键点的特征向量被保存到了一个MAT的数据结构中,作为特征。

4、对两幅图的特征向量进行匹配,得到匹配值。

opencv中keypoint数据结构分析

分析opencv中keypoint数据结构的相关信息,找到opencv的document(http://docs.opencv.org/java/org/opencv/features2d/KeyPoint.html)。可以看到KeyPoint这数据结构中有如下数据结构:

angle:角度,表示关键点的方向,通过Lowe大神的论文可以知道,为了保证方向不变形,SIFT算法通过对关键点周围邻域进行梯度运算,求得该点方向。-1为初值。

class_id:当要对图片进行分类时,我们可以用class_id对每个特征点进行区分,未设定时为-1,需要靠自己设定

octave:代表是从金字塔哪一层提取的得到的数据。

pt:关键点点的坐标

response:响应程度,代表该点强壮大小,一开始我也理解不了,看到两位stackoverflow大大的原话(http://stackoverflow.com/questions/10328298/what-does-size-and-response-exactly-represent-in-a-surf-keypointhttp://stackoverflow.com/questions/24699495/opencv-keypoints-response-greater-or-less?lq=1)——response代表着该关键点how
good,更确切的说,是该点角点的程度。瞬间明白。

size:该点直径的大小

注意一个问题:keypoint只是保存了opencv的sift库检测到的特征点的一些基本信息,也就上面所说的这些,但sift所提取出来的特征向量其实不是在这个里面,特征向量通过SiftDescriptorExtractor 提取,结果放在一个Mat的数据结构中。这个数据结构才真正保存了该特征点所对应的特征向量。具体见后文对SiftDescriptorExtractor 所生成的对象的详解。

opencv中SiftDescriptorExtractor所做的SIFT特征向量提取工作简单分析

SiftDescriptorExtractor对应于SIFT算法中特征向量提取的工作,通过他对关键点周围邻域内的像素分块进行梯度运算,得到128维的特征向量。具体有如下几个操作:

0、首先,我们假设在之前关键点提取的步骤中,我们对一个三角形提取关键点,检测到其中一个关键点的坐标为三角形的一个角(如下面用红圈圈出的),如下图





放大看,假设检测到该关键点的方向如下图:





1、将关键点周围的像素旋转到一个统一的方向,以保证方向不变性。如下图





2、将这些像素分成4X4的小块





对每个格子进行分析,将格子中的像素计算梯度,映射到8个方向上,对于每一个格子,可以得到一个8维的向量,对于一个关键点周围16个格子,则得到了16X8=128维的向量,这就是一个关键点特征向量。





使用举一个实际的例子分析:

用opencv对一个三角形进行特征点检测,得到如下结果:





提取特征向量,得到如下结果:





这幅图的每一行就是一个128维的特征向量,维度用0-255表示。黑一些就是小,白就是大。

粗略可以看出,这些特征点排布较为相似,因为都是角

再来一个:









引自:http://www.cnblogs.com/cj695/p/4041478.html

附:使用OPENCV下SIFT库做图像匹配的例程

// FeatureDetector.cpp : Defines the entry point for the console application.

#include<opencv2/nonfree/features2d.hpp> //使用SiftFeatureDetector需要加上此头文件
#include<opencv2\opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
//Load Image
Mat c_src1 = imread("image1.jpg");
Mat c_src2 = imread("image2.jpg");
Mat src1 = imread("image1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat src2 = imread("image2.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if (!src1.data || !src2.data)
{
std::cout << " --(!) Error reading images " << std::endl; return -1;
}

//sift feature detect
SiftFeatureDetector detector;
vector<KeyPoint> kp1, kp2;

detector.detect(src1, kp1);
detector.detect(src2, kp2);
SiftDescriptorExtractor extractor;
Mat des1, des2;//descriptor
extractor.compute(src1, kp1, des1);
extractor.compute(src2, kp2, des2);
Mat res1, res2;
int drawmode = DrawMatchesFlags::DRAW_RICH_KEYPOINTS;
drawKeypoints(c_src1, kp1, res1, Scalar::all(-1), drawmode);//在内存中画出特征点
drawKeypoints(c_src2, kp2, res2, Scalar::all(-1), drawmode);
cout << "size of description of Img1: " << kp1.size() << endl;
cout << "size of description of Img2: " << kp2.size() << endl;

BFMatcher matcher(NORM_L2);
vector<DMatch> matches;
matcher.match(des1, des2, matches);
Mat img_match;
drawMatches(src1, kp1, src2, kp2, matches, img_match);//,Scalar::all(-1),Scalar::all(-1),vector<char>(),drawmode);
cout << "number of matched points: " << matches.size() << endl;
imshow("matches", img_match);
cvWaitKey();
cvDestroyAllWindows();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: