算法部分
- 获取关键点
- 使用cv::FAST函数获取图像特征点,cv::FAST中自带高斯金字塔,实现了尺度不变性
- 计算描述子
- 剔除边缘不稳定的关键点
- 求关键点局部区域的旋转方向
- 在关键点附近的局部区域(patch)组成的图像块,定义图像块的像素矩m01、m10,然后求图像块的像素质心(类似于重心)C=(m10/m_sqrt , m01/m_sqrt)
- 连接图像块几何中心O与质心C,得到方向向量OC,定义特征点方向为 theta
- 在关键点附近选取256对随机像素点(像素点对的选取方式为pattern,pattern服从随机分布、高斯分布等,特征点的分布方式不影响旋转结果),每对像素点都旋转 theat 角度。
- 比较每对像素点,p大于q取1,小于取0。则每对关键点都由附近的像素点比较后组成了256位的描述子。
- 比较描述子
- 每个特征点x(t)与所有x(t+1)计算汉明距离并排序,取最近点为匹配点
//
// Created by wcm on 2020/6/1.
//
//nmmintrin与SSE指令集有关
//SSE指令集提供标量和包裹式浮点运算
#include <opencv2/opencv.hpp>
#include <string>
#include <nmmintrin.h>
#include <chrono>
using namespace std;
//global variables
string first_file= "/home/automobile/wcm/slambook2/ch7/01.png";
string second_file= "/home/automobile/wcm/slambook2/ch7/02.png";
//Descriptor type
//32 bit unsigned int, will have 8, 8*32=256
typedef vector<uint32_t> DescType;
/**
* compute descriptors of ORB keypoints
* @param img input image
* @param keypoints detected fast keypoints
* @param descriptors descriptors
*
* Note:if a keypoint goes outside the image boundary(8 pixels),
* descriptors will not be compute and leave as empty
*/
void ComputeORB(const cv::Mat &img, vector<cv::KeyPoint> &keypoints, vector<DescType> &descriptors);
/**
* Brute-Force match two sets of descriptors
* @param desc1 the first descriptors
* @param desc2 the second descriptors
* @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, CV_LOAD_IMAGE_COLOR);
cv::Mat second_image = cv::imread(second_file, CV_LOAD_IMAGE_COLOR);
assert(first_image.data != nullptr && second_image.data != nullptr );
//detect fast keypoints using threshold=40
//ORB使用FAST算法检测特征点
//OpenCV中的ORB采用了图像金字塔来解决尺度变换一致性
//自定义ComputeORB函数来描述ORB特征点,并旋转使其具备旋转尺度不变性
chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
vector<cv::KeyPoint> keypoints1;
cv::FAST(first_image, keypoints1, 40);
vector<DescType> descriptor1;
ComputeORB(first_image, keypoints1, descriptor1);
//same for the second
vector<cv::KeyPoint> keypoints2;
cv::FAST(second_image, keypoints2, 40);
vector<DescType> descriptor2;
ComputeORB(second_image, keypoints2, descriptor2);
chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
chrono::duration<double> time_used_extract = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << " extract ORB cost = " << time_used_extract.count() << " seconds. "<< endl;
//find matches
//自定义BfMatch函数,匹配特征点
vector<cv::DMatch> matches;
chrono::steady_clock::time_point t3 = chrono::steady_clock::now();
BfMatch(descriptor1, descriptor2, matches);
chrono::steady_clock::time_point t4 = chrono::steady_clock::now();
chrono::duration<double> time_used_match = chrono::duration_cast<chrono::duration<double>>(t4 - t3);
cout << " match ORB cost " << time_used_match.count() << " seconds" <<endl;
chrono::duration<double> ORB_total_time_used = chrono::duration_cast<chrono::duration<double>>(time_used_extract + time_used_match);
cout << " extract and match ORB cost = " << ORB_total_time_used.count() << " seconds" <<endl;
cout << " matches: " << matches.size() <<endl;
//plot the matches
cv::Mat image_show;
cv::drawMatches(first_image, keypoints1, 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;
}
//-------------------------------------------------------------//
//ORB pattern
//特征点附近256次像素比较,每次比较两个像素点
//patter选取的两个像素点的分布方式,如高斯分布,随机分布,每种分布的结果应该差不多
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