概述
稠密光流算法估计前后帧之间每个 4x4 像素块中的运动矢量。它的用途包括运动检测和物体跟踪。
下面的输出表示 HSV 颜色空间中的每个矢量,其中色调与运动方向相关,值与速度成正比。
输入 | 输出运动矢量 |
|
|
实现
该算法分析两张图像(前一帧和当前帧)的内容,并将运动估计写入输出图像。
如下所示,该算法将输入图像分割成 4x4 像素块。然后,对于每个块,它估计从前一帧到当前帧的内容平移,并将估计值作为运动矢量写入输出图像中的对应像素。
2D 运动矢量表示为 X,Y 坐标对,每个坐标采用 S10.5 有符号定点格式,如下所示
S10.5 格式和浮点格式之间的转换如下所示
\begin{align*} S_{10.5} &= \lfloor F \times 32 \rfloor \\ F &= \lfloor S_{10.5} / 32 \rfloor \end{align*}
C API 函数
有关实现该算法的限制、约束和后端的列表,请查阅以下函数的参考文档
用法
语言
- 导入 VPI 模块
- 获取第一帧。
prevImage = inVideo.read()[1]
- 获取下一帧。
while inVideo.read(curImage)[0]
- 使用 OFA 后端执行算法,将前一帧和当前帧传递给它。
with vpi.Backend.OFA
motion = vpi.optflow_dense(prevImage, curImage)
- 通过将当前帧分配给前一帧,为下一次迭代做准备。
- 初始化阶段
- 包含定义所需函数和类型的头文件
- 创建将在其中提交算法以供执行的流
struct VPIStreamImpl * VPIStream
流的句柄。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
- 定义具有块线性内存布局的运动矢量图像。运动矢量采用 [x, y] 形式,表示估计的平移,两个坐标均采用 S10.5 格式。输出维度计算时考虑到一个 4x4 输入像素块对应一个输出矢量
int32_t mvWidth = (width + 3) / 4;
int32_t mvHeight = (height + 3) / 4;
struct VPIImageImpl * VPIImage
图像的句柄。
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用指定的标志创建空的图像实例。
- 创建负载以包含临时缓冲区。负载配置为由 OFA 后端处理
int32_t gridSize = 4;
VPI_CHECK_STATUS(
VPIStatus vpiCreateOpticalFlowDense(uint64_t backends, int32_t width, int32_t height, VPIImageFormat inputFmt, const int32_t *gridSize, int32_t numLevels, VPIOpticalFlowQuality quality, VPIPayload *payload)
为 vpiSubmitOpticalFlowDense 创建负载。
struct VPIPayloadImpl * VPIPayload
算法负载的句柄。
- 获取第一帧
- 处理阶段
- 从第二帧开始处理循环
for (int idframe = 1; idframe < frame_count; ++idframe)
{
- 获取当前帧
- 提交算法。该算法必须将前一帧和当前帧都馈送到 NVIDIA 编码器引擎,并为每个 4x4 像素块生成运动矢量
VPIStatus vpiSubmitOpticalFlowDense(VPIStream stream, uint64_t backend, VPIPayload payload, VPIImage prevImg, VPIImage curImg, VPIImage mvImg)
在两帧上运行稠密光流,输出运动矢量。
- (可选)如果不再有任务要提交到流,请等待直到流完成处理。同步完成后,您可以使用在此迭代中计算的输出运动矢量
VPIStatus vpiStreamSync(VPIStream stream)
阻塞调用线程,直到此流队列中所有提交的命令都完成(队列为空)。。。
- 交换前一帧和当前帧,以便当前帧成为下一次迭代的前一帧
prevImage = curImage;
curImage = tmpImg;
}
- 清理阶段
- 释放流、负载以及输入和输出数组所持有的资源
void vpiImageDestroy(VPIImage img)
销毁图像实例。
void vpiPayloadDestroy(VPIPayload payload)
释放负载对象和所有关联的资源。
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
请查阅 稠密光流 示例以获取完整示例。
有关更多信息,请参阅 VPI - 视觉编程接口 的 “C API 参考” 部分中的 稠密光流。
性能
有关如何使用下表中的性能信息,请参阅 算法性能表。
在比较测量结果之前,请查阅 比较算法运行时间。
有关性能基准测试方式的更多信息,请参阅 性能基准。
-