用二值描述子匹配关键点 - sumpig/OpenCV GitHub Wiki


为了减少内存使用、降低计算量,人们引入了将一组比特位(0 和1)组合成二值描述子的概念。

本节将介绍其中的几种二值描述子,重点讲解ORB 和BRISK 描述子。


实现

二值描述子(例如ORB)的用法与 SURF、SIFT 没有什么区别。基于特征的图像匹配的整个过程如下所示:

// 定义关键点容器和描述子
std::vector<cv::KeyPoint> keypoints1;
std::vector<cv::KeyPoint> keypoints2;
cv::Mat descriptors1;
cv::Mat descriptors2;

// 定义特征检测器/描述子
cv::Ptr<cv::Feature2D> feature = cv::ORB::create(60);

// 检测并描述关键点
// 检测ORB 特征
feature->detectAndCompute(image1, cv::noArray(), keypoints1, descriptors1);
feature->detectAndCompute(image2, cv::noArray(), keypoints2, descriptors2);

// 构建匹配器
cv::BFMatcher matcher(cv::NORM_HAMMING); // 二值描述子一律使用 Hamming 规范

// 匹配两幅图像的描述子
std::vector<cv::DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);

这里唯一的区别是使用了 Hamming 规范(cv::NORM_HAMMING 标志),它通过统计不一致的位数,计算两个二值描述子的差值。在很多处理器上,这可以用异或运算加简单的位数统计来实现,并且效率很高。

原理

ORB 算法在多个尺度下检测特征点,这些特征点含有方向。基于这些特征点,ORB 描述子通过简单比较强度值,提取出每个关键点的表征。实际上,ORB 就是在BRIEF 描述子的基础上构建的(前面介绍过BRIEF 描述子),然后在关键点周围的邻域内随机选取一对像素点,创建一个二值描述子。比较这两个像素点的强度值,如果第一个点的强度值较大,就把对应描述子的位(bit)设为1,否则就设为0。对一批随机像素点对进行上述处理,就产生了一个由若干位(bit)组成的描述子,通常采用128 到512 位(成对地测试)。

这就是 ORB 采用的模式。接下来就要判断用哪些像素点对构建描述子了。事实上,虽然像素点对是随机选取的,但只要它们被选中,就要进行同样的二值测试,并构建全部关键点的描述子,以确保结果的一致性。直觉告诉我们,选择合适的像素点对可以使描述子具有更大的独特性。此外,每个关键点的方向是已经确定的,如果根据方向对该关键点进行调整(即使用相对于关键点方向的坐标),就会导致强度值模式分布的偏差。考虑到这些因素,并根据实验验证,ORB 选出了变化幅值较高、相关性极低的256 对像素点;也就是说,针对各种关键点,这些选用的二值测试项等于 0 或 1 的概率是均等的,并且它们之间的依赖性是最小的。

BRISK 描述子的情况也非常类似,它的基础也是成对地比较强度值。但有两点不同:第一,它不是从31×31 的邻域中随机选取像素,而是从一系列等间距的同心圆(由 60 个点组成)的采样模式中选取;第二,这些采样点的强度值都经过高斯平滑处理,处理中使用的 σ 值与该像素到圆心的距离成正比。BRISK 据此选取了512 对点。


扩展

FREAK

FREAK 全称为Fast Retina Keypoint(快速视网膜关键点),也是一种二值描述子,但没有对应的检测器。它可以应用于所有已检测到的关键点,例如SIFT、SURF 或ORB。

与 BRISK 一样,FREAK 描述子也基于用同心圆定义的采样模式。但为了设计描述子,设计者们使用人眼进行了类比。他们发现,随着离中央凹距离越来越远,视网膜上的神经节细胞密度越来越小。因此他们用 43 个像素点构建了采样模式,中心点附近的像素密度比其他地方要高得多。为了获得它的强度值,每个像素都用高斯内核进行滤波,当与中心点的距离增加时,内核的尺寸也随之增大。

根据经验,可以采用 ORB 中的类似策略,标识出需要执行的成对比较项。通过对几千个关键点的分析,可得到具有最高变化幅值和最低相关性的二值测试项,最终为 512 对。

FREAK 还引入了阶梯式比较描述子的概念。具体做法是,先执行表示较粗略信息的前 128 位(用较大的高斯内核在外围进行测试)。只有对比的描述子通过了第一步测试,后面的测试才能进行。

用 ORB 算法检测到关键点后,只需用下面的方法创建 cv::DescriptorExtractor 实例即可提取出 FREAK 描述子:

// 用FREAK 描述
feature = cv::xfeatures2d::FREAK::create();

本节三个描述子使用的采样模式参见下面的示意图。

第一个方块是 ORB/BRIEF 描述子,像素点对是在正方形网格中随机选取的。每个像素点对用线条连接起来,表示比较两个像素强度值的概率测试。这里只显示了8 对,ORB 默认使用 256 对。中间的方块是BRISK 采样模式,在圆形上均匀地采样像素点(为了使画面更清晰,这里只显示了第一个圆的点)。第三个方块是 FREAK 的对数极坐标的采样网格。BRISK 的采样点是均匀分布的,而FREAK 则是越接近中心点,密度越高。例如,BRISK 的外围圆圈上有 20 个点,而FREAK 的外围圆圈上只有 6 个点。

⚠️ **GitHub.com Fallback** ⚠️