查看全课大纲(第 18 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

局部特征-ORB特征描述子

ORB特征描述子

小象实战讲义 · 基于深度学习的计算机视觉

前面我们已经学习了SIFT和SURF这两种强大的局部特征描述子:SIFT具有良好的旋转、尺度、光照不变性;SURF在亮度变化和模糊下表现好,但尺度与旋转不变性均不及SIFT。然而,它们的计算复杂度较高,在实时性要求高的场景下(如移动设备、机器人视觉)往往力不从心。本节我们将介绍ORB(Oriented FAST and Rotated BRIEF) 特征描述子,它巧妙地将FAST角点检测的快速性与BRIEF描述子的简洁性相结合,并通过改进使其具备了尺度和旋转不变性,成为在速度和性能之间取得优秀平衡的实时特征提取方案。

💡 核心导读

  • ORB的诞生背景:了解SIFT/SURF在实时性和专利方面的局限,以及ORB作为免费、快速替代方案的价值。
  • 两大技术基石:掌握ORB如何结合并改进FAST角点检测(赋予尺度不变性)和BRIEF特征描述(赋予旋转不变性)。
  • BRIEF描述子原理:理解通过随机点对比较生成二进制描述串的机制,以及点对分布的两种常见方式。
  • ORB的改进策略:学习ORB如何通过构建高斯金字塔为FAST添加尺度不变性,以及如何通过计算“形心”方向为BRIEF添加旋转不变性。
  • 算法流程总览:从图像输入到最终生成具备不变性的二进制描述子,梳理ORB的完整工作流程。

ORB的诞生:快速且免费的特征描述子

在计算机视觉的早期应用中,SIFT和SURF是局部特征描述领域的标杆。它们性能强大,但计算复杂。课程中特别指出,SURF相比SIFT虽然快了不少,但如果没有硬件加速,两者其实都不快,很难满足实时特征检测的需求。

更现实的一个问题是,SIFT和SURF在早期是有专利保护的,属于收费技术。这在商业应用中构成了额外的成本和壁垒。因此,业界迫切需要一种性能相当、计算更快、并且免费的特征描述子。ORB(由Ethan Rublee等人在2011年提出)正是在这样的背景下应运而生。

ORB并非一个完全创新的算法,而是两种已有技术的巧妙结合与改进:

  1. 特征点检测:采用FAST(Features from Accelerated Segment Test)角点检测器。FAST以其极高的检测速度著称。
  2. 特征点描述:采用BRIEF(Binary Robust Independent Elementary Features)描述子。BRIEF通过比较像素点对生成紧凑的二进制串,描述和匹配速度极快。

ORB的核心工作,就是针对FAST和BRIEF各自的缺点进行改进,然后将它们融合成一个既快又好的特征描述方案。

技术基石一:FAST角点检测及其改进

FAST角点检测的基本思想非常直观:在一个像素点周围画一个半径为3个像素的圆(共16个圆周像素),如果这个圆上有连续N个(通常N=12)像素的灰度值,都比中心像素的灰度值加上一个阈值t大,或者都比中心像素的灰度值减去t小,那么这个中心点就被认为是一个角点。

import numpy as np
import cv2

# 为了演示,我们创建一个简单的含有角点图案的小图像(例如一个黑色背景上的白色L型)
# 图像尺寸 9x9
image = np.zeros((9, 9), dtype=np.uint8)
image[2:7, 2] = 255  # 垂直白线
image[6, 2:7] = 255  # 水平白线
# 角点在 (6,2) 位置

print("模拟图像(L型角点):")
print(image)
模拟图像(L型角点):
[[  0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0]
 [  0   0 255   0   0   0   0   0   0]
 [  0   0 255   0   0   0   0   0   0]
 [  0   0 255   0   0   0   0   0   0]
 [  0   0 255   0   0   0   0   0   0]
 [  0   0 255 255 255 255 255   0   0]
 [  0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0]]

FAST的缺点:缺乏尺度不变性。 问题在于,FAST检测时所用的那个“半径为3像素的圆”是固定大小的。这意味着它只能在固定的、最细的尺度上寻找角点。如果物体离相机很远,角点在图像中只占据很小的区域(小尺度),FAST能检测到;但如果物体很近,同一个角点可能覆盖一大片像素区域(大尺度),FAST固定的检测圆就无法有效捕捉到这个“大块头”的角点了。

ORB的改进:引入图像金字塔。 解决尺度不变性的经典方法就是构建图像金字塔。ORB采用了高斯金字塔。具体做法是:

  1. 对原始图像进行不同尺度的高斯模糊(下采样),得到一系列不同尺度的图像。
  2. 在金字塔的每一层图像上都独立运行FAST角点检测。 这样,无论角点在原始图像中呈现为何种尺度,总能在金字塔的某一层上,以其“合适”的尺度被FAST检测出来。这就赋予了ORB特征尺度不变性。

技术基石二:BRIEF描述子及其改进

BRIEF描述子的目标是为一个特征点(关键点)生成一个简短、独特的二进制描述串。它的思路非常巧妙,完全依赖于像素点对的强度比较。

BRIEF描述子的生成步骤:

  1. 图像平滑:首先对特征点周围的图像块(Patch)进行高斯平滑,以抑制噪声。
  2. 选择点对模式:在特征点周围的Patch内,预先定义好n_d个(例如256个)点对 (p, q)。每个点对包含两个像素位置。这些点对的位置是随机生成但一旦确定就固定不变的,形成一个“比较模板”。
  3. 生成二进制串:对于每个点对 (p, q),比较位置p和q处的像素灰度值I(p)和I(q)。
    • 如果 I(p) < I(q),则在描述串的对应位上输出 1。
    • 如果 I(p) > I(q),则输出 0。 遍历所有n_d个点对,就得到了一个长度为n_d的二进制串(例如256位),这就是该特征点的BRIEF描述子。
import numpy as np

# 模拟BRIEF描述子生成过程
np.random.seed(42)  # 固定随机种子,确保可复现
patch_size = 31  # 假设Patch大小为31x31
nd = 8  # 为了演示,只用8个点对(实际常用256)

# 1. 模拟一个平滑后的图像Patch (用随机灰度模拟)
patch = np.random.randint(0, 256, (patch_size, patch_size), dtype=np.uint8)

# 2. 预先定义的点对(坐标相对于Patch中心)。这里使用均匀分布生成。
# 点对坐标限制在[-patch_size//2, patch_size//2]范围内
S = patch_size // 2
point_pairs = []
for _ in range(nd):
    x1, y1 = np.random.randint(-S, S, 2)
    x2, y2 = np.random.randint(-S, S, 2)
    point_pairs.append(((x1, y1), (x2, y2)))

# 3. 生成二进制描述串
descriptor = []
center = (patch_size // 2, patch_size // 2)  # Patch中心
for (p, q) in point_pairs:
    # 将相对坐标转换为绝对坐标
    p_abs = (center[0] + p[0], center[1] + p[1])
    q_abs = (center[0] + q[0], center[1] + q[1])
    # 获取像素值(确保坐标在边界内)
    val_p = patch[p_abs[0], p_abs[1]]
    val_q = patch[q_abs[0], q_abs[1]]
    # 比较并生成bit
    bit = 1 if val_p < val_q else 0
    descriptor.append(bit)

print("模拟的8个点对(相对中心坐标):")
for i, (p, q) in enumerate(point_pairs):
    print(f"  点对{i}: p({int(p[0])}, {int(p[1])}) vs q({int(q[0])}, {int(q[1])})")
print(f"\n生成的8位BRIEF描述子: {descriptor}")
print(f"二进制串: {''.join(str(b) for b in descriptor)}")
模拟的8个点对(相对中心坐标):
  点对0: p(7, 12) vs q(9, -9)
  点对1: p(14, -15) vs q(-15, 9)
  点对2: p(11, 14) vs q(9, 4)
  点对3: p(-3, -7) vs q(-13, -9)
  点对4: p(-10, -8) vs q(11, -7)
  点对5: p(14, -11) vs q(-15, 3)
  点对6: p(-6, -4) vs q(8, -1)
  点对7: p(11, 6) vs q(8, -7)

生成的8位BRIEF描述子: [0, 0, 0, 1, 1, 0, 0, 1]
二进制串: 00011001

点对的分布模式: 课件中提到,点对的生成方式有5种,常见的有两种:

  1. 均匀分布:点对的坐标在Patch范围内均匀随机选取。生成的连线看起来在整个Patch内随机分布。
  2. 高斯分布:点对的坐标服从以特征点为中心的高斯分布。这意味着点对更可能出现在特征点附近,因为一般认为靠近中心的像素信息更稳定、更重要。

BRIEF的缺点:缺乏旋转不变性。 由于BRIEF描述子依赖的是固定位置的点对比较,一旦图像发生旋转,特征点周围Patch的内容相对于这些固定点对的位置就发生了变化,导致比较结果完全不同,描述子也就不再匹配。

ORB的改进:为BRIEF添加方向(旋转不变性)。 ORB采用了一种直观的方法为每个特征点计算一个主方向,然后将BRIEF的比较坐标系旋转到这个主方向上。具体步骤是:

  1. 计算形心(Centroid):在特征点周围的圆形区域内,将每个像素的坐标以其灰度值为“质量”进行加权,计算该区域的质心。公式可以表示为: mpq=∑x,yxpyqI(x,y)m_{pq} = \sum_{x,y} x^p y^q I(x,y) 质心坐标则为:C=(m10m00,m01m00)C = \left( \frac{m_{10}}{m_{00}}, \frac{m_{01}}{m_{00}} \right) 其中I(x,y)是像素灰度,m_00是区域内的总“质量”(灰度之和)。
  2. 确定主方向:从特征点指向质心C的向量,即为该特征点的主方向。若坐标以关键点为原点,方向角为:θ=atan2(m01,m10)\theta = \text{atan2}(m_{01}, m_{10})
  3. 旋转点对:在生成BRIEF描述子时,不再使用原始固定的点对坐标,而是将这些点对坐标根据计算出的方向角θ进行旋转,然后再进行像素值比较。这样就保证了无论图像如何旋转,描述子都是在相同的“视觉方向”上生成的,从而具备了旋转不变性。
# ORB中计算主方向(形心法)的伪代码示例
def compute_orientation(patch):
    """
    计算一个图像Patch的主方向(通过形心法)。
    patch: 以关键点为中心的图像块。
    """
    h, w = patch.shape
    # 创建坐标网格
    y_coords, x_coords = np.mgrid[:h, :w]
    # 计算矩
    m00 = np.sum(patch)
    m10 = np.sum(x_coords * patch)
    m01 = np.sum(y_coords * patch)
    # 计算形心
    cx = m10 / m00
    cy = m01 / m00
    # 计算方向角(从中心指向形心)
    orientation = math.atan2(cy - h/2, cx - w/2)  # 注意坐标转换
    return orientation

ORB算法流程总结

综合以上改进,ORB特征提取的完整流程如下:

  1. 构建高斯金字塔:对输入图像进行多尺度下采样,以支持尺度不变性。
  2. FAST角点检测:在金字塔的每一层图像上检测FAST角点。
  3. Harris角点响应筛选:对FAST角点计算Harris角点响应值,按响应值排序并保留前N个,使角点分布更稳定、更均匀。
  4. 计算特征点方向:对于每个最终确定的特征点,在其所在金字塔层的对应位置,提取一个图像Patch,利用形心法计算该特征点的主方向θ。
  5. 生成rBRIEF描述子:使用预先定义好的点对集合,但将这些点对的坐标根据方向θ进行旋转。然后在旋转后的坐标位置上,进行像素强度比较,生成二进制描述串。按方向旋转点对的版本称为 steered BRIEF;ORB 实际采用的 rBRIEF 还在此基础上通过贪心学习挑选高方差、低相关的点对。
  6. 特征点与描述子输出:最终,每个特征点由其位置(包含尺度信息)、方向以及一个二进制描述子(如256位)共同表示。

通过“FAST(加金字塔)+ rBRIEF(加方向)”的组合,ORB成功地在速度和不变性性能之间取得了出色的平衡。其描述子是二进制的,匹配时可以使用汉明距离(Hamming Distance)(即计算两个二进制串中不同位的数量),这种位运算速度极快,进一步提升了整个特征匹配流程的效率。

📝 动手练一练

  1. 概念辨析:ORB描述子是一个256位的浮点数向量,这种说法对吗?为什么?ORB描述子匹配时通常使用什么距离度量?
👉 点击查看参考答案

这种说法不对。ORB描述子是一个256位的二进制串(例如由0和1组成的序列),而不是浮点数向量。它通过比较像素点对生成二进制位。

ORB描述子匹配时通常使用汉明距离(Hamming Distance)。汉明距离是指两个等长字符串在对应位置上不同字符的个数。对于二进制串,就是进行异或(XOR)操作后统计结果中1的个数。计算汉明距离可以通过高效的位运算完成,速度非常快,这也是ORB适合实时应用的原因之一。

  1. 流程理解:假设你有一张图像,先用FAST检测到了角点,然后直接使用BRIEF为其生成描述子。现在将该图像旋转30度后重复此过程。你认为这两组描述子还能成功匹配吗?ORB是如何解决这个问题的?
👉 点击查看参考答案

很可能无法成功匹配。因为BRIEF描述子依赖于特征点周围固定位置的点对比较。图像旋转后,同一个物理点在图像上的周围像素布局相对于这些固定点对发生了改变,导致比较结果(0或1)大量变化,从而使描述子失效。

ORB的解决方案:在生成BRIEF描述子之前,ORB会为每个特征点计算一个主方向(例如通过形心法)。然后,在生成描述子时,会将预先定义的点对坐标旋转到这个主方向上来,再进行像素比较。这样,无论图像如何旋转,描述子都是在相同的“视觉方向”上生成的,从而具备了旋转不变性。这个按方向旋转点对的版本称为 steered BRIEF;ORB 最终采用的 rBRIEF 还在此基础上通过学习挑选去相关的点对。

本章小结

本节我们深入剖析了ORB特征描述子,它是实时计算机视觉应用中的一个经典选择。ORB的智慧在于“站在巨人的肩膀上”,通过有针对性的改进,将FAST角点检测的“快”和BRIEF描述的“简”融合升级,最终获得了具备尺度和旋转不变性的快速二进制描述子。

📋 行动清单

  • 理解ORB的构成:能够清晰说出ORB是哪两种技术的结合,并分别指出它们原有的缺陷以及ORB的改进方法。
  • 掌握BRIEF原理:理解二进制描述子是如何通过随机点对比较生成的,并知道均匀分布和高斯分布两种点对模式的特点。
  • 实践与思考:尝试使用OpenCV的cv2.ORB_create()函数(标准opencv-python即可;需要contrib的是SURF等非自由算子)提取并可视化图像中的ORB特征点,观察其在不同图像变换下的稳定性。

—— 小象教研组