第二节 特征描述符匹配器及匹配点绘制
OpenCV中关键点描述符的匹配器具有带有公共接口的包装器,可以轻松地在解决同一问题的不同算法之间进行切换。 本节专门介绍在多维空间中以向量表示的匹配描述符。 实现矢量描述符匹配器的所有对象都继承DescriptorMatcher接口以及相应的关键点和匹配点绘制接口。
1、cv::drawKeypoints
绘制关键点
void cv::drawKeypoints(InputArray image,const std::vector< KeyPoint > & keypoints,InputOutputArray outImage,const Scalar & color = Scalar::all(-1),DrawMatchesFlags flags = DrawMatchesFlags::DEFAULT)
参数如下:
参数名称 | 参数描述 |
---|---|
image | 原图像 |
keypoints | 原图像的关键点 |
outImage | 输出图像。 其内容取决于标志值,该标志值定义在输出图像中绘制的内容。 请参阅下面的可能的标志位值。 |
color | 关键点的颜色。 |
flags | 标志设置图形功能。 可能的标志位值由DrawMatchesFlags定义。 请参阅上述drawMatches中的详细信息。 |
2、cv::drawMatches
从两个图像绘制找到的关键点匹配项。
void cv::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 | 第一个源图像 |
keypoints1 | 第一个源图像关键点 |
img2 | 第二个源图像 |
keypoints2 | 第二个源图像关键点 |
matches1to2 | 从第一张图片匹配到第二张图片,这意味着keypoints1 [i]在keypoints2 [matches [i]]中具有一个对应点。 |
outImg | 输出图像。 其内容取决于标志值,该标志值定义在输出图像中绘制的内容。 请参阅下面的可能的标志位值。 |
matchColor | 匹配项的颜色(线和连接的关键点)。 如果matchColor == Scalar :: all(-1),则颜色是随机生成的。 |
singlePointColor | 单个关键点(圆圈)的颜色,这意味着关键点没有匹配项。 singlePoint Color == Scalar :: all(-1)的颜色是随机生成的。 |
matchesMask | 遮罩确定绘制哪些匹配项。 如果蒙版为空,则绘制所有匹配项。 |
flags | 标志设置图形功能。 可能的标志位值由DrawMatchesFlags定义。 |
3、cv::BFMatcher
蛮力(Brute-force)描述符匹配器。对于第一组中的每个描述符,此匹配器通过尝试每个描述符来找到第二组中最接近的描述符。 此描述符匹配器支持屏蔽描述符集的允许匹配。
类BFMatcher继承DescriptorMatcher接口,并实现了相应的方法,创建BFMatcher对象通过静态的create方法来实现。
static Ptr cv::BFMatcher::create (int normType=NORM_L2,bool crossCheck = false)
参数如下:
参数名称 | 参数描述 |
---|---|
normType | NORM_L1,NORM_L2,NORM_HAMMING,NORM_HAMMING2中的一个。 对于SIFT和SURF描述符,L1和L2norms是更好的选择,当WTA_K == 3或4时,NORM_HAMMING应该与ORB,BRISK和Brief一起使用,NORM_HAMMING2应该与ORB一起使用(请参阅ORB :: ORB构造函数说明)。 |
crossCheck | 如果为false,则为每个查询描述符找到k个最近的邻居时,这将是默认的BFMatcher行为。 如果crossCheck == true,则k = 1的knnMatch()方法将仅返回对(i,j),这样对于第i个查询描述符,匹配器集合中的第j个描述符是最近的,反之亦然,即 BFMatcher将仅返回一致对。 当有足够的匹配项时,这种技术通常会以最少的异常值产生最佳结果。 这是D. Lowe在SIFT论文中使用的比率测试的替代方法。 |
DescriptorMatcher接口有几个核心的接口:
-
void cv::DescriptorMatcher::match(InputArray queryDescriptors,InputArray trainDescriptors,std::vector< DMatch > & matches,InputArray mask = noArray())
-
void cv::DescriptorMatcher::radiusMatch(InputArray queryDescriptors,InputArray trainDescriptors,std::vector< std::vector< DMatch > > & matches,float maxDistance,InputArray mask = noArray(),bool compactResult = false)
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
// 读取图像
cv::Mat src1 = cv::imread("images/plane.jpg");
if(src1.empty()){
cerr << "cannot read image 1.\n";
return EXIT_FAILURE;
}
cv::Mat src2 = cv::imread("images/plane_part.jpg");
if(src2.empty()){
cerr << "cannot read image 2.\n";
return EXIT_FAILURE;
}
// 转换成灰度图像
cv::Mat gray1,gray2;
cv::cvtColor(src1,gray1,cv::COLOR_BGR2GRAY);
cv::cvtColor(src2,gray2,cv::COLOR_BGR2GRAY);
// 创建SIFT特征提取器
cv::Ptr<cv::SIFT> sift = cv::SIFT::create(256,3,0.09,220,2.5);
// 特征点检测
// 检测特征点
vector<cv::KeyPoint> keypoints1,keypoints2;
cv::Mat descriptor1,descriptor2;
sift->detectAndCompute(gray1,cv::Mat(),keypoints1,descriptor1);
sift->detectAndCompute(gray2,cv::Mat(),keypoints2,descriptor2);
// 创建特征点匹配器
cv::Ptr<cv::BFMatcher> matcher = cv::BFMatcher::create();
// 执行特征点匹配
vector<cv::DMatch> dmatch;
matcher->match(descriptor1,descriptor2,dmatch);
// 绘制特征点和匹配特征结果
cv::Mat matchResult;
cv::drawMatches(src1,keypoints1,src2,keypoints2,dmatch,matchResult);
cv::imshow("src1",src1);
cv::imshow("src2",src2);
cv::imshow("match result",matchResult);
cv::waitKey();
return 0;
}
4、cv::FlannBasedMatcher
基于Flann的描述符匹配器。该匹配器在火车描述符集合上训练cv :: flann :: Index,并调用其最近的搜索方法以找到最佳匹配。 因此,匹配大型火车集合时,此匹配器可能比蛮力匹配器更快。 FlannBasedMatcher不支持屏蔽描述符集的允许匹配,因为flann :: Index不支持此功能。
类FlannBasedMatcher继承DescriptorMatcher接口,并实现了相应的方法,创建BFMatcher对象通过静态的create方法来实现。
static Ptr cv::FlannBasedMatcher::create()
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
// 读取图像
cv::Mat src1 = cv::imread("images/plane.jpg");
if(src1.empty()){
cerr << "cannot read image 1.\n";
return EXIT_FAILURE;
}
cv::Mat src2 = cv::imread("images/plane_part.jpg");
if(src2.empty()){
cerr << "cannot read image 2.\n";
return EXIT_FAILURE;
}
// 转换成灰度图像
cv::Mat gray1,gray2;
cv::cvtColor(src1,gray1,cv::COLOR_BGR2GRAY);
cv::cvtColor(src2,gray2,cv::COLOR_BGR2GRAY);
// 创建SIFT特征提取器
cv::Ptr<cv::SIFT> sift = cv::SIFT::create(256,3,0.09,220,2.5);
// 特征点检测
// 检测特征点
vector<cv::KeyPoint> keypoints1,keypoints2;
cv::Mat descriptor1,descriptor2;
sift->detectAndCompute(gray1,cv::Mat(),keypoints1,descriptor1);
sift->detectAndCompute(gray2,cv::Mat(),keypoints2,descriptor2);
// 创建特征点匹配器
cv::Ptr<cv::FlannBasedMatcher> matcher = cv::FlannBasedMatcher::create();
// 执行特征点匹配
vector<cv::DMatch> dmatch;
matcher->match(descriptor1,descriptor2,dmatch);
// 绘制特征点和匹配特征结果
cv::Mat matchResult;
cv::drawMatches(src1,keypoints1,src2,keypoints2,dmatch,matchResult);
cv::imshow("src1",src1);
cv::imshow("src2",src2);
cv::imshow("match result",matchResult);
cv::waitKey();
return 0;
}