什么是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;
}