關(guān)于特征檢測(cè)和匹配的具體原理會(huì)在后續(xù)的文章中具體講解,本文主要介紹Opencv實(shí)現(xiàn)的簡(jiǎn)單過程:
第一步:定義特征檢測(cè)器(SIFT,SURF,ORB等)。
第二步:對(duì)圖像中特征點(diǎn)進(jìn)行檢測(cè),并將特征點(diǎn)存儲(chǔ)在Keypoints中。
第三步:提取特征點(diǎn)的描述信息。
第四步:定義特征匹配器(特征匹配的方法主要有兩種分別為暴力匹配BFmatch和FlannBased)。
第五步:過濾掉較差的匹配點(diǎn)位(一般根據(jù)臨近兩點(diǎn)的距離進(jìn)行過濾)
主要是根據(jù)DMatch中的distance進(jìn)行過濾,對(duì)于distance可以抽象理解為匹配的分值,distance越小說明檢測(cè)點(diǎn)的相似度越高,效果越好。
第六步:對(duì)匹配的特征點(diǎn)顯示。
代碼1(未濾波,只限制篩選點(diǎn)數(shù)為20)
#include <iostream>
#include <opencv2/opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <opencv2/xfeatures2d.hpp>
using namespace cv; //包含cv命名空間
using namespace std;
using namespace xfeatures2d;
int main() {
system("color 2E");
//載入圖片
Mat src1 = imread("E:\\喬大花進(jìn)度\\11-18\\sift特征檢測(cè)和匹配\\3.jpg",1);
Mat src2 = imread("E:\\喬大花進(jìn)度\\11-18\\sift特征檢測(cè)和匹配\\4.jpg", 1);
//顯示原圖
imshow("原圖1",src1);
imshow("原圖2", src2);
//定義變量
vector<KeyPoint> keypoints1, keypoints2;//定義檢測(cè)的特征點(diǎn)存儲(chǔ)容器
Mat descriptors1,descriptors2;//定義特征點(diǎn)描述信息為Mat類型
Mat result_img;//匹配結(jié)果圖片
//創(chuàng)建sift特征檢測(cè)器實(shí)例
//將SIFT可以換位SURF、ORB
Ptr<SIFT>detector = SIFT::create();
//提取特征點(diǎn)
detector->detect(src1,keypoints1,noArray());
detector->detect(src2, keypoints2, Mat());
//獲取特征點(diǎn)的描述信息=>特征向量
detector->compute(src1,keypoints1,descriptors1);
detector->compute(src2, keypoints2, descriptors2);
//定義匹配器的實(shí)例化=>方法為暴力匹配法
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE);//create中的參數(shù)可以填string FlannBased等匹配方法
//第二種實(shí)例化方法
//BFMatcher matcher;
//進(jìn)行暴力匹配
vector<DMatch> matches;
//第一個(gè)參數(shù)為queryDescription為目標(biāo),第二個(gè)參數(shù)為trainDescription模板
matcher->match(descriptors1,descriptors2,matches);
//限制特征點(diǎn)匹配數(shù)量=》只匹配前20個(gè)較好的特征點(diǎn)
int num = 20;
nth_element(matches.begin(), matches.begin()+num,matches.end());
//vector去除20以后的元素
matches.erase(matches.begin()+num,matches.end());
//輸出關(guān)鍵點(diǎn)和匹配結(jié)果
//其中右側(cè)圖為trainDescription模板,左側(cè)圖為queryDescription目標(biāo)
//左圖中的點(diǎn)與右圖中進(jìn)行匹配對(duì)應(yīng)
drawMatches(src1,keypoints1,src2,keypoints2, matches,result_img);
drawKeypoints(src1,keypoints1,src1);
drawKeypoints(src2,keypoints2,src2);
imshow("匹配結(jié)果",result_img);
imshow("特征點(diǎn)1",src1);
imshow("特征點(diǎn)2",src2);
waitKey(0);
system("pause");
return 0;
}
運(yùn)行結(jié)果為:
代碼2(通過距離進(jìn)行濾波)
#include <iostream>
#include <opencv2/opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <opencv2/xfeatures2d.hpp>
using namespace cv; //包含cv命名空間
using namespace std;
using namespace xfeatures2d;
int main() {
system("color 2E");
//載入圖片
Mat src1 = imread("E:\\喬大花進(jìn)度\\11-18\\sift特征檢測(cè)和匹配\\3.jpg",1);
Mat src2 = imread("E:\\喬大花進(jìn)度\\11-18\\sift特征檢測(cè)和匹配\\4.jpg", 1);
//顯示原圖
imshow("原圖1",src1);
imshow("原圖2", src2);
//定義變量
vector<KeyPoint> keypoints1, keypoints2;//定義檢測(cè)的特征點(diǎn)存儲(chǔ)容器
Mat descriptors1,descriptors2;//定義特征點(diǎn)描述信息為Mat類型
Mat result_img;//匹配結(jié)果圖片
//創(chuàng)建sift特征檢測(cè)器實(shí)例
//將SIFT可以換位SURF、ORB
Ptr<SIFT>detector = SIFT::create();
//提取特征點(diǎn)
detector->detect(src1,keypoints1,noArray());
detector->detect(src2, keypoints2, Mat());
//獲取特征點(diǎn)的描述信息=>特征向量
detector->compute(src1,keypoints1,descriptors1);
detector->compute(src2, keypoints2, descriptors2);
//定義匹配器的實(shí)例化=>方法為暴力匹配法
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE);//create中的參數(shù)可以填string FlannBased等匹配方法
//第二種實(shí)例化方法
//BFMatcher matcher;
//進(jìn)行暴力匹配
vector<DMatch> matches;
//第一個(gè)參數(shù)為queryDescription為目標(biāo),第二個(gè)參數(shù)為trainDescription模板
matcher->match(descriptors1,descriptors2,matches);
//限制特征點(diǎn)匹配數(shù)量=》只匹配前20個(gè)較好的特征點(diǎn)
int num = 20;
nth_element(matches.begin(), matches.begin()+num,matches.end());
//vector去除20以后的元素
matches.erase(matches.begin()+num,matches.end());
double Max_distance = matches[1].distance;
double Min_distance = matches[1].distance;
vector<DMatch> goodfeatrues;
//根據(jù)特征點(diǎn)的距離去篩選
for (int i = 0; i < matches.size(); i++)
{
double dist = matches[i].distance;
if (dist>Max_distance)
{
Max_distance = dist;
}
if (dist<Min_distance)
{
Min_distance = dist;
}
}
cout << "匹配點(diǎn)的最大距離:" << Max_distance << endl;
cout << "匹配點(diǎn)的最小距離:" << Min_distance << endl;
//M為距離閾值,M越大點(diǎn)數(shù)越多
double M = 1.3;
for (int i = 0; i < matches.size(); i++)
{
double dist = matches[i].distance;
if (dist<M*Min_distance) {
goodfeatrues.push_back(matches[i]);
}
}
cout << "最終選取特征點(diǎn)的數(shù)量為:" << matches.size() << endl;
//輸出關(guān)鍵點(diǎn)和匹配結(jié)果
//其中右側(cè)圖為trainDescription模板,左側(cè)圖為queryDescription目標(biāo)
//左圖中的點(diǎn)與右圖中進(jìn)行匹配對(duì)應(yīng)
drawMatches(src1,keypoints1,src2,keypoints2, goodfeatrues,result_img);
drawKeypoints(src1,keypoints1,src1);
drawKeypoints(src2,keypoints2,src2);
imshow("匹配結(jié)果",result_img);
imshow("特征點(diǎn)1",src1);
imshow("特征點(diǎn)2",src2);
waitKey(0);
system("pause");
return 0;
}
運(yùn)行結(jié)果為:
?代碼3(通過knnMatch匹配,可以通過對(duì)distance設(shè)置閾值進(jìn)行濾波,效果最好)
#include <iostream>
#include <opencv2/opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <opencv2/xfeatures2d.hpp>
using namespace cv; //包含cv命名空間
using namespace std;
using namespace xfeatures2d;
int main() {
system("color 2E");
//載入圖片
Mat src1 = imread("E:\\喬大花進(jìn)度\\11-18\\sift特征檢測(cè)和匹配\\3.jpg",1);
Mat src2 = imread("E:\\喬大花進(jìn)度\\11-18\\sift特征檢測(cè)和匹配\\4.jpg", 1);
//顯示原圖
imshow("原圖1",src1);
imshow("原圖2", src2);
//定義變量
vector<KeyPoint> keypoints1, keypoints2;//定義檢測(cè)的特征點(diǎn)存儲(chǔ)容器
Mat descriptors1,descriptors2;//定義特征點(diǎn)描述信息為Mat類型
Mat result_img;//匹配結(jié)果圖片
//創(chuàng)建sift特征檢測(cè)器實(shí)例
//將SIFT可以換位SURF、ORB
Ptr<SIFT>detector = SIFT::create();
//提取特征點(diǎn)
detector->detect(src1,keypoints1,noArray());
detector->detect(src2, keypoints2, Mat());
//獲取特征點(diǎn)的描述信息=>特征向量
detector->compute(src1,keypoints1,descriptors1);
detector->compute(src2, keypoints2, descriptors2);
//定義匹配器的實(shí)例化=>方法為暴力匹配法
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE);//create中的參數(shù)可以填string FlannBased等匹配方法
//第二種實(shí)例化方法
//BFMatcher matcher;
//進(jìn)行暴力匹配
vector<DMatch> matches;
vector<Mat>train_desc(1, descriptors2);
matcher->add(train_desc);
matcher->train();
vector<vector<DMatch>> matchpoints;
matcher->knnMatch(descriptors1,matchpoints,2);
vector<DMatch> goodfeatur;
for (int i = 0; i < matchpoints.size(); i++)
{
if (matchpoints[i][0].distance<0.15*matchpoints[i][1].distance)
{
goodfeatur.push_back(matchpoints[i][0]);
}
}
cout << "篩選后的特征點(diǎn)數(shù)量為: " << goodfeatur.size() << endl;
//輸出關(guān)鍵點(diǎn)和匹配結(jié)果
//其中右側(cè)圖為trainDescription模板,左側(cè)圖為queryDescription目標(biāo)
//左圖中的點(diǎn)與右圖中進(jìn)行匹配對(duì)應(yīng)
drawMatches(src1,keypoints1,src2,keypoints2, goodfeatur,result_img);
drawKeypoints(src1,keypoints1,src1);
drawKeypoints(src2,keypoints2,src2);
namedWindow("匹配結(jié)果",WINDOW_NORMAL);
resizeWindow("匹配結(jié)果",500,500);
imshow("匹配結(jié)果",result_img);
waitKey(0);
system("pause");
return 0;
}
運(yùn)行結(jié)果為:文章來源:http://www.zghlxwxcb.cn/news/detail-440522.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-440522.html
到了這里,關(guān)于Opencv(C++)學(xué)習(xí)系列---特征點(diǎn)檢測(cè)和匹配的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!