图像处理之SURF特征提取例子

257 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天

1 概述

我们利用SurfDescriptorExtractor类进行特征向量的相关计算。程序利用了SURF特征的特征描述办法,其操作封装在类 SurfFeatureDetector 中,利用类内的detect函数可以检测出SURF特征的关键点,保存在vector 容器中。

第二步利用 SurfDescriptorExtractor 类进行特征向量的相关计算。将之前的 vector 变量变成向量矩阵形式保存在Mat中。最后强行匹配两幅图像的特征向量,利用了类BruteForceMatcher中的函数match。

程序的核心思想如下。

  • 使用 DescriptorExtractor 接口来寻找关键点对应的特征向量。
  • 使用 SurfDescriptorExtractor以及它的函数compute来完成特定的计算。
  • 使用BruteForceMatcher来匹配特征向量。
  • 使用函数drawMatches来绘制检测到的匹配点。

关键点讲解:

OpenCV引入了一个通用类,用于提取不同的特征点描述子,计算如下。

2 计算描述子(特征向量)

SurfDescriptorExtractorextractor; Matdescriptors1,descriptors2;

extractor.compute(srcImage1, keyPoint1, descriptors1 );

extractor.compute(srcImage2, keyPoints2, descriptors2);

这里的结果为一个Mat矩阵,它的行数与特征点向量中元素个数是一致的。每行都是一个N维描述子的向量,比如SURF算法默认的描述子维度为64,该向量描绘了特征点周围的强度样式。

两个特征点越相似,它们的特征向量也越靠近。这些描述子在图像匹配中尤其有用。例如,我们想匹配同一个场景中的两幅图像。首先,检测每幅图像中的特征,然后提取它们的描述子。第一幅图像中的每一个特征描述子向量都会与第二幅图中的描述子进行比较,得分最高的一对描述子(也就是两个向量的距离最近)将被视为那个特征的最佳匹配。该过程对于第一幅图像中的所有特征进行重复,这便是BruteForceMatcher中实行的最基本的策略。相关代码如下。

3 使用BruteForce进行匹配

实例化一个匹配器

BruteForceMatcher<L2>matcher; std::vector matches;

匹配两幅图中的描述子(descriptors)

matcher.match(descriptors1, descriptors2,matches);

BruteForceMatcher 是由 DescriptorMatcher 派生出来的一个类,而 DescriptorMatcher 定义了不同的匹配策略的共同接口。调用match方法后,在其第三个参数输出一个cv::DMatch向量。

于是我们定义一个std::vector<DMatch>类 型的matches。

调用match方法之后,便可以使用drawMatches方法对匹配到的点进行绘制,并最终显示出来。

4 绘制从两个图像中匹配出的关键点MatimgMatches;

进行绘制

drawMatches(srcImage1, keyPoint1, srcImage2, keyPoints2,matches, imgMatches);

5 显示效果图

imshow("匹配图", imgMatches);

核心部分讲解完毕,下面我们一起来看看详细示例程序。

源码

//--------------------------------------【程序说明】-------------------------------------------
//		程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序90
//		程序描述:SURF特征描述
//		开发测试所用操作系统: Windows 7 64bit
//		开发测试所用IDE版本:Visual Studio 2010
//		开发测试所用OpenCV版本:	2.4.9
//		2014年06月 Created by @浅墨_毛星云
//		2014年11月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------



//---------------------------------【头文件、命名空间包含部分】----------------------------
//		描述:包含程序所使用的头文件和命名空间
//--------------------------------------------------------------------------------------
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/nonfree/nonfree.hpp>
#include<opencv2/legacy/legacy.hpp>
#include <iostream>
using namespace cv;
using namespace std;


//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//--------------------------------------------------------------------------------------------
int main(  )
{
	//【0】改变console字体颜色
	system("color 1F"); 

	//【1】载入素材图
	Mat srcImage1 = imread("1.jpg",1);
	Mat srcImage2 = imread("2.jpg",1);
	if( !srcImage1.data || !srcImage2.data )
	{ printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }  

	//【2】使用SURF算子检测关键点
	int minHessian = 700;//SURF算法中的hessian阈值
	SurfFeatureDetector detector( minHessian );//定义一个SurfFeatureDetector(SURF) 特征检测类对象  
	std::vector<KeyPoint> keyPoint1, keyPoints2;//vector模板类,存放任意类型的动态数组

	//【3】调用detect函数检测出SURF特征关键点,保存在vector容器中
	detector.detect( srcImage1, keyPoint1 );
	detector.detect( srcImage2, keyPoints2 );

	//【4】计算描述符(特征向量)
	SurfDescriptorExtractor extractor;
	Mat descriptors1, descriptors2;
	extractor.compute( srcImage1, keyPoint1, descriptors1 );
	extractor.compute( srcImage2, keyPoints2, descriptors2 );

	//【5】使用BruteForce进行匹配
	// 实例化一个匹配器
	BruteForceMatcher< L2<float> > matcher;
	std::vector< DMatch > matches;
	//匹配两幅图中的描述子(descriptors)
	matcher.match( descriptors1, descriptors2, matches );

	//【6】绘制从两个图像中匹配出的关键点
	Mat imgMatches;
	drawMatches( srcImage1, keyPoint1, srcImage2, keyPoints2, matches, imgMatches );//进行绘制

	//【7】显示效果图
	imshow("匹配图", imgMatches );

	waitKey(0);
	return 0;
}

原图

1.jpg

2.jpg

效果图

捕获.PNG

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天