1. SURF特征提取
在OpenCV中,使用SURF进行特征点描述主要是使用drawMatches 方法和BruteForceMatcher类。
1.1 drawMatches()函数
drawMatches用于绘制出相匹配的两个图像的关键点,该函数有两个函数原型。
void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
const Mat& img2,
const vector<KeyPoint>& keypoints2,
const vector<DMatch>& matches1to2,
Mat& outImg,
const Scalar& singlePointColor=Scalar::all(-1),
int flags=DrawMatchesFlags::DEFAULT );
void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
const Mat& img2, const vector<KeyPoint>& keypoints2,
Mat& outImg,
const Scalar& matchColor=Scalar::all(-1),
const Scalar& singlePointColor=Scalar::all(-1),
const vector<vector<char> >& matchesMask=vector<vector<char> >(),
int flags=DrawMatchesFlags::DEFAULT );
第一个参数:第一幅源图像;
第二个参数:第一幅图像的特征点,为输出参数;
第三个参数:第二幅源图像;
第四个参数:第二幅图像的特征点,为输出参数;
第五个参数:matches1to2,第一幅图像到第二幅图像的匹配点;
第六个参数:输出图像;
第七个参数:线和关键点的颜色,默认Scalar::all(-1)表随机颜色;
第八个参数:单一特征点的颜色,默认值表随机颜色;
第九个参数:确定哪些匹配是要绘制出来的掩码,默认值表所有的都要绘制;
第十个参数:特征绘制的标识符。
1.2 BruteForceMatches类
template<class Distance>
class CV_EXPORTS BruteForceMatcher : public BFMatcher
{
public:
BruteForceMatcher( Distance d = Distance() ) : BFMatcher(Distance::normType, false) {(void)d;}
virtual ~BruteForceMatcher() {}
};
1.3 程序实例
#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;
}
2.使用FLANN进行特征点匹配
FLANN——快速最近邻逼近搜索函数库,Fast Libray for Approximate Nearest Neighbors。
2.1 FlannBasedMatcher类
class CV_EXPORTS_W FlannBasedMatcher : public DescriptorMatcher
{
//
}
2.2 找到最佳匹配:DescriptorMatcher::match方法
2.3 程序实例
#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( int argc, char** argv )
{
//【0】改变console字体颜色
system("color 4F");
//【1】载入源图片
Mat img_1 = imread("1.jpg", 1 );
Mat img_2 = imread( "2.jpg", 1 );
if( !img_1.data || !img_2.data ) { printf("读取图片image0错误~! \n"); return false; }
//【2】利用SURF检测器检测的关键点
int minHessian = 300;
SURF detector( minHessian );
std::vector<KeyPoint> keypoints_1, keypoints_2;
detector.detect( img_1, keypoints_1 );
detector.detect( img_2, keypoints_2 );
//【3】计算描述符(特征向量)
SURF extractor;
Mat descriptors_1, descriptors_2;
extractor.compute( img_1, keypoints_1, descriptors_1 );
extractor.compute( img_2, keypoints_2, descriptors_2 );
//【4】采用FLANN算法匹配描述符向量
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );
double max_dist = 0; double min_dist = 100;
//【5】快速计算关键点之间的最大和最小距离
for( int i = 0; i < descriptors_1.rows; i++ )
{
double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
//输出距离信息
printf("> 最大距离(Max dist) : %f \n", max_dist );
printf("> 最小距离(Min dist) : %f \n", min_dist );
//【6】存下符合条件的匹配结果(即其距离小于2* min_dist的),使用radiusMatch同样可行
std::vector< DMatch > good_matches;
for( int i = 0; i < descriptors_1.rows; i++ )
{
if( matches[i].distance < 2*min_dist )
{ good_matches.push_back( matches[i]); }
}
//【7】绘制出符合条件的匹配点
Mat img_matches;
drawMatches( img_1, keypoints_1, img_2, keypoints_2,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//【8】输出相关匹配点信息
for( int i = 0; i < good_matches.size(); i++ )
{ printf( ">符合条件的匹配点 [%d] 特征点1: %d -- 特征点2: %d \n", i, good_matches[i].queryIdx, good_matches[i].trainIdx ); }
//【9】显示效果图
imshow( "匹配效果图", img_matches );
//按任意键退出程序
waitKey(0);
return 0;
}