概述
金字塔 Lucas-Kanade (LK) 光流算法估计从前一帧到下一帧的稀疏特征点的 2D 平移。图像金字塔用于提高在大平移上跟踪的性能和鲁棒性。
输入是先前的图像金字塔、下一个图像金字塔以及先前图像上的特征点。
输出是下一个图像上的特征点以及每个特征点的跟踪状态。
帧 #10
实现
每个特征点使用 x、y 坐标定义其在图像中的位置。然后在下一张图像中跟踪这些点。跟踪状态将告知特征点是否被成功跟踪。有关更多信息,请参阅 [1] 和 [2] 。
C API 函数
有关实现该算法的限制、约束和后端的列表,请查阅以下函数的参考文档
用法
语言
C/C++
Python
导入 VPI 模块
初始化阶段
创建金字塔光流 LK 对象,向其馈送初始帧和包含要跟踪的关键点的 VPI 数组。 CUDA 后端将用于执行该算法。with vpi.Backend.CUDA
optflow = vpi.OpticalFlowPyrLK(frame, curFeatures, 4)
处理阶段
从输入视频序列中获取新帧到 VPI 图像中。while inVideo.read(input)[0]
将此 VPI 图像馈送到 OptFlow 对象中。 我将返回传递帧中估计的关键点位置,以及告知关键点状态的向量,即它是否正在被跟踪。curFeatures, status = optflow(input)
初始化阶段
包含定义所需函数和结构的头文件。
创建算法将在其中提交执行的流。
struct VPIStreamImpl * VPIStream
流的句柄。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
定义所需的图像、金字塔和数组
struct VPIArrayImpl * VPIArray
数组的句柄。
struct VPIImageImpl * VPIImage
图像的句柄。
struct VPIPyramidImpl * VPIPyramid
图像金字塔的句柄。
创建将包含处理所需的所有临时缓冲区的负载。其参数取自所使用的输入金字塔和图像。 int levels;
float scale;
int width, height;
VPIStatus vpiImageGetFormat(VPIImage img, VPIImageFormat *format)
获取图像格式。
VPIStatus vpiImageGetSize(VPIImage img, int32_t *width, int32_t *height)
获取图像尺寸(以像素为单位)。
VPIStatus vpiCreateOpticalFlowPyrLK(uint64_t backends, int32_t width, int32_t height, VPIImageFormat fmt, int32_t levels, float scale, VPIPayload *payload)
为 vpiSubmitOpticalFlowPyrLK 创建负载。
struct VPIPayloadImpl * VPIPayload
算法负载的句柄。
VPIStatus vpiPyramidGetNumLevels(VPIPyramid pyr, int32_t *numLevels)
获取图像金字塔级别计数。
VPIStatus vpiPyramidGetScale(VPIPyramid pyr, float *scale)
返回金字塔级别的比例因子。
@ VPI_BACKEND_CUDA
CUDA 后端。
定义指导 LK 跟踪过程的配置参数。
VPIStatus vpiInitOpticalFlowPyrLKParams(uint64_t backends, VPIOpticalFlowPyrLKParams *params)
使用默认值初始化 VPIOpticalFlowPyrLKParams。
定义 vpiSubmitOpticalFlowPyrLK 参数的结构体。
处理阶段
从第二帧开始的处理循环。前一帧是算法从中获取特征点的帧,当前帧是在其上估计这些特征点的帧。 for (int idframe = 1; idframe < frame_count; ++idframe)
{
从输入视频中获取新帧。
使用 CUDA 后端为当前图像生成图像金字塔。VPI_CHECK_STATUS(
VPIStatus vpiSubmitGaussianPyramidGenerator(VPIStream stream, uint64_t backend, VPIImage input, VPIPyramid output, VPIBorderExtension border)
从输入图像计算高斯金字塔。
@ VPI_BORDER_CLAMP
边界像素无限重复。
提交算法以由 CUDA 后端执行。它将遍历所有输入特征点,并在下一张图像中找到估计的点和跟踪状态。用户将决定是继续使用跟踪的特征点还是重新生成一组新的特征点。在此示例中,跟踪的特征点被重用作为下一帧的输入。
VPIStatus vpiSubmitOpticalFlowPyrLK(VPIStream stream, uint64_t backend, VPIPayload payload, VPIPyramid prevPyr, VPIPyramid curPyr, VPIArray prevPts, VPIArray curPts, VPIArray trackingStatus, const VPIOpticalFlowPyrLKParams *params)
在两帧上运行金字塔 LK 光流。
等待直到处理完成。
VPIStatus vpiStreamSync(VPIStream stream)
阻止调用线程,直到此流队列中的所有提交命令完成(队列为空)。
为下一次迭代做准备。当前迭代的 *cur*
缓冲区将用作下一次迭代的 *prev*
缓冲区。
prevImage = curImage;
curImage = tmpImg;
pyrPrevFrame = pyrCurFrame;
pyrCurFrame = tmpPyr;
arrPrevPts = arrCurPts;
arrCurPts = tmpArray;
}
清理阶段
释放流、负载以及输入和输出数组所持有的资源。
void vpiArrayDestroy(VPIArray array)
销毁数组实例。
void vpiPayloadDestroy(VPIPayload payload)
释放负载对象和所有关联的资源。
void vpiPyramidDestroy(VPIPyramid pyr)
销毁图像金字塔实例以及它拥有的所有资源。
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
有关更多信息,请参阅“VPI - Vision Programming Interface ”的“C API 参考”部分中的 金字塔 LK 光流 。
性能
有关如何使用下表中的性能信息,请参阅 算法性能表 。 在比较测量结果之前,请查阅 比较算法运行时间 。 有关性能基准测试方式的更多信息,请参阅 性能基准 。
清除过滤器
设备
Jetson AGX Orin
- 流
1
2
4
8
参考
B. D. Lucas 和 T. Kanade (1981), "An iterative image registration technique with an application to stereo vision." Proceedings of Imaging Understanding Workshop, pages 121–130
J. Y. Bouguet, (2000), "Pyramidal implementation of the affine lucas kanade feature tracker description of the algorithm." Intel Corporation, Microprocessor Research Labs