什么是FLANN

FLANN库全称是Fast Library for Approximate Nearest Neighbors,它是目前最完整的(近似)最近邻开源库 ,SIFT/SURF是基于浮点数的匹配,ORB是二值匹配,速度更快。对于FLANN匹配算法,当使用ORB匹配算法的时候,需要重新构造HASH。对匹配之后的输出结果,根据距离进行排序,就会得到距离比较的匹配点。

FLANN匹配流程

  • 特征提取:寻找易于追踪和对比的特征。
  • 特征描述:对提取的特征用计算机的语言进行描述,使得其能够在其它图像中寻找到相似区域。
  • 特征匹配:根据特征描述,在其它图像中寻找所有相同的特征区域,以便进行需求的操作[如排列,整合等]。

API介绍

//匹配信息存储结构体DMatch
class CV_EXPORTS_W_SIMPLE DMatch
{
public:
    CV_WRAP DMatch();
    CV_WRAP DMatch(int _queryIdx, int _trainIdx, float _distance);
    CV_WRAP DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _distance);

    CV_PROP_RW int queryIdx; //!< query descriptor index
    CV_PROP_RW int trainIdx; //!< train descriptor index
    CV_PROP_RW int imgIdx;   //!< train image index

    CV_PROP_RW float distance;

    // less is better
    bool operator<(const DMatch &m) const;
};
/*******************************************************************
*				queryIdx:				查询点的索引
*				trainIdx:				被查询到的点的索引
*				imgIdx:					匹配图像下标
*			对于一副图像img1的描述子,在其他图像中找到与其最相似的,imgIdx就是找到的图像下标
*				distance:		    	两个描述子的距离,一般是欧式距离
*********************************************************************/
virtual void detectAndCompute( InputArray image, InputArray mask,CV_OUT std::vector<KeyPoint>& keypoints,OutputArray descriptors,bool useProvidedKeypoints=false );
//检查关键点,获取描述子
/*******************************************************************
*				image:  				输入图
*				mask:					掩膜
*				keypoints:				关键点
*				descriptors:			描述符
*				useProvidedKeypoints:	是否使用提供的关键点
*********************************************************************/
template<typename _Tp, typename ... A1> static inline
Ptr<_Tp> makePtr(const A1&... a1)
//构建智能指针对象
void match( InputArray queryDescriptors, InputArray trainDescriptors, CV_OUT std::vector<DMatch>& matches, InputArray mask=noArray() ) const;
//获取描述符的最佳匹配
/*******************************************************************
*				queryDescriptors:  		查询描述符集合
*				trainDescriptors:		训练描述符集合
*				matches:				匹配点集合
*				mask:					指定允许匹配的掩膜
*********************************************************************/
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 );
//绘制检测匹配点
/*******************************************************************
*				img1:					输入图1
*				keypoints1:			    输入图1的特征点
*				img2:					输入图2
*				keypoints2:				输入图2的特征点
*				matches1to2:			两图匹配的特征点
*				outImg:					输出图,具体有flag
*				matchColor:				匹配的颜色(特征点和连线) -1 随机
*				singlePointColor:		未配对的特征点颜色 -1 随机颜色
*								std::vector<char>	
*				matchesMask:			Mask决定哪些点将被画出
*											空,则画出所有匹配点
*				flags:					输出图样式,参见DrawMatchesFlags
*********************************************************************/
/** @overload */
void drawMatches( InputArray img1, const std::vector<KeyPoint>& keypoints1, InputArray img2, const std::vector<KeyPoint>& keypoints2,const std::vector<DMatch>& matches1to2, InputOutputArray outImg,const int matchesThickness, const Scalar& matchColor=Scalar::all(-1),const Scalar& singlePointColor=Scalar::all(-1), const std::vector<char>& matchesMask=std::vector<char>(),DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT );
//绘制检测匹配点
/*******************************************************************
*				img1:					输入图1
*				keypoints1:			    输入图1的特征点
*				img2:					输入图2
*				keypoints2:				输入图2的特征点
*				matches1to2:			两图匹配的特征点
*				outImg:					输出图,具体有flag
*				matchesThickness:		匹配线的厚度
*				matchColor:				匹配的颜色(特征点和连线) -1 随机
*				singlePointColor:		未配对的特征点颜色 -1 随机颜色
*				matchesMask:			Mask决定哪些点将被画出
*											空,则画出所有匹配点
*				flags:					输出图样式,参见DrawMatchesFlags	
*********************************************************************/
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 );
//绘制检测匹配点
/*******************************************************************
*				img1:					输入图1
*				keypoints1:			    输入图1的特征点
*				img2:					输入图2
*				keypoints2:				输入图2的特征点
*				matches1to2:			两图匹配的特征点
*				outImg:					输出图,具体有flag
*				matchColor:				匹配的颜色(特征点和连线) -1 随机
*				singlePointColor:		未配对的特征点颜色 -1 随机颜色
*							std::vector<std::vector<char>>		
*				matchesMask:			Mask决定哪些点将被画出
*											空,则画出所有匹配点
*				flags:					输出图样式,参见DrawMatchesFlags
*********************************************************************/
//DrawMatchesFlags结构体
enum struct DrawMatchesFlags
{
  DEFAULT = 0,					//所有特征点绘制
  DRAW_OVER_OUTIMG = 1,         //不创建新图方式
  NOT_DRAW_SINGLE_POINTS = 2,	//单个点不绘制
  DRAW_RICH_KEYPOINTS = 4 		//绘制带有方向和圆 描述特征点
};

综合代码

#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class FLANNMatch
{
public:
	FLANNMatch() :img_1(imread("mm.jpg")), img_2(imread("girl.jpg"))
	{
		maxDist = 0.0f;
	}
	void GetFeature()
	{
		Ptr<ORB> dector = ORB::create();
		dector->detectAndCompute(img_1, Mat(), kpt_1, descript_1);
		dector->detectAndCompute(img_2, Mat(), kpt_2, descript_2);
	}
	void GetMatches()
	{
		//FLANN
		Ptr<DescriptorMatcher> matcher = makePtr<FlannBasedMatcher>(makePtr<flann::LshIndexParams>(12, 20, 2));
		matcher->match(descript_1, descript_2, matches);
		for (unsigned int i = 0; i < matches.size(); i++)
		{
			maxDist = max(maxDist, matches[i].distance);
		}
		for (int i = 0; i < matches.size(); i++)
		{
			if (matches[i].distance < maxDist / 50.0)
			{
				goodmatches.push_back(matches[i]);
			}
		}
	}
	void DrawMatches()
	{
		Mat result;
		drawMatches(img_1, kpt_1, img_2, kpt_2, goodmatches, result);
		imshow("FLANN",result);
		waitKey(0);
	}

protected:
	Mat img_1;
	Mat img_2;
	
	//特征点
	vector<KeyPoint> kpt_1;
	vector<KeyPoint> kpt_2;

	//描述子
	Mat descript_1;
	Mat descript_2;

	float maxDist;
	vector<DMatch> matches;			//匹配信息
	vector<DMatch> goodmatches;		//好的匹配

};

int main() 
{
	unique_ptr<FLANNMatch> p(new FLANNMatch);
	p->GetFeature();
	p->GetMatches();
	p->DrawMatches();
	return 0;
}

OpenCV FLANN特征匹配_特征点