VPI - 视觉编程接口

3.2 版本

FAST 角点检测器

概述

加速分割测试特征 (FAST) 是一种角点检测算法。它检测输入图像上的角点,并返回其坐标。这些角点随后可以用作跟踪的特征关键点。使用 FAST 的主要优点是其计算效率,因此得名 FAST(快速)。此优势在实时视频处理和机器学习管道中非常重要。FAST 的主要缺点是缺乏方向性以及对图像域和特征尺度的敏感性。下表显示了一个示例输入图像、FAST 算法的一组输入参数(如下所述)以及以红色检测到的角点。

输入参数输出

\begin{align*} \mathit{circleRadius} &= 3 \\ \mathit{arcLength} &= 9 \\ \mathit{intensityThreshold} &= 142 \\ \mathit{nonMaxSuppression} &= 1 \end{align*}

实现

FAST 算法对输入图像的所有像素执行角点检测测试。该算法最初在 [1] 中描述,后来在 [2] 中得到改进。如果中心像素周围一定数量的连续像素比它更亮或更暗,则该像素被检测为角点。

FAST 算法将中心候选像素 \( p \) 周围的像素定义为位于半径为 \( R \) 的 Bresenham 圆 \( x \in \{1...M\} \) 上的像素,该圆由函数 \( B(R, p) \) 生成。下图显示了一个候选像素(黄色)及其 Bresenham 圆(橙色)的示例,其中 \( R = 3 \),因此包含 \( M = 16 \) 个像素。圆半径 \( R \) 是算法的一个参数 (VPIFASTCornerDetectorParams::circleRadius),它唯一地定义了中心像素周围的 \( M \) 个像素。

中心像素的强度用 \( I_p \) 表示,圆上的像素强度用 \( I_{p\rightarrow x} \) 表示。圆上的每个像素可以有三种状态之一:\(\text{更亮}\);\(\text{更暗}\);或 \(\text{相似}\)。圆上像素的状态用 \( S_{p\rightarrow x} \) 表示。FAST 算法测试圆中至少 \( N \) 个连续像素(称为弧)是否具有相同的状态,即分别比候选像素“更亮”或“更暗”,加上或减去阈值 \( t \)。以下公式总结了这些概念

\begin{align*} S_{p\rightarrow x} &= \begin{cases} \text{brighter} &I_p + t \geq &I_{p\rightarrow x} & \\ \text{darker} & &I_{p\rightarrow x} \leq &I_p - t \\ \text{similar} &I_p - t < &I_{p\rightarrow x} < &I_p + t \\ \end{cases} \\ I_{p\rightarrow x} &= B(R, p) \end{align*}

下图显示了一个候选像素(黄色)及其周围圆弧(红色)的示例,其中 \( N = 9 \)。弧长 \( N \) 和强度阈值 \( t \) 是算法的参数(分别为:VPIFASTCornerDetectorParams::arcLengthVPIFASTCornerDetectorParams::intensityThreshold)。

FAST 算法还提供了一个辅助测试来移除相邻角点,称为非极大值抑制。如果非极大值抑制参数标志 (VPIFASTCornerDetectorParams::nonMaxSuppression) 开启,则每个被检测为角点的像素都会检查其紧邻的 1-邻域中是否有另一个像素也被检测为角点。如果 2 个或更多相邻像素被标记为角点,则每个像素都会被分配一个分数 \( V \),作为使其保持为角点的最大阈值。具有最大分数 \( V \) 的像素通过测试,即保持为角点,而其他像素则不再是角点。这有效地减少了找到的关键点角点。此辅助测试降低了 FAST 算法的性能。

C API 函数

有关实现该算法的限制、约束和后端列表,请查阅以下函数的参考文档

函数描述
vpiInitFASTCornerDetectorParams 使用默认值初始化 VPIFASTCornerDetectorParams
vpiSubmitFASTCornerDetector 向流提交 FAST 角点检测器 操作。

用法

语言
  1. 导入 VPI 模块
    import vpi
  2. 在输入图像上使用 CPU 后端运行 FAST 角点检测器算法。
    with vpi.Backend.CPU
    corners = input.fastcorners()
  3. (可选)检索找到的第一个角点位置。
    1. 锁定输出角点数组以高效访问其内容。
      with corners.rlock_cpu() as corners_data
    2. 检索第一个角点位置的坐标。(x, y) 坐标被交换为 (y, x) 并转换为元组。这等效于矩阵中的 (i, j) 位置,适用于 2D numpy 数组索引。
      corners_loc = tuple(corners_data[0].astype(int)[::-1])
  1. 初始化阶段
    1. 包含定义 FAST 算法函数和参数结构的头文件。
      声明实现 FAST 角点支持的函数。
    2. 定义输入图像对象。
      VPIImage input = /*...*/;
      struct VPIImageImpl * VPIImage
      图像的句柄。
      定义: Types.h:256
    3. 创建输出数组,该数组将存储带有 FAST 角点的关键点。输出数组容量控制要找到的最大角点数。在此示例中,输出数组容量设置为 \( 1000 \)。
      VPIArray corners;
      VPIStatus vpiArrayCreate(int32_t capacity, VPIArrayType type, uint64_t flags, VPIArray *array)
      创建空数组实例。
      struct VPIArrayImpl * VPIArray
      数组的句柄。
      定义: Types.h:232
      @ VPI_ARRAY_TYPE_KEYPOINT_F32
      VPIKeypointF32 元素。
    4. 创建将在其中提交算法以供执行的流。
      VPIStream stream;
      vpiStreamCreate(0, &stream);
      struct VPIStreamImpl * VPIStream
      流的句柄。
      定义: Types.h:250
      VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
      创建流实例。
  2. 处理阶段
    1. 使用用户提供的参数初始化参数结构。在此示例中,参数设置为反映上面的输出,即 \( R = 3, N = 9, t = 142, NMS = 1 \)。
      params.circleRadius = 3;
      params.arcLength = 9;
      params.intensityThreshold = 142;
      params.nonMaxSuppression = 1;
      float intensityThreshold
      选择像素作为关键点候选点周围圆弧一部分的阈值。
      int32_t arcLength
      圆弧上用于检查中心像素是否为角点的弧长(像素为单位)。
      int8_t nonMaxSuppression
      是否应用非极大值抑制来移除过于靠近的角点。
      int32_t circleRadius
      像素周围的圆半径,用于检查像素是否为角点。
      VPIStatus vpiInitFASTCornerDetectorParams(VPIFASTCornerDetectorParams *params)
      使用默认值初始化 VPIFASTCornerDetectorParams。
      定义 vpiSubmitFASTCornerDetector 参数的结构体。
    2. 将算法及其参数提交到流。它将由 CPU 后端执行。在此示例中,边界 limited 用于忽略图像边界附近的像素。
      VPIStatus vpiSubmitFASTCornerDetector(VPIStream stream, uint64_t backend, VPIImage input, VPIArray outCorners, const VPIFASTCornerDetectorParams *params, VPIBorderExtension border)
      向流提交 FAST 角点检测器操作。
      @ VPI_BACKEND_CPU
      CPU 后端。
      定义: Types.h:92
      @ VPI_BORDER_LIMITED
      将图像视为有限,不访问外部像素。
      定义: Types.h:282
    3. (可选)等待直到处理完成。
      vpiStreamSync(stream);
      VPIStatus vpiStreamSync(VPIStream stream)
      阻塞调用线程,直到此流队列中的所有提交命令都完成(队列为空)。
  3. 清理阶段
    1. 释放流、输入图像和输出数组所持有的资源。
      vpiArrayDestroy(corners);
      void vpiArrayDestroy(VPIArray array)
      销毁数组实例。
      void vpiImageDestroy(VPIImage img)
      销毁图像实例。
      void vpiStreamDestroy(VPIStream stream)
      销毁流实例并释放所有硬件资源。

有关更多信息,请参阅 VPI - 视觉编程接口 的“C API 参考”部分中的 FAST 角点

性能

有关如何使用下表性能表的信息,请参阅 算法性能表
在比较测量结果之前,请查阅 比较算法运行时间
有关性能基准测试方式的更多信息,请参阅 性能基准

 - 

参考文献

  1. E. Rosten, T. Drummond (2006), "Machine learning for high speed corner detection"(用于高速角点检测的机器学习)
    in 9th European Conference on Computer Vision, vol. 1, pp. 430-443(第九届欧洲计算机视觉会议,第 1 卷,第 430-443 页)
  2. E. Rosten, R. Porter, T. Drummond (2010), "Faster and better: a machine learning approach to corner detection"(更快更好:一种用于角点检测的机器学习方法)
    in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 32, pp. 105-119(IEEE 模式分析与机器智能汇刊,第 32 卷,第 105-119 页)