目录
1 概念讲解
1.1 ORB算法介绍
ORB特征描述算法的运行时间远优于SIFT和SURF,可用于实时性特征检测。 ORB特征基于FAST的特征点检测与描述技术,具有尺度与旋转不变性,同时对噪声及透视仿射也具有不变性,良好的性能使得用ORB在进行特征描述时的应用场景十分广泛。
1.2 FAST算法介绍
ORB采用FAST(features from accelerated segment test)算法来检测特征点,FAST算法的核心思想就是比较当前点和周围的点,如果周围大部分的点都与当前点不同,就可以认为它是一个特征点。
2 ORB特征检测流程
1)尺度空间建立:
FAST特征点检测算法虽然速度块,但是无法体现出一个优良特征点的尺度不变性与旋转不变性。 因此特征点检测的第一步就是尺度空间的构建。 ORB的尺度不变性,通过多分辨率图像金字塔来实现,步骤如下: ①设置比例因子scale(默认1.2)和金字塔层数n(通常取8)。 ②将源图像按照比例因子逐步缩小,共生成n副图像。
2)特征点检测:
在构建的尺度空间中,对每幅图像进行FAST特征点检测。将N幅不同比例的图像提取特征点总和作为输入图像的FAST特征点。
对于上图,FAST特征点检测算法的流程如下:
1)对于当前检测点P,判断其是否为特征点。
2)以P为圆心,R为半径,在图像中均匀选择M(16)个周围点与P进行比较。
3)设定一个合适的阈值t,当点P和周围点灰度值差的绝对值大于t时,认为这两点不同。
4)如果M个周围点与点P有连续的n个点不同,则认为点P是一个特征点。 对于分辨率大的图像,对每个像素点采取上述步骤,需要很大计算量。因此有一种通过排除非角点的算法,提高FAST特征点检测效率。
提升效率的FAST特征点检测算法的具体流程如下:
1)对于当前检测点P,判断其是否为特征点。
2)以P为圆心,R为半径,在图像中均匀选择M(16)个周围点。
3)定义阈值t,计算1、9与中心像素P的灰度差,若他们都小于阈值,则认为P不可能为特征点,否则进行下一步。
4)计算1、9、5、13与中心像素P的灰度差,若它们的绝对值至少三 个超过阈值t,则进行下一步,否则剔除。
5)计算1-16与中心像素的灰度差,若它们至少有9个超过阈值t,则 认为P是特征点。
3)特征主方向计算(旋转不变性):
对于上述步骤提取的特征点还没有旋转不变性,SIFT利用特征点周围像素块构建的梯度直方图峰值方向作为特征方向解决旋转不变性。 在ORB中则是利用图像的矩来完成旋转不变性。
具体步骤如下:
①在一个以特征点为中心小的图像块B中,定义图像块的矩(原点矩)为:
②通过图像的零阶和一阶矩,我们可以计算图像块的质心:
③连接图像块几何中心O与质心C,得到一个方向向量 为特征点的方向。
4)特征点的描述
得到特征点后,我们需要某种方式F来描述这些特征点的属性。这些属性的输出为我们称之为该特征点的描述子。ORB采用BRIEF算法来计算一个特征点的描述子。 BRIEF算法的核心思想是在特征点P的周围SxS邻域以一定模式选取N个点对(p_i,q_i)_i=1…..n,然后比较每个点对的灰度值大小,如果I(p_i)>I(q_i),则为1,否则为0。对所有点对进行比较,生成长度为N的二进制串。 然后将上面求出的二进制编码作为特征点的描述子,到了每个特征点的256位描述向量。
3 API详解
3.1 ORB::create()函数
cv::ORB::create 是一个静态函数,用于创建 ORB 特征点检测和描述子生成器的对象。
cv::ORB::create 函数返回一个指向 cv::ORB 对象的智能指针 (cv::Ptr<cv::ORB>)。智能指针的好处是可以自动管理内存,无需手动释放资源。
通过调用 create 函数并传递所需的参数,可以创建一个 ORB 特征点检测和描述子生成器的对象,并根据需求对其进行配置。
static cv::Ptr<cv::ORB> cv::ORB::create(
int nfeatures = 500, // 检测到的最大特征点数量,默认为 500
float scaleFactor = 1.2f, // 尺度因子,默认为 1.2f
int nlevels = 8, // 图像金字塔层数,默认为 8
int edgeThreshold = 31, // 边缘阈值,默认为 31
int firstLevel = 0, // 最初的图像金字塔层级,默认为 0
int WTA_K = 2, // BRIEF 描述子计算中使用的像素对数,默认为 2
int scoreType = cv::ORB::HARRIS_SCORE, // 关键点排列方式,默认为 HARRIS_SCORE
int patchSize = 31, // 计算描述子时的窗口大小,默认为 31
int fastThreshold = 20 // FAST 关键点检测阈值,默认为 20
);
nfeatures:检测到的最大特征点数量。默认为 500,可以根据实际需要进行调整。
scaleFactor:尺度因子。默认为 1.2f,表示每个金字塔层级之间的尺度比例。
nlevels:图像金字塔的层数。默认为 8,通常越多层级可以检测到更小尺度的特征点。
edgeThreshold:边缘阈值。默认为 31,用于排除位于边缘上的关键点。
firstLevel:最初的图像金字塔层级。默认为 0,表示从原始输入图像开始构建金字塔。
WTA_K:BRIEF 描述子计算中使用的像素对数。默认为 2,表示使用两个像素进行描述子的比较。
scoreType:关键点排列方式。默认为 cv::ORB::HARRIS_SCORE,可选择 cv::ORB::HARRIS_SCORE 或 cv::ORB::FAST_SCORE。
patchSize:计算描述子时的窗口大小。默认为 31,必须是一个奇数。
fastThreshold:FAST 关键点检测阈值。默认为 20,用于判断某个像素是否是关键点。
3.2 ORB::detectAndCompute()函数
cv::ORB::detectAndCompute 函数用于在图像上检测 ORB 特征点并计算对应的描述子。
void cv::ORB::detectAndCompute(
InputArray image, // 输入图像
InputArray mask, // 掩码,用于指定感兴趣区域,默认为空
std::vector<KeyPoint>& keypoints, // 输出的关键点
OutputArray descriptors, // 输出的描述子
bool useProvidedKeypoints = false // 是否使用提供的关键点,默认为 false
);
image:输入图像,类型为 cv::Mat 或 cv::InputArray。
mask:掩码,用于指定感兴趣区域。默认为空,表示没有限制。
keypoints:输出的关键点,类型为 std::vector<cv::KeyPoint>。函数将检测到的关键点存储在此向量中。
descriptors:输出的描述子,类型为 cv::Mat 或 cv::OutputArray。函数将计算的描述子存储在此矩阵中。
useProvidedKeypoints:是否使用提供的关键点,默认为 false。如果设置为 true,则函数将不会检测关键点,而是直接使用提供的关键点进行计算。
4 C++ 代码实现
以下是使用 OpenCV C++ 实现 ORB 特征点检测和描述子生成的示例代码:
#include <opencv2/opencv.hpp>
int main() {
// 读取图像
cv::Mat image = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
// 创建 ORB 对象
cv::Ptr<cv::ORB> orb = cv::ORB::create();
// 检测特征点并计算描述子
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
orb->detectAndCompute(image, cv::noArray(), keypoints, descriptors);
// 绘制检测到的特征点
cv::Mat image_with_keypoints;
cv::drawKeypoints(image, keypoints, image_with_keypoints);
// 显示图像和特征点
cv::imshow("Image with Keypoints", image_with_keypoints);
cv::waitKey(0);
return 0;
}