vSLAMNet(三)-描述子-BRIEF描述子

1. 概述

  • BRIEF(Binary Robust Independent Elementary Features)是一种对已检测到的特征点进行表示和描述的特征描述方法,和传统的利用图像局部邻域的灰度直方图或梯度直方图提取特征的方式不同,BRIEF是一种二进制编码的特征描述子,既降低了存储空间的需求,提升了特征描述子生成的速度,也减少了特征匹配时所需的时间
  • BRIEF正是这样一种基于二进制编码生成特征描述子,以及利用汉明距离进行特征匹配的算法
  • 由于BRIEF只是一种特征描述子,因此事先得检测并定位特征点,可采用Harris、FAST或者是SIFT算法检测特征点,在此基础上利用BRIEF算法建立特征描述符,在特征点邻域Patch内随机选取若干点对(p,q),并比较这些点对的灰度值,若I(p)>I(q),则编码为1,否则编码为0。这样便可得到一个特定长度的二进制编码串,即BRIEF特征描述子
  • 算法特点
    • BRIEF算法通过检测随机响应,并采用二进制编码方式建立特征描述子,减少了特征的存储空间需求,并提升了特征生成的速度;Hamming距离的度量方式便于进行特征点的快速匹配,而且大量实验数据表明,不匹配特征点的Hamming距离为128左右(特征维数为256),而匹配点的Hamming距离则远小于128
    • BRIEF算法的缺点是不具备尺度不变性和旋转不变性,在图像的旋转角度超过30度时,特征点匹配的准确率快速下降

2. 算法详解

  • 利用Harris或者FAST等方法检测特征点
  • 确定特征点的邻域窗口Patch,并对该邻域内像素点进行σ=2、窗口尺寸为9的高斯平滑,以滤除噪声(也可直接对整幅图像做高斯平滑)
  • 在邻域窗口内随机选取n对(n可取128、256等)像素点,并根据灰度值大小编码成二进制串,生成n位(bit)的特征描述子

3. 采样方式

  • 论文原作者Calonder提供了5种在S×S的邻域Patch内随机选取点对(X,Y)的方法,如下图所示,一条线段的两个端点表示一个随机点对(xi,yi)
    • X、Y为均匀分布[−S/2,S/2]
    • X、Y均为高斯分布[0, S2/25],采样准则服从各向同性的同一高斯分布
    • XX 服从高斯分布[0,S2/25],Y服从高斯分布(xi,S2/100),即采样分为两步,首先在原点处为xi进行高斯采样,然后在中心为xi处为yi进行高斯采样
    • X、Y在空间量化极坐标下的离散位置处进行随机采样
    • X固定为(0,0),Y在空间量化极坐标下的离散位置处进行随机从采样

image-20200503145906313

4. 代码实现

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
#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>

using namespace cv;

int main(int argc, char** argv)
{
Mat img_1 = imread("box.png");
Mat img_2 = imread("box_in_scene.png");

// -- Step 1: Detect the keypoints using STAR Detector
std::vector<KeyPoint> keypoints_1,keypoints_2;
StarDetector detector;
detector.detect(img_1, keypoints_1);
detector.detect(img_2, keypoints_2);

// -- Stpe 2: Calculate descriptors (feature vectors)
BriefDescriptorExtractor brief;
Mat descriptors_1, descriptors_2;
brief.compute(img_1, keypoints_1, descriptors_1);
brief.compute(img_2, keypoints_2, descriptors_2);

//-- Step 3: Matching descriptor vectors with a brute force matcher
BFMatcher matcher(NORM_HAMMING);
std::vector<DMatch> mathces;
matcher.match(descriptors_1, descriptors_2, mathces);
// -- dwaw matches
Mat img_mathes;
drawMatches(img_1, keypoints_1, img_2, keypoints_2, mathces, img_mathes);
// -- show
imshow("Mathces", img_mathes);

waitKey(0);
return 0;
}