特征描述子
即图像中每个像素位置的描述,通过此描述去匹配另一张图像是否含有相同特征。
暴力匹配:Brute-Force
图像匹配本质上是特征匹配。因为我们总可以将图像表示成多个特征向量的组成,因此如果两
幅图片具有相同的特征向量越多,则可以认为两幅图片的相似程度越高。而特征向量的相似程度通常是用它们之间的欧氏距离来衡量,欧式距离越小,则可以认为越相似。
代码:
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include<iostream>
#include<math.h>
#include <string>
#include<fstream>
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
int main() {
Mat src1, src2;
src1 = imread("C:/Users/Administrator/Desktop/pic/04.jpg");
src2 = imread("C:/Users/Administrator/Desktop/pic/03.jpg");
imshow("src1", src1);
imshow("src2", src2);
int minHessian = 400;
Ptr<SURF> detector = SURF::create(minHessian);
vector<KeyPoint> keypoints1;
vector<KeyPoint> keypoints2;
Mat descriptor1, descriptor2;
detector->detectAndCompute(src1,Mat(), keypoints1, descriptor1);
detector->detectAndCompute(src2,Mat(), keypoints2, descriptor2);
cout << "keypoint1.size=" << keypoints1.size() << endl;
cout << "keypoint2.size=" << keypoints2.size() << endl;
cout << "descriptor1 depth" << descriptor1.depth()<<",type=" <<descriptor1.type()<< endl;
cout << "descriptor2 depth" << descriptor2.depth() << ",type=" << descriptor2.type() << endl;
BFMatcher matcher(NORM_L2); //Brute - Force 匹配,参数表示匹配的方式,默认NORM_L2(欧几里得) ,NORM_L1(绝对值的和)
vector<DMatch>matches;// 保存匹配的结果
matcher.match(descriptor1, descriptor2, matches); //在descriptor_2中暴力匹配descriptor_1中含有的特征描述子匹配
cout << "matches.size=" << matches.size() << endl;
Mat dst;
drawMatches(src1, keypoints1, src2, keypoints2, matches, dst);
imshow("dst", dst);
waitKey(0);
}
结果:
FLANN特征匹配
算法速度特别快
特征匹配记录下目标图像与待匹配图像的特征点(KeyPoint),并根据特征点集合构造特征量(descriptor),对这个特征量进行比较、筛选,最终得到一个匹配点的映射集合。我们也可以根据这个集合的大小来衡量两幅图片的匹配程度。
代码:
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include<iostream>
#include<math.h>
#include <string>
#include<fstream>
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
int main() {
Mat src1, src2;
src1 = imread("C:/Users/Administrator/Desktop/pic/test3.jpg");
src2 = imread("C:/Users/Administrator/Desktop/pic/test4.jpg");
imshow("src1", src1);
imshow("src2", src2);
int minHessian = 300;
Ptr<SURF> detector = SURF::create(minHessian);// 也可以用 SIFT 特征
vector<KeyPoint> keypoints1; // 保存特征点
vector<KeyPoint> keypoints2;
Mat descriptor1, descriptor2;// 特征描述子
detector->detectAndCompute(src1, Mat(), keypoints1, descriptor1);
detector->detectAndCompute(src2, Mat(), keypoints2, descriptor2);
cout << "keypoint1.size=" << keypoints1.size() << endl;
cout << "keypoint2.size=" << keypoints2.size() << endl;
cout << "descriptor1 depth" << descriptor1.depth() << ",type=" << descriptor1.type() << endl;
cout << "descriptor2 depth" << descriptor2.depth() << ",type=" << descriptor2.type() << endl;
FlannBasedMatcher matcher; //Flann匹配
vector<DMatch>matches;// 保存匹配的结果
matcher.match(descriptor1, descriptor2, matches); //在descriptor_2中匹配descriptor_1中含有的特征描述子匹配
cout << "matches.size=" << matches.size() << endl;
//找到好的匹配点
double minDist = 1000;
double maxDist = 0;
for (int i = 0; i < descriptor1.rows; i++) {
cout << "matches[" << i << "].queryIdx" << matches[i].queryIdx << ","<<endl;
cout << "matches[" << i << "].trainIdx" << matches[i].trainIdx << ","<<endl;
cout << "matches[" << i << "].distanIdx" << matches[i].distance<< ","<<endl;
double dist = matches[i].distance;
if (dist > maxDist) {
maxDist = dist;
}
if (dist < minDist) {
minDist = dist;
}
}
cout << "maxdistance=" << maxDist << endl;
cout << "mindistance=" << minDist << endl;
vector<DMatch>goodMatches;
for (int i = 0; i < descriptor1.rows; i++) {
double dist = matches[i].distance;
if (dist < max(3 * minDist, 0.02)) {
goodMatches.push_back(matches[i]);
}
}
Mat dst;
drawMatches(src1, keypoints1, src2, keypoints2, goodMatches, dst, Scalar::all(-1),
Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
imshow("