OpenCV4入门111:SIFT特征检测与匹配

  • SIFT特征提取—关键点提取
  • SIFT特征提取—描述子生成
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include <opencv2/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

//--------------------------------------【main( )函数】-----------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main() {
//【1】载入图像、显示并转化为灰度图
Mat trainImage = imread("1.jpg"), trainImage_gray;
imshow("原始图", trainImage);
cvtColor(trainImage, trainImage_gray, CV_BGR2GRAY);

//【2】检测SIFT关键点、提取训练图像描述符
vector<KeyPoint> train_keyPoint;
Mat trainDescription;
SiftFeatureDetector featureDetector;
featureDetector.detect(trainImage_gray, train_keyPoint);
SiftDescriptorExtractor featureExtractor;
featureExtractor.compute(trainImage_gray, train_keyPoint, trainDescription);

// 【3】进行基于描述符的暴力匹配
BFMatcher matcher;
vector<Mat> train_desc_collection(1, trainDescription);
matcher.add(train_desc_collection);
matcher.train();

//【4】创建视频对象、定义帧率
VideoCapture cap(0);
unsigned int frameCount = 0; //帧数

//【5】不断循环,直到q键被按下
while (char(waitKey(1)) != 'q') {
//<1>参数设置
double time0 = static_cast<double>(getTickCount()); //记录起始时间
Mat captureImage, captureImage_gray;
cap >> captureImage; //采集视频到testImage中
if (captureImage.empty())
continue;

//<2>转化图像到灰度
cvtColor(captureImage, captureImage_gray, CV_BGR2GRAY);

//<3>检测SURF关键点、提取测试图像描述符
vector<KeyPoint> test_keyPoint;
Mat testDescriptor;
featureDetector.detect(captureImage_gray, test_keyPoint);
featureExtractor.compute(captureImage_gray, test_keyPoint, testDescriptor);

//<4>匹配训练和测试描述符
vector<vector<DMatch>> matches;
matcher.knnMatch(testDescriptor, matches, 2);

// <5>根据劳氏算法(Lowe's algorithm),得到优秀的匹配点
vector<DMatch> goodMatches;
for (unsigned int i = 0; i < matches.size(); i++) {
if (matches[ i ][ 0 ].distance < 0.6 * matches[ i ][ 1 ].distance)
goodMatches.push_back(matches[ i ][ 0 ]);
}

//<6>绘制匹配点并显示窗口
Mat dstImage;
drawMatches(captureImage, test_keyPoint, trainImage, train_keyPoint, goodMatches, dstImage);
imshow("匹配窗口", dstImage);

//<7>输出帧率信息
cout << "\t>当前帧率为:" << getTickFrequency() / (getTickCount() - time0) << endl;
}

return 0;
}
// 功能:代码 8-3 SIFT 特征检测及匹配
// 作者:朱伟 zhu1988wei@163.com
// 来源:《OpenCV图像处理编程实例》
// 博客:http://blog.csdn.net/zhuwei1988
// 更新:2016-8-1
// 说明:版权所有,引用或摘录请联系作者,并按照上面格式注明出处,谢谢。
// 注解:需重新编译OpenCV3.1 contrib,见本书附录2
#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;
// 计算图像的SIFT特征及匹配
float cacSIFTFeatureAndCompare(cv::Mat srcImage1,
cv::Mat srcImage2, float paraHessian)
{
CV_Assert(srcImage1.data != NULL && srcImage2.data != NULL);
// 转换为灰度
cv::Mat grayMat1, grayMat2;
cv::cvtColor(srcImage1, grayMat1, CV_RGB2GRAY);
cv::cvtColor(srcImage2, grayMat2, CV_RGB2GRAY);
// 初始化SIFT检测描述子
cv::Ptr<Feature2D> sift = xfeatures2d::SIFT::create();

// 关键点及特征描述矩阵声明
vector<cv::KeyPoint> keyPoints1, keyPoints2;
cv::Mat descriptorMat1, descriptorMat2;

sift->detectAndCompute(grayMat1, Mat(), keyPoints1, descriptorMat1);
sift->detectAndCompute(grayMat2, Mat(), keyPoints2, descriptorMat2);
float result = 0;
// 特征点匹配
if (keyPoints1.size() > 0 && keyPoints2.size() > 0)
{
// 计算特征匹配点
cv::FlannBasedMatcher matcher;
vector< cv::DMatch > matches;
std::vector<cv::DMatch> viewMatches;
matcher.match(descriptorMat1, descriptorMat2, matches);
// 最优匹配判断
double minDist = 100;
for (int i = 0; i < matches.size(); i++)
{
if (matches[i].distance < minDist)
minDist = matches[i].distance;
}
// 计算距离特征符合要求的特征点
int num = 0;
std::cout << "minDist: " << minDist << std::endl;
for (int i = 0; i < matches.size(); i++)
{
// 特征点匹配距离判断
if (matches[i].distance <= 2 * minDist)
{
result += matches[i].distance * matches[i].distance;
viewMatches.push_back(matches[i]);
num++;
}
}
// 匹配度计算
result /= num;
// 绘制特征点匹配结果
cv::Mat matchMat;
cv::drawMatches(srcImage1, keyPoints1,
srcImage2, keyPoints2, matches, matchMat);
cv::imshow("matchMat", matchMat);
cv::waitKey(0);
}
return result;
}
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;
float matchRate = cacSIFTFeatureAndCompare(srcImage1, srcImage2, 1000);
std::cout << "matchRate: " << matchRate << std::endl;
return 0;
}