一、什么是ORB特征
ORB 特征亦由关键点和描述子两部分组成。它的关键点称为“Oriented FAST”,是
一种改进的 FAST 角点,什么是 FAST 角点我们将在下文介绍。它的描述子称为 BRIEF
(Binary Robust Independent Elementary Features)。
因此,提取 ORB 特征分为两个步骤:
FAST 角点提取:找出图像中的” 角点”。相较于原版的 FAST, ORB 中计算了特征点的主方向,为后续的 BRIEF 描述子增加了旋转不变特性。
BRIEF 描述子:对前一步提取出特征点的周围图像区域进行描述。
二、暴力匹配
即对每一个特征点 xmt ,与所有的 xnt+1测量描述子的距离,然后排序,取最近的一个作为匹配点。描述子距离表示了两个特征之间的相似程度,不过在实际运用中还可以取不同的距离度量范数。对于浮点类型的描述子,使用欧氏距离进行度量即可。而对于二进制的描述子(比如 BRIEF 这样的),我们往往使用汉明距离(Hamming distance)做为度量——两个二进制串之间的汉明距离,指的是它们不同位数的个数。
三、实现代码
#include <opencv2/opencv.hpp>
#include <string>
using namespace std;
// global variables
string first_file = "./1.png";
string second_file = "./2.png";
const double pi = 3.1415926; // pi
// TODO implement this function
/**
* compute the angle for ORB descriptor
* @param [in] image input image
* @param [in|out] detected keypoints
*/
void computeAngle(const cv::Mat &image, vector<cv::KeyPoint> &keypoints);
// TODO implement this function
/**
* compute ORB descriptor
* @param [in] image the input image
* @param [in] keypoints detected keypoints
* @param [out] desc descriptor
*/
typedef vector<bool> DescType; // type of descriptor, 256 bools
void computeORBDesc(const cv::Mat &image, vector<cv::KeyPoint> &keypoints, vector<DescType> &desc);
// TODO implement this function
/**
* brute-force match two sets of descriptors
* @param desc1 the first descriptor
* @param desc2 the second descriptor
* @param matches matches of two images
*/
void bfMatch(const vector<DescType> &desc1, const vector<DescType> &desc2, vector<cv::DMatch> &matches);
int main(int argc, char **argv) {
// load image
cv::Mat first_image = cv::imread(first_file, 0); // load grayscale image
cv::Mat second_image = cv::imread(second_file, 0); // load grayscale image
// plot the image
cv::imshow("first image", first_image);
cv::imshow("second image", second_image);
cv::waitKey(0);
// detect FAST keypoints using threshold=40
vector<cv::KeyPoint> keypoints;
cv::FAST(first_image, keypoints, 40);
cout << "keypoints: " << keypoints.size() << endl;
// compute angle for each keypoint
computeAngle(first_image, keypoints);
// compute ORB descriptors
vector<DescType> descriptors;
computeORBDesc(first_image, keypoints, descriptors);
// plot the keypoints
cv::Mat image_show;
cv::drawKeypoints(first_image, keypoints, image_show, cv::Scalar::all(-1),
cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
cv::imshow("features", image_show);
cv::imwrite("feat1.png", image_show);
cv::waitKey(0);
// we can also match descriptors between images
// same for the second
vector<cv::KeyPoint> keypoints2;
cv::FAST(second_image, keypoints2, 40);
cout << "keypoints: " << keypoints2.size() << endl;
// compute angle for each keypoint
computeAngle(second_image, keypoints2);
// compute ORB descriptors
vector<DescType> descriptors2;
computeORBDesc(second_image, keypoints2, descriptors2);
// find matches
vector<cv::DMatch> matches;
bfMatch(descriptors, descriptors2, matches);
cout << "matches: " << matches.size() << endl;
// plot the matches
cv::drawMatches(first_image, keypoints, second_image, keypoints2, matches, image_show);
cv::imshow("matches", image_show);
cv::imwrite("matches.png", image_show);
cv::waitKey(0);
cout << "done." << endl;
return 0;
}
// -------------------------------------------------------------------------------------------------- //
// compute the angle
void computeAngle(const cv::Mat &image, vector<cv::KeyPoint> &keypoints) {
int half_patch_size = 8;
for (auto &kp : keypoints) {
// START YOUR CODE HERE (~7 lines)
kp.angle = 0; // compute kp.angle
// END YOUR CODE HERE
}
return;
}
// -------------------------------------------------------------------------------------------------- //
// ORB pattern
int ORB_pattern[256 * 4] = {
8, -3, 9, 5/*mean (0), correlation (0)*/,
4, 2, 7, -12/*mean (1.12461e-05), correlation (0.0437584)*/,
-11, 9, -8, 2/*mean (3.37382e-05), correlation (0.0617409)*/,
7, -12, 12, -13/*mean (5.62303e-05), correlation (0.0636977)*/,
2, -13, 2, 12/*mean (0.000134953), correlation (0.085099)*/,
1, -7, 1, 6/*mean (0.000528565), correlation (0.0857175)*/,
-2, -10, -2, -4/*mean (0.0188821), correlation (0.0985774)*/,
-13, -13, -11, -8/*mean (0.0363135), correlation (0.0899616)*/,
-13, -3, -12, -9/*mean (0.121806), correlation (0.099849)*/,
10, 4, 11, 9/*mean (0.122065), correlation (0.093285)*/,
-13, -8, -8, -9/*mean (0.162787), correlation (0.0942748)*/,
-11, 7, -9, 12/*mean (0.21561), correlation (0.0974438)*/,
7, 7, 12, 6/*mean (0.160583), correlation (0.130064)*/,
-4, -5, -3, 0/*mean (0.228171), correlation (0.132998)*/,
-13, 2, -12, -3/*mean (0.00997526), correlation (0.145926)*/,
-9, 0, -7, 5/*mean (0.198234), correlation (0.143636)*/,
12, -6, 12, -1/*mean (0.0676226), correlation (0.16689)*/,
-3, 6, -2, 12/*mean (0.166847), correlation (0.171682)*/,
-6, -13, -4, -8/*mean (0.101215), correlation (0.179716)*/,
11, -13, 12, -8/*mean (0.200641), correlation (0.192279)*/,
4, 7, 5, 1/*mean (0.205106), correlation (0.186848)*/,
5, -3, 10, -3/*mean (0.234908), correlation (0.192319)*/,
3, -7, 6, 12/*mean (0.0709964), correlation (0.210872)*/,
-8, -7, -6, -2/*mean (0.0939834), correlation (0.212589)*/,
-2, 11, -1, -10/*mean (0.127778), correlation (0.20866)*/,
-13, 12, -8, 10/*mean (0.14783), correlation (0.206356)*/,
-7, 3, -5, -3/*mean (0.182141), correlation (0.198942)*/,
-4, 2, -3, 7/*mean (0.188237), correlation (0.21384)*/,
-10, -12, -6, 11/*mean (0.14865), correlation (0.23571)*/,
5, -12, 6, -7/*mean (0.222312), correlation (0.23324)*/,
5, -6, 7, -1/*mean (