KeyPoint类
class KeyPoint
{
Point2f pt; //坐标
float size; //特征点领域直径
float angle;//特征点的方向,值为(0,360),负值表示不使用
float response;
int octave; //特征点所在的图像金字塔的组
int class_id; //用于聚类的id
}
DMatch类
struct CV_EXPORTS_W_SIMPLE DMatch
{
//默认构造函数,FLT_MAX是无穷大
CV_WRAP DMatch() : queryIdx(-1), trainIdx(-1), imgIdx(-1), distance(FLT_MAX) {}
//DMatch构造函数
CV_WRAP DMatch( int _queryIdx, int _trainIdx, float _distance ) : queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(-1), distance(_distance) {}
//DMatch构造函数
CV_WRAP DMatch( int _queryIdx, int _trainIdx, int _imgIdx, float _distance ) : queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(_imgIdx),distance(_distance) {}
//queryIdx为query描述子的索引,match函数中前面的那个描述子
CV_PROP_RW int queryIdx;
//trainIdx为train描述子的索引,match函数中后面的那个描述子
CV_PROP_RW int trainIdx;
//imgIdx为进行匹配图像的索引
//例如已知一幅图像的sift描述子,与其他十幅图像的描述子进行匹配,找最相似的图像,则imgIdx此时就有用了。
CV_PROP_RW int imgIdx;
//distance为两个描述子之间的距离
CV_PROP_RW float distance;
//DMatch比较运算符重载,比较的是DMatch中的distance,小于为true,否则为false
bool operator<( const DMatch &m ) const
{
return distance < m.distance;
}
};
ORB 特征点 FLANN BruteForceMatcher匹配
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat img1 = imread("1.png");
Mat img2 = imread("2.png");
if(img1.empty()||img2.empty()){
cout<<"could not load image .."<<endl;
return -1;
}
namedWindow("DMatch");
vector<KeyPoint> keyPoint1,keyPoint2;
Mat descriptor1,descriptor2;
Ptr<ORB> orb = ORB::create(500);
orb->detectAndCompute(img1,Mat(),keyPoint1,descriptor1);
orb->detectAndCompute(img2,Mat(),keyPoint2,descriptor2);
vector<DMatch> match;
//暴力匹配
BFMatcher bfMatcher(NORM_HAMMING);
//快速最近邻逼近搜索函数库
//FlannBasedMatcher fbMatcher(NORM_HAMMING);
Mat outImg;
bfMatcher.match(descriptor1,descriptor2,match,Mat());
double dist_min = 1000;
double dist_max = 0;
for(size_t t = 0;t<match.size();t++){
double dist = match[t].distance;
if(dist<dist_min) dist_min = dist;
if(dist>dist_max) dist_max = dist;
}
vector<DMatch> goodMatch;
for(size_t t = 0;t<match.size();t++){
double dist = match[t].distance;
if(dist <= max(2*dist_min,30.0))
goodMatch.push_back(match[t]);
}
drawMatches(img1,keyPoint1,img2,keyPoint2,goodMatch,outImg);
imshow("DMatch",outImg);
waitKey(0);
return 0;
}
运行结果:
Good!OK!
另一种定义方法:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
//-- 读取图像
Mat img_1 = imread("1.png", CV_LOAD_IMAGE_COLOR);
Mat img_2 = imread("2.png", CV_LOAD_IMAGE_COLOR);
//-- 初始化
std::vector<KeyPoint> keypoints_1, keypoints_2;
Mat descriptors_1, descriptors_2;
Ptr<FeatureDetector> detector = ORB::create();
Ptr<DescriptorExtractor> descriptor = ORB::create();
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
//-- 第一步:检测 Oriented FAST 角点位置
detector->detect(img_1, keypoints_1);
detector->detect(img_2, keypoints_2);
//-- 第二步:根据角点位置计算 BRIEF 描述子
descriptor->compute(img_1, keypoints_1, descriptors_1);
descriptor->compute(img_2, keypoints_2, descriptors_2);
Mat outimg1;
drawKeypoints(img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
imshow("ORB特征点", outimg1);
//-- 第三步:对两幅图像中的BRIEF描述子进行匹配,使用 Hamming 距离
vector<DMatch> matches;
//BFMatcher matcher ( NORM_HAMMING );
matcher->match(descriptors_1, descriptors_2, matches);
//-- 第四步:匹配点对筛选
double min_dist = 10000, max_dist = 0;
//找出所有匹配之间的最小距离和最大距离, 即是最相似的和最不相似的两组点之间的距离
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;
}
// 仅供娱乐的写法
min_dist = min_element(matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;})->distance;
max_dist = max_element(matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;})->distance;
printf("-- Max dist : %f \n", max_dist);
printf("-- Min dist : %f \n", min_dist);
//当描述子之间的距离大于两倍的最小距离时,即认为匹配有误.但有时候最小距离会非常小,设置一个经验值30作为下限.
std::vector< DMatch > good_matches;
for (int i = 0; i < descriptors_1.rows; i++)
{
if (matches[i].distance <= max(2 * min_dist, 30.0))
{
good_matches.push_back(matches[i]);
}
}
//-- 第五步:绘制匹配结果
Mat img_match;
Mat img_goodmatch;
drawMatches(img_1, keypoints_1, img_2, keypoints_2, matches, img_match);
drawMatches(img_1, keypoints_1, img_2, keypoints_2, good_matches, img_goodmatch);
imshow("所有匹配点对", img_match);
imshow("优化后匹配点对", img_goodmatch);
waitKey(0);
return 0;
}