FAST 是用于快速检测图像中关键点的方法,而 SURF 和 SIFT 算法的设计重点是尺度不变性。为了同时实现快速检测和尺度不变性,OpenCV
中引入了新的兴趣点检测器,包括 BRISK
(Binary Robust Invariant Scalable Keypoints
) 检测器(基于 FAST 特征检测器)和 ORB
(Oriented FAST and Rotated BRIEF
) 检测器。当需要快速可靠的图像匹配时,可以使用特征点检测器 BRISK
和 ORB
。
可以利用 cv::FeatureDetector
抽象类使用 BRISK
检测关键点。
(1) 首先创建一个检测器的实例,然后在输入图片上调用 detect
方法:
cv::Ptr<cv::xfeatures2d::SiftFeatureDetector> ptrSIFT = new cv::xfeatures2d::SiftFeatureDetector();
ptrSIFT->detect(image, keypoints);
在图像中检测到的多尺度关键点如下图所示:
BRISK
不仅是一个特征点检测器,而且该方法还包括每个检测到的关键点的邻域,接下来,我们将介绍如何使用 BRISK
执行多尺度关键点的快速检测。
为了检测不同尺度的兴趣点,BRISK
方法首先通过两个下采样过程构建图像金字塔,第一个过程从原始图像大小开始,并在每一层(或 octave
) 上将其缩小一半,中间层是通过将原始图像向下采样 1.5
倍来创建的,在这些中间层中,原始图像通过连续的 1/2
采样生成附加层:
然后将 FAST
特征检测器应用于该金字塔的所有图像,关键点提取与 SIFT
使用类似的标准。首先,当将其强度与其八个空间邻居之一进行比较时,可接受的兴趣点必须是局部最大值,然后将该点与上下层中相邻点的分数进行比较,如果它的分数同样更高,那么它就被认为是一个兴趣点,BRISK
的关键在于金字塔的不同层具有不同的分辨率。
该方法需要在尺度和空间上进行插值,以便精确定位每个关键点,插值基于 FAST
关键点分数。在空间中,插值是在 3x3
邻域上执行的,在尺度上,它是通过沿着尺度轴拟合一个一维抛物线通过当前点及其上下两个相邻的局部关键点来计算的;上图中说明了如何进行这种关键点定位。因此,即使在离散图像尺度上执行 FAST
关键点检测,与每个关键点关联的结果检测尺度也是一个连续值。
cv::BRISK
类提供了两个可选参数来控制关键点的检测,第一个参数是 FAST
关键点的阈值,第二个参数是图像金字塔中将生成的 octave
数:
cv::Ptr<cv::BRISK> ptrBRISK = cv::BRISK::create(
60, // BRISK 关键点可接受的阈值
5); // octave 数量
ptrBRISK->detect(image, keypoints);
在 OpenCV
中,除了 BRISK
可以作为多尺度快速检测器外,ORB
特征检测器也可以高效的执行关键点检测。
ORB
(Oriented FAST and Rotated BRIEF
) 的第一部分指的是关键点检测部分,而第二部分指的是 ORB
提出的描述符,本节中,我们将专注于检测方法。
与 BRISK
一样,ORB
首先创建一个由多个层组成图像金字塔,其中每一层都是由前一层按特定比例因子(由 cv::ORB
函数中的参数)下采样获得。然后接受最强的 N
个关键点,其中关键点分数由 Harris
角度度量定义。
ORB
检测器的方向与每个检测到的兴趣点相关联,这些信息有助于对齐在不同图像中检测到的关键点的描述符,ORB
中使用关键点周围圆形邻域的质心方向。根据定义,由于 FAST
关键点始终具有偏心的质心,因此连接中心点和质心的直线的角度可以很好的定义质心方向。ORB
特征检测调用方法如下:
cv::Ptr<cv::ORB> ptrORB = cv::ORB::create(
75, // 关键点总数
1.2, // 层间缩放因子
8); // 金字塔中层数
ptrORB->detect(image, keypoints);
得到的结果如下所示:
如上图所示,由于关键点是在每个金字塔层上独立检测的,因此检测器可以在不同尺度上重复检测相同的特征点。
头文件 (harrisDetector.h
) 完整代码参考 Harris 特征点检测一节,主函数文件 (briskCorners.cpp
) 完整代码如下所示:
#include
#include
#include
#include
#include
#include
#include "harrisDetector.h"
int main() {
// Harris
cv::Mat image = cv::imread("1.png", 0);
if (!image.data) return 0;
std::vector<cv::KeyPoint> keypoints;
cv::Mat featureImage;
// BRISK
cv::transpose(image, image);
cv::flip(image, image, 0);
keypoints.clear();
cv::Ptr<cv::BRISK> ptrBRISK = cv::BRISK::create(
60, // BRISK 关键点可接受的阈值
5); // octave 数量
ptrBRISK->detect(image, keypoints);
cv::drawKeypoints(image, keypoints, featureImage, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
cv::namedWindow("BRISK");
cv::imshow("BRISK", featureImage);
std::cout << "Number of BRISK keypoints: " << keypoints.size() << std::endl;
// ORB
image = cv::imread("1.png", 0);
cv::transpose(image, image);
cv::flip(image, image, 0);
keypoints.clear();
cv::Ptr<cv::ORB> ptrORB = cv::ORB::create(
75, // 关键点总数
1.2, // 层间缩放因子
8); // 金字塔中层数
ptrORB->detect(image, keypoints);
cv::drawKeypoints(image, keypoints, featureImage, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
cv::namedWindow("ORB");
cv::imshow("ORB", featureImage);
std::cout << "Number of ORB keypoints: " << keypoints.size() << std::endl;
cv::waitKey();
return 0;
}
OpenCV实战(1)——OpenCV与图像处理基础
OpenCV实战(2)——OpenCV核心数据结构
OpenCV实战(3)——图像感兴趣区域
OpenCV实战(4)——像素操作
OpenCV实战(5)——图像运算详解
OpenCV实战(6)——OpenCV策略设计模式
OpenCV实战(7)——OpenCV色彩空间转换
OpenCV实战(8)——直方图详解
OpenCV实战(9)——基于反向投影直方图检测图像内容
OpenCV实战(10)——积分图像详解
OpenCV实战(11)——形态学变换详解
OpenCV实战(12)——图像滤波详解
OpenCV实战(13)——高通滤波器及其应用
OpenCV实战(14)——图像线条提取
OpenCV实战(15)——轮廓检测详解
OpenCV实战(16)——角点检测详解
OpenCV实战(17)——FAST特征点检测