OpenCV4入门115:ORB特征检测与匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 功能:代码 8-5 ORB特征检测与匹配
// 作者:朱伟 zhu1988wei@163.com
// 来源:《OpenCV图像处理编程实例》
// 博客:http://blog.csdn.net/zhuwei1988
// 更新:2016-8-1
// 说明:版权所有,引用或摘录请联系作者,并按照上面格式注明出处,谢谢。//
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>
#include <iostream>

using namespace cv::xfeatures2d;
using namespace std;
using namespace cv;
// 计算图像的ORB特征及匹配
cv::Mat cacORBFeatureAndCompare(cv::Mat srcImage1,
cv::Mat srcImage2)
{
CV_Assert(srcImage1.data != NULL && srcImage2.data != NULL);
// 转换为灰度
cv::Mat grayMat1, grayMat2;
cv::cvtColor(srcImage1, grayMat1, CV_RGB2GRAY);
cv::cvtColor(srcImage2, grayMat2, CV_RGB2GRAY);
// 关键点检测
std::vector<KeyPoint> keyPoints1, keyPoints2;
// 描述特征向量
cv::Mat descriptorMat1, descriptorMat2;
// 初始化ORB检测描述子
cv::Ptr<Feature2D> orb = cv::ORB::create();

// 计算兴趣点
orb->detectAndCompute(grayMat1, Mat(), keyPoints1, descriptorMat1,false);
orb->detectAndCompute(grayMat2, Mat(), keyPoints2, descriptorMat2,false);

// 特征匹配
BFMatcher matcher(NORM_HAMMING);
std::vector<DMatch> mathces;
matcher.match(descriptorMat1, descriptorMat2, mathces);
// 绘制匹配点集
Mat matchMat;
drawMatches(srcImage1, keyPoints1,
srcImage2, keyPoints2, mathces, matchMat);
//cv::imshow("Mathces", matchMat);
return matchMat;
}
int main()
{
// 读取源图像及待匹配图像
cv::Mat srcImage1 =
cv::imread("..\\images\\hand1.jpg", 1);
if (srcImage1.empty())
return -1;
cv::Mat srcImage2 =
cv::imread("..\\images\\hand3.jpg", 1);
if (srcImage2.empty())
return -1;
cv::Mat matchMat = cacORBFeatureAndCompare(srcImage1, srcImage2);
cv::imshow("matchMat", matchMat);
cv::waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText() {
//输出欢迎信息和OpenCV版本
printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
printf("\n\n\t\t\t此为本书OpenCV2版的第72个配套示例程序\n");
printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION);
printf("\n\n ----------------------------------------------------------------------------\n");
//输出一些帮助信息
printf("\n\t欢迎来到【ORB算法描述提取,配合FLANN-LSH进行匹配】示例程序\n");
printf("\n\n\t按键操作说明: \n\n"
"\t\t键盘按键【ESC】- 退出程序\n");
}

//--------------------------------------【main( )函数】-----------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main() {
//【0】改变console字体颜色
system("color 2F");

//【0】显示帮助文字
ShowHelpText();

//【0】载入源图,显示并转化为灰度图
Mat srcImage = imread("1.jpg");
imshow("原始图", srcImage);
Mat grayImage;
cvtColor(srcImage, grayImage, CV_BGR2GRAY);

//------------------检测SIFT特征点并在图像中提取物体的描述符----------------------

//【1】参数定义
OrbFeatureDetector featureDetector;
vector<KeyPoint> keyPoints;
Mat descriptors;

//【2】调用detect函数检测出特征关键点,保存在vector容器中
featureDetector.detect(grayImage, keyPoints);

//【3】计算描述符(特征向量)
OrbDescriptorExtractor featureExtractor;
featureExtractor.compute(grayImage, keyPoints, descriptors);

//【4】基于FLANN的描述符对象匹配
flann::Index flannIndex(descriptors, flann::LshIndexParams(12, 20, 2),
cvflann::FLANN_DIST_HAMMING);

//【5】初始化视频采集对象
VideoCapture cap(0);

unsigned int frameCount = 0; //帧数

//【6】轮询,直到按下ESC键退出循环
while (1) {
double time0 = static_cast<double>(getTickCount()); //记录起始时间
Mat captureImage, captureImage_gray; //定义两个Mat变量,用于视频采集
cap >> captureImage; //采集视频帧
if (captureImage.empty()) //采集为空的处理
continue;

//转化图像到灰度
cvtColor(captureImage, captureImage_gray, CV_BGR2GRAY); //采集的视频帧转化为灰度图

//【7】检测SIFT关键点并提取测试图像中的描述符
vector<KeyPoint> captureKeyPoints;
Mat captureDescription;

//【8】调用detect函数检测出特征关键点,保存在vector容器中
featureDetector.detect(captureImage_gray, captureKeyPoints);

//【9】计算描述符
featureExtractor.compute(captureImage_gray, captureKeyPoints, captureDescription);

//【10】匹配和测试描述符,获取两个最邻近的描述符
Mat matchIndex(captureDescription.rows, 2, CV_32SC1),
matchDistance(captureDescription.rows, 2, CV_32FC1);
flannIndex.knnSearch(captureDescription, matchIndex, matchDistance, 2,
flann::SearchParams()); //调用K邻近算法

//【11】根据劳氏算法(Lowe's algorithm)选出优秀的匹配
vector<DMatch> goodMatches;
for (int i = 0; i < matchDistance.rows; i++) {
if (matchDistance.at<float>(i, 0) < 0.6 * matchDistance.at<float>(i, 1)) {
DMatch dmatches(i, matchIndex.at<int>(i, 0), matchDistance.at<float>(i, 0));
goodMatches.push_back(dmatches);
}
}

//【12】绘制并显示匹配窗口
Mat resultImage;
drawMatches(captureImage, captureKeyPoints, srcImage, keyPoints, goodMatches, resultImage);
imshow("匹配窗口", resultImage);

//【13】显示帧率
cout << ">帧率= " << getTickFrequency() / (getTickCount() - time0) << endl;

//按下ESC键,则程序退出
if (char(waitKey(1)) == 27)
break;
}

return 0;
}