计算机系统应用教程网站

网站首页 > 技术文章 正文

OpenCV SURF特征点检测和匹配 opencv特征提取方法

btikc 2024-09-30 13:13:33 技术文章 12 ℃ 0 评论

SURF算法为每个检测到的特征定义了位置和尺度,尺度值可用于定义围绕特征点的窗口大小,不论物体的尺度在窗口是什么样的,都将包含相同的视觉信息,这些信息用于表示特征点以使得他们与众不同。在特征匹配中,特征描述子通常是用于N维向量,在光照不变以及少许透视变形的情况下很理想。另外,优质的描述子可以通过简单的距离测量进行比较,比如欧氏距离。因此,他们在特征匹配算法中,用处是很大的。

在OpenCV中,使用SURF进行特征点描述主要是drawMatches方法和BruteForceMatcher类的运用。drawMatches用于绘制出相匹配的两个图像的关键点,它有如下两个版本的C++函数原型:

/** @brief Draws the found matches of keypoints from two images.

@param img1 First source image.
@param keypoints1 Keypoints from the first source image.
@param img2 Second source image.
@param keypoints2 Keypoints from the second source image.
@param matches1to2 Matches from the first image to the second one, which means that keypoints1[i]
has a corresponding point in keypoints2[matches[i]] .
@param outImg Output image. Its content depends on the flags value defining what is drawn in the
output image. See possible flags bit values below.
@param matchColor Color of matches (lines and connected keypoints). If matchColor==Scalar::all(-1)
, the color is generated randomly.
@param singlePointColor Color of single keypoints (circles), which means that keypoints do not
have the matches. If singlePointColor==Scalar::all(-1) , the color is generated randomly.
@param matchesMask Mask determining which matches are drawn. If the mask is empty, all matches are
drawn.
@param flags Flags setting drawing features. Possible flags bit values are defined by
DrawMatchesFlags.

This function draws matches of keypoints from two images in the output image. Match is a line
connecting two keypoints (circles). See cv::DrawMatchesFlags.
 */
CV_EXPORTS_W void drawMatches( InputArray img1, const std::vector<KeyPoint>& keypoints1,
                             InputArray img2, const std::vector<KeyPoint>& keypoints2,
                             const std::vector<DMatch>& matches1to2, InputOutputArray outImg,
                             const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
                             const std::vector<char>& matchesMask=std::vector<char>(), DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT );

/** @overload */
CV_EXPORTS_AS(drawMatchesKnn) void drawMatches( InputArray img1, const std::vector<KeyPoint>& keypoints1,
                             InputArray img2, const std::vector<KeyPoint>& keypoints2,
                             const std::vector<std::vector<DMatch> >& matches1to2, InputOutputArray outImg,
                             const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
                             const std::vector<std::vector<char> >& matchesMask=std::vector<std::vector<char> >(), DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT );
//! @} features2d_draw

除了第五个参数matches1to2和第九个参数matchesMask有细微的差别以外,两个版本的基本上相同。

参数1,const Mat&类型的img1,第一幅源图像。

参数2,const vector<KeyPoint>&类型的keypoints1,根据第一幅源图像得到的特征点,它是一个输出参数。

参数3,const Mat&类型的img2,第二幅源图像。

参数4,const vector<KeyPoint>&类型的keypoints2,根据第二幅源图像得到的特征点,它是一个输出参数。

参数5,matches1to2,第一幅图像到第二幅图像的匹配点,即表示每一个图1中的特征点都在图2中有一一对应的点、

参数6,Mat&类型的outImg,输出图像,其内容取决于第五个参数标识符falgs。

参数7,const Scalar&类型的matchColor,匹配的输出颜色,即线和关键点的颜色。它有默认值Scalar::all(-1),表示颜色是随机生成的。

参数8,const Scalar&类型的singlePointColor,单一特征点的颜色,它也有表示随机生成颜色的默认值Scalar::all(-1)。

参数8,matchesMask,确定哪些匹配是会绘制出来的掩膜,如果掩膜为空,表示所有匹配都进行绘制。

参数10,int类型的flags,特征绘制的标识符,有默认值DrawMatchesFlags::DEFAULT。可以在如下这个DrawMatchesFlags结构体中选取值:

enum
	{
		DEFAULT = 0, // Output image matrix will be created (Mat::create), i.e. existing memory ofoutput image may be reused.Two source images,matches, and single keypoints will be drawn.
		// For each keypoint, only the center pointwill be drawn (without a circlearound the keypoint with the keypoint size andorientation).
		DRAW_OVER_OUTIMG = 1, // Output image matrix will not be created (usingMat::create). Matches will be drawn on existing contentof output image.
		NOT_DRAW_SINGLE_POINTS = 2, // Single keypoints will not be drawn.
		DRAW_RICH_KEYPOINTS = 4 // For each keypoint, the circle around keypoint withkeypoint size and orientation will be drawn.
	};

参考一下 SURF特征匹配示例程序

int main()
{	
	Mat srcImage1 = imread("leuvenA.jpg");
	Mat srcImage2 = imread("leuvenB.jpg");

	imshow("原始测试图像", srcImage1);
	imshow("基准图像", srcImage2);
	waitKey(0);
	////////////////////////////灰度图转换
	Mat image1, image2;
	cvtColor(srcImage1, image1, COLOR_RGB2GRAY);
	cvtColor(srcImage2, image2, COLOR_RGB2GRAY);
	//////////////////////////////////////////////////////提取特征点 

	waitKey(0);

	//检测两幅图像中的特征点
	int minHessian = 2000;      //定义Hessian矩阵阈值
	Ptr<SURF> detector = SURF::create(minHessian);
	//SurfFeatureDetector detector(minHessian);       //定义Surf检测器
	vector<KeyPoint>keypoint1, keypoint2;           //定义两个KeyPoint类型矢量存储检测到的特征点
	detector->detect(srcImage1, keypoint1);
	detector->detect(srcImage2, keypoint2);

	//计算特征向量的描述子
	//SurfDescriptorExtractor descriptorExtractor;//OpenCV2 
	Ptr<SURF>descriptorExtractor = SURF::create();//OpenCV4
	Mat descriptors1, descriptors2;

	descriptorExtractor->compute(srcImage1, keypoint1, descriptors1);
	descriptorExtractor->compute(srcImage2, keypoint2, descriptors2);

	////使用BruteForceMatcher进行描述符匹配
	//BFMatcher matcher(NORM_L2);
	//vector<DMatch>matches;
	//matcher.match(descriptors1, descriptors2, matches);
	//使用BruteForce进行匹配
	Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce");
	std::vector< DMatch > matches;
	matcher->match(descriptors1, descriptors2, matches);

	//////绘制两个图像中的匹配特征点
	Mat matchImage;
	drawMatches(srcImage1, keypoint1, srcImage2, keypoint2, matches, matchImage);

	///////////////////////显示匹配的图像
	namedWindow("output", WINDOW_AUTOSIZE);
	imshow("output", matchImage);

	waitKey(0);
	return 0;
}

特征点检测和匹配效果展示:

特征点的检测和匹配效果图如下,

对这个示例程序做个说明,它利用了SURF特征的特征描述办法,其操作封装在类SurfFeatureDetector中。特征点检测和匹配分三步执行,

首先利用类内的detect函数可以检测出SURF特征的关键点,保存在vector容器中,然后再利用SurfDescriptorExtractor类进行特征向量的相关计算,将之前的vector变量变成向量矩阵形式保存在Mat中,最后强行匹配两幅图像的特征向量,利用了类BruteForceMatcher中的函数match。

程序的核心:

使用 DescriptorExtractor 接口来寻找关键点对应的特征向量;

使用 SurfDescriptorExtractor 以及它的函数 compute 来完成特定的计算;

使用 BruteForceMatcher 来匹配特征向量;

使用函数 drawMatches 来绘制检测到的匹配点。

关键点:

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

//计算特征向量的描述子(特征向量)

Ptr<SURF>descriptorExtractor = SURF::create();//OpenCV4
Mat descriptors1, descriptors2;
descriptorExtractor->compute(srcImage1, keypoint1, descriptors1);
descriptorExtractor->compute(srcImage2, keypoint2, descriptors2);

这里的结果为一个Mat矩阵,它的行数与特征点向量中元素个数是一致的。每行都是一个N维描述子的向量,比如SURF算法默认的描述子维度为64,该向量描绘了特征点周围的强度样式。两个特征点越相似,他们的特征向量也越靠近。这些描述子在图像匹配中尤其有用,如我们想匹配同一个场景中的两幅图像。首先,我们检测每幅图像中的特征,然后提取他们的描述子。第一幅图像中的每一个特征描述子向量都会与第二幅图中的描述子进行比较,得分最高的一对描述子,也就是两个向量的距离最近)将被视为那个特征的最佳匹配。该过程对于第一幅图像中的所有特征进行重复,这便是BruteForceMatcher中实行的最基本的策略。相关代码如下:

//使用BruteForceMatcher进行描述符匹配
BFMatcher matcher(NORM_L2);
vector<DMatch>matches;
matcher.match(descriptors1, descriptors2, matches);

BruteForceMatcher是由DescriptorMatcher派生出来的一个类,而DescriptorMatcher定义了不同的匹配策略的共同接口。调用match方法后,在其第三个参数输出一个cv::DMatch向量。于是我们定义一个std::vector<DMatch>类型的matches。调用match方法之后,我们便可以使用drawMatches方法对匹配到的点进行绘制,并最终显示出来。相关代码如下:

//绘制两个图像中的匹配特征点
Mat matchImage;
drawMatches(srcImage1, keypoint1, srcImage2, keypoint2, matches, matchImage);

重点部分梳理完毕。

SURF 技术应用很多,除了这里的图像配准之外,还可以用于图像中的特征元素检测定位和识别,图像拼接,这部分内容后面再补充。

注意:

1)使用SURF需要加入opencv-contrib模块 ,这部分内容需要自行编译,编译方法可以参考前面的文章

2)需要包含opencv2/xfeatures2d.hpp


如果本文对你有所帮助,还请帮忙点赞转发关注加收藏,谢谢。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表