图形/仿真

光流 SDK 3.0 的新增功能

NVIDIA 图灵架构引入了一种新的硬件功能,用于以非常高的性能计算一对图像之间的光流。 NVIDIA 光流 SDK 公开了使用这种光流硬件(也称为 NVOFA )加速应用程序的 API 。我们很高兴地宣布光流 SDK 3 . 0 的可用性具有以下新功能:

  1. DirectX 12 光流 API
  2. 通过单个 API 的前后向光流
  3. 全球流动矢量

DirectX 12 光流 API

DirectX 12 是一个来自 Microsoft 的低级编程 API ,与它的前身 DirectX 11 相比,它减少了驱动程序开销。 DirectX 12 为开发人员提供了更大的灵活性和细粒度的控制。开发人员现在可以利用 DirectX 12 中的低级编程 API 并优化其应用程序,以提供比早期 DirectX 版本更好的性能—同时,客户端应用程序本身必须负责资源管理、同步, DirectX 12 在游戏和其他图形应用程序中迅速发展。

光流 SDK 3 . 0 支持 DirectX 12 应用程序使用 NVIDIA 光流引擎。计算出的光流可用于提高游戏和视频中的帧速率,以获得更平滑的体验或用于目标跟踪。为了提高帧速率, F rame R ate U p C onversion ( FRUC )技术通过在原始帧之间插入插值帧来使用。插值算法使用帧对之间的流来生成中间帧。

光流硬件的所有代支持 DirectX 12 光流接口。光流 SDK 包包含头( S )、演示使用的示例应用程序、可根据需要重新使用或修改的 C ++包装类和文档。用于访问光流硬件的所有其他组件都包含在 NVIDIA 显示驱动程序中。 Windows 20H1 或更高版本的操作系统支持 DirectX 12 光流 API 。

除了显式同步之外, directx12 光流 API 的设计与 SDK 中已有的其他接口( CUDA 和 DirectX 11 )非常接近, DirectX 12 光流 API 由初始化、流量估计和销毁三个核心功能组成。

typedef NV_OF_STATUS(NVOFAPI* PFNNVOFINIT) (NvOFHandle hOf, const NV_OF_INIT_PARAMS* initParams);

typedef NV_OF_STATUS(NVOFAPI* PFNNVOFEXECUTED3D12) (NvOFHandle hOf, const NV_OF_EXECUTE_INPUT_PARAMS_D3D12* executeInParams, NV_OF_EXECUTE_OUTPUT_PARAMS_D3D12* executeOutParams);

typedef NV_OF_STATUS(NVOFAPI* PFNNVOFDESTROY) (NvOFHandle hOf);

初始化和销毁 API 在所有接口上都是相同的,但在 DirectX 12 和其他接口(即 DirectX 11 和 CUDA )之间执行 API 是不同的。尽管在 DirectX 12 中传递给 executeapi 的大多数参数与其他两个接口中的参数相同,但在功能上还是存在一些差异。 DirectX 11 和 CUDA 接口中的同步由操作系统运行时和驱动程序自动处理。但是,在 DirectX 12 中,需要有关围栏和围栏值的附加信息作为执行 API 的输入参数。这些围栏对象将用于同步 CPU ↔ GPU 和 GPU ↔ GPU 操作。有关详细信息,请参阅光流 SDK 附带的编程指南。

DirectX 12 中的缓冲区管理 API 接口也需要 fence 对象来进行同步。

所有接口的光流输出质量相同。与其他两个接口相比, DirectX 12 的性能应该非常接近。

正反向光流

没有一种光流算法能给出 100% 的准确流量。在闭塞区域,流动通常是扭曲的。有时, NVOA 提供的成本也可能不代表流动的真实可信度。通常采用的一个简单检查是比较向前和向后流动。如果正向流和反向流之间的欧氏距离超过阈值,则该流可以标记为无效。

为了估计两个方向上的流,客户机必须调用 Execute API 两次:一次调用输入和引用图像,第二次调用在反转输入和引用图像之后。像这样两次调用 Optical Flow Execute API 可能会由于上下文切换、线程切换等开销而导致性能不佳。 Optical Flow sdk3 . 0 公开了一个新的 API ,以便在单个 Execute 调用中生成双向流。可以通过在初始化中设置 NV_OF_INIT_PARAMS::predDirection to NV_OF_PRED_DIRECTION_BOTH 并在 NV_OF_EXECUTE_OUTPUT_PARAMS/NV_OF_EXECUTE_OUTPUT_PARAMS_D3D12::bwdOutputBuffer, NV_OF_EXECUTE_OUTPUT_PARAMS/NV_OF_EXECUTE_OUTPUT_PARAMS_D3D12::bwdOutputCostBuffer .   中提供接收反向流和/或开销所需的缓冲区来启用此功能

图 1 .源图像 (http :// ultravideo . fi /# testsequences)
NVIDIA Optical Flow
( b ) 正向流动,( c )反向流动,( d )一致性检查。图像中的黑色像素显示不一致的流,( e )最近邻填充

一旦在两个方向上生成流,客户端应用程序就可以比较两个方向的流向量,根据适当的标准(例如,向前和向后流向量之间的欧几里德距离)丢弃不准确的流向量,并使用孔填充算法来填充这些丢弃的流向量。

注意,由于一些优化, FB 流的输出质量可能不同于单向流。

演示 FB flow API 编程和一致性检查的示例代码:

// Initialization of API
NV_OF_INIT_PARAMS initParams = { 0 };
...
initParams.predDirection = NV_OF_PRED_DIRECTION_BOTH;
...
NvOFAPI->nvOFInit(hNvOF, &initParams);
// Estimation of forward and backward flow
NV_OF_EXECUTE_INPUT_PARAMS executeInParams = { 0 };
...
NV_OF_EXECUTE_OUTPUT_PARAMS executeOutParams = { 0 };
...
executeOutParams.outputBuffer = forwardFlowBuffer;
executeOutParams.outputCostBuffer = forwardFlowCostBuffer;
executeOutParams.bwdOutputBuffer = backwardFlowBuffer;
executeOutParams.bwdOutputCostBuffer = backwardFlowCostBuffer;

NvOFAPI->nvOFExecute(hNvOF, &executeInparams, &executeOutParams)


// Invalidating flow vectors
for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
        // read forward flow vector
        float mvx = GetFlowX(forwardFlowBuffer, x, y);
        float mvy = GetFlowY(forwardFlowBuffer, x, y);

        // derive the corresponding position in the backward flow (assuming 1x1 grid size)
        // and read the backward flow vector
        int x2 = x + mvx;
        int y2 = y + mvy;
        if (x2 < 0 || x2 > width - 1 || y2 < 0 || y2 < height - 1)
        {
            SetFlowInvalid(forwardFlowBuffer, x, y);
            continue;
        }
        float mvx2 = -1 * GetFlowX(backwardFlowBuffer, x2, y2);
        float mvy2 = -1 * GetFlowY(backwardFlowBuffer, x2, y2);

        // mark flow vector as invalid if the distance is greater than a threshold
        if (((mvx - mvx2) * (mvx - mvx2) + (mvy - mvy2) * (mvy - mvy2)) > thresh) {
            SetFlowInvalid(forwardFlowBuffer, x, y);
        }
    }
}

全球流量估算

视频序列或游戏中的全局流是由摄影机平移运动引起的。全局流估计是一个重要的工具,广泛应用于图像分割、视频拼接或基于运动的视频分析应用中。

全局流矢量也可以启发式地用于计算背景运动。一旦估计出背景运动,它就可以用来填充遮挡区域中的流矢量,也可以用来处理插值帧中扭曲像素的碰撞。

全局流量是基于发生频率和其他一些启发式算法,在前向流矢量上计算的。

为了能够生成全局流,初始化 API 需要设置标志 初始化参数的 NV \ u :: enableGlobalFlow ,并在 executeapi 中提供额外的缓冲区 NV _ OF _ EXECUTE _ OUTPUT _ PARAMS / NV _ OF _ EXECUTE _ OUTPUT _ PARAMS _ D3D12 ::全局流缓冲区

参考

  1. NVIDIA 光流 SDK
  2. 开发者博客: NVIDIA 光流 SDK 简介
  3. 开发者博客: 用 NVIDIA 图灵 GPU s 加速 OpenCV :光流算法

 

Tags