SIFT特征提取匹配
步骤
① 使用SiftFeatureDetector的detect方法检测特征存入一个向量里(可以使用drawKeypoints在图中标识出来)
② 使用SiftDescriptorExtractor的compute方法提取特征描述符(特征向量),特征描述符是一个矩阵
③ 使用匹配器matcher对描述符进行匹配
④ 匹配结果保存由DMatch的组成的向量里设置距离阈值, 使得匹配的向量距离小于阈值才能进入最终的结果
⑤用DrawMatch绘制显示匹配结果
函数原型
代码片段
使用匹配器进行匹配
原理
暴力匹配器很简单, 首先在第一幅图像中选取一个关键点然后依次与第二幅图像的每个关键点进行(描述符)距离测试, 最后返回距离最近的关键点
函数原型1- - -BFMatcher
- normType: 用于指定要使用的距离测试类型, 默认值NORM_L2, L1和L2较适用SIFT和SUFT算法
- crossCheck: 是否交叉检测, 默认值false(不使用)。如果设置为true, 匹配条件就会更加严格, 只有到A中的第i个特征点与B中的第j个特征点距离最近, 并且B 中的第j个特征点到A中的第i个特征点也是最近(A中没有其他点到j的距离更近)时才会返回最佳匹配(i, j), 也就是这两个特征点要互相匹配才行
函数原型2–match
函数原型3- - -drawMatches
- img1: 输入的第一幅图像
- keypoints1: 根据第一幅图像得到的特征点
- img2: 输入的第二幅图像
- keypoints2: 根据第二幅图像得到的特征点
- matches1to2: 第一幅图像到第二幅图像的匹配点, 即表示每一个图1中的特征点都能在图2中有一一对应的点
- outImg: 输出图像, 包含匹配结果, 与flags参数有关
- matchColor: 匹配的输出颜色, 即匹配到的线和关键点的颜色, 默认值Scalar::all(-1)
- singlePointColor: 单一特征点的颜色, 默认值Scalar::all(-1)
- matchesMask: 确定哪些匹配是要绘制出来的掩码, 为空则所有匹配都绘制
- flags: 特征绘制的标识符, 默认值DrawMatchesFlags::DEFAULT, 可以在下面选:
应用实例
代码1- - -SIFT_BFMATCH的第一种方式
#include "opencv2/opencv.hpp"
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <vector>
#include<iostream>
using namespace std;
using namespace cv;
void main()
{
Mat srcImg1 = imread("11.jpg");
Mat srcImg2 = imread("22.jpg");
//定义SIFT特征检测类对象
SiftFeatureDetector siftDetector1;
SiftFeatureDetector siftDetector2;
//定义KeyPoint变量
vector<KeyPoint>keyPoints1;
vector<KeyPoint>keyPoints2;
//特征点检测
siftDetector1.detect(srcImg1, keyPoints1);
siftDetector2.detect(srcImg2, keyPoints2);
//绘制特征点(关键点)
Mat feature_pic1, feature_pic2;
drawKeypoints(srcImg1, keyPoints1, feature_pic1, Scalar::all(-1));
drawKeypoints(srcImg2, keyPoints2, feature_pic2, Scalar::all(-1));
//drawKeypoints(srcImg1, keyPoints1, feature_pic1, Scalar(0, 255, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//drawKeypoints(srcImg2, keyPoints2, feature_pic2, Scalar(0, 255, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//显示原图
imshow("src1", srcImg1);
imshow("src2", srcImg2);
//显示结果
imshow("feature1", feature_pic1);
imshow("feature2", feature_pic2);
//计算特征点描述符 / 特征向量提取
SiftDescriptorExtractor descriptor;
Mat description1;
descriptor.compute(srcImg1, keyPoints1, description1);
Mat description2;
descriptor.compute(srcImg2, keyPoints2, description2);
cout<<description1.cols<<endl;
cout<<description1.rows<<endl;
//进行BFMatch暴力匹配
BruteForceMatcher<L2<float>>matcher; //实例化暴力匹配器
vector<DMatch>matches; //定义匹配结果变量
matcher.match(description1, description2, matches); //实现描述符之间的匹配
//计算向量距离的最大值与最小值
double max_dist=0, min_dist=100;
for(int i=0; i<description1.rows; i++)
{
if(matches.at(i).distance > max_dist)
max_dist = matches[i].distance;
if(matches.at(i).distance < min_dist)
min_dist = matches[i].distance;
}
cout<<"min_distance="<<min_dist<<endl;
cout<<"max_distance="<<max_dist<<endl;
//匹配结果删选
vector<DMatch>good_matches;
for(int i=0; i<matches.size(); i++)
{
if(matches[i].distance < 2*min_dist)
good_matches.push_back(matches[i]);
}
Mat result;
drawMatches(srcImg1, keyPoints1, srcImg2, keyPoints2, good_matches, result, Scalar(0, 255, 0), Scalar::all(-1));
imshow("Match_Result", result);
waitKey(0);
}
代码2- - -sift_BFMatch的第二种方式
#include "opencv2/opencv.hpp"
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <vector>
#include<iostream>
using namespace std;
using namespace cv;
void main()
{
Mat srcImg1 = imread("00.jpg");
Mat srcImg2 = imread("01.jpg");
//定义SIFT特征检测类对象
SiftFeatureDetector siftDetector1;
SiftFeatureDetector siftDetector2;
//定义KeyPoint变量
vector<KeyPoint>keyPoints1;
vector<KeyPoint>keyPoints2;
//特征点检测
siftDetector1.detect(srcImg1, keyPoints1);
siftDetector2.detect(srcImg2, keyPoints2);
//绘制特征点(关键点)
Mat feature_pic1, feature_pic2;
drawKeypoints(srcImg1, keyPoints1, feature_pic1, Scalar::all(-1));
drawKeypoints(srcImg2, keyPoints2, feature_pic2, Scalar::all(-1));
//drawKeypoints(srcImg1, keyPoints1, feature_pic1, Scalar(0, 255, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//drawKeypoints(srcImg2, keyPoints2, feature_pic2, Scalar(0, 255, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//显示原图
imshow("src1", srcImg1);
imshow("src2", srcImg2);
//显示结果
imshow("feature1", feature_pic1);
imshow("feature2", feature_pic2);
//计算特征点描述符 / 特征向量提取
SiftDescriptorExtractor descriptor;
Mat description1;
descriptor.compute(srcImg1, keyPoints1, description1);
Mat description2;
descriptor.compute(srcImg2, keyPoints2, description2);
cout<<description1.cols<<endl;
cout<<description1.rows<<endl;
//进行BFMatch暴力匹配
BruteForceMatcher<L2<float>>matcher; //实例化暴力匹配器
vector<DMatch>matches; //定义匹配结果变量
matcher.match(description1, description2, matches); //实现描述符之间的匹配
//匹配结果删选
std::nth_element(matches.begin(), matches.begin()+29, matches.end()); //提取出前30个最佳匹配结果
matches.erase(matches.begin()+30, matches.end()); //剔除掉其余的匹配结果
Mat result;
//drawMatches(srcImg1, keyPoints1, srcImg2, keyPoints2, matches, result, Scalar::all(-1), Scalar::all(-1));
drawMatches(srcImg1, keyPoints1, srcImg2, keyPoints2, matches, result, Scalar(0, 255, 0), Scalar::all(-1));
imshow("Match_Result", result);
waitKey(0);
}