VisionWorks快速入门--Graph Mode

2023-11-12


本教程的第一部分(VisionWorks快速启动(立即模式))展示了如何使用优化的VisionWorks立即模式函数替换几个耗时的OpenCV函数,从而提高video stabilization应用程序的性能。visionworks库实现openvx标准,还可以使用图形模式执行来使应用程序更快。

本教程的第二部分与第一部分一样基于“video stabilization”示例。算法和完整的代码包含在第一部分中;您还可以在其中找到visionworks即时模式的完整代码。本教程的第二部分将修改此代码,例如,与数据转换相关的代码行。本教程重点介绍立即模式和图形模式之间的区别。

原语可以通过两种方式执行:

基于graph的执行原语被实例化为graph节点。graph是提前构建、验证和优化的,并且可以在运行时多次执行而无需重新验证。基于graph的执行对于多次执行的视觉管道(例如处理视频流)是首选的,因为它提供了最佳的性能。
立即执行原语通过调用函数(前缀为vxu或nvxu)直接执行,类似于OpenCV或NPP执行模式。当基本设置开销不是一个大问题时,立即执行模型对于一次性处理非常有用。它也可以作为应用程序开发的中间步骤,比如移植使用opencv的应用程序时。

本节讨论这些模式之间的对应关系。每个立即模式功能都有相应的节点,例如:

Immediate mode Graph mode
vxuFastCorners() vxFastCornersNode()
nvxuFindHomography() nvxFindHomographyNode()

每个节点被附加到一个graph中,然后验证graph。每次算法迭代只调用vxProcessGraph()函数,即代码的很大一部分从负责算法执行的函数转换到负责初始化的函数。函数后面都加一个“node”

让我们看看本例子如何操作。

从立即模式过渡到图形模式

在每次迭代中按顺序调用以下函数:

vxuFastCorners();
vxuColorConvert();
vxuGaussianPyramid();
vxuOpticalFlowPyrLK();
nvxuFindHomography();
homography_smoother_->push();
homography_smoother_->getSmoothedHomography();
vxuWarpPerspective();

上面所有VISIONWORKS函数都存在对应的节点,但是两个用户函数在库中没有对应的节点。不可能画出一个有“洞”的图;它必须包含一个算法的连续部分。解决这个问题有两种方法:

  • 将算法分成两部分,由用户代码分隔。因此,第一部分包含与前五个函数相对应的节点,而第二个图仅包含一个节点(或者不创建单节点图并保留vxuWarpPerspective());

  • 实现用户节点(详细教程位于
    VisionWorks之用户自定义结点),所有中间代码都隐藏在其中。您可以创建一个包含所有必要节点的图。

我们选择第二个是因为它保持了设计的纯洁性和代码的可读性。

在转换描述之前,请注意一种VisionWorks数据类型。库中有一种特殊的数据类型,名为vx_delay。vx_delay是一个循环缓冲区。我们使用它来存储smoothing_window_size_ + 1个最近的图像、2 * smoothing_window_size_ + 1个单应矩阵、最新的 2个 grayscale frame和 最新的2个 金字塔。如您所见,使用此数据类型存储有关最后几帧的信息非常方便。

让我们将从立即模式到图形模式的转换划分为以下步骤:

  1. 创建新节点。

  2. 向GraphModestabilizer类添加新字段和函数。

  3. 初始化字段。

  4. 执行算法的迭代。

  5. Release objects。

1. 创建新节点。

我们必须将所有位于nvxuFindHomography()和vxuWarpPerspective()函数之间的代码包装到用户节点我们把它命名为homographySmootherNode。

新节点必须执行以下操作:

  • 将新的单应矩阵添加到(2 * smoothing_window_size_)矩阵的循环缓冲区中;

  • 对单应矩阵应用了更平滑的单应运算稳定映射。

由于节点不应该存储其状态,因此它必须采用高斯权重数组(也可以在每次迭代中计算)、单应矩阵缓冲区和新的单应矩阵。转换矩阵作为输出参数传递给节点。

代码在文件homography_smooler_node.hpp和homography_smooler_node.cpp中。

2. 向GraphModestabilizer类添加新字段和函数。

有些字段必须删除,有些要替换,有些要添加。特别是,不使用“宽度”和“高度”字段。它们只是创建图像所必需的,这些图像被添加到帧队列中。现在我们使用vx_delay代替std::queue,并且这种数据类型保存有关帧大小的信息。

替换字段有:

Immediate mode stabilizer Graph mode stabilizer
std::gueue<vx_image> frames vx_delay frames_delay_
vx_image gray_latest_frame_, vx_image gray_current_frame_ vx_delay gray_frames_delay_
vx_pyramid latest_pyr_, vx_pyramid current_pyr_ vx_delay pyr_delay_

仍然需要为HomographySmoother节点添加字段:

    vx_array gaussian_weights_;
    vx_delay homography_matrices_;

图的字段,即图及其节点:

    vx_graph main_graph_;
    vx_node fast_corners_node_;
    vx_node color_convert_node_;
    vx_node gaussian_pyramid_node_;
    vx_node opt_flow_node_;
    vx_node find_homography_node_;
    vx_node homography_smoother_node_;
    vx_node warp_perspective_node_;

我们添加了参数初始化和图形创建功能。

    void createMainGraph();
    vx_status initGaussianWeights();
    vx_status initHomographyMatrices();

3. 初始化字段。

与立即模式相比,有哪些初始化要做呢?新字段出现在类中,一些旧字段已更改,因此我们必须初始化它们。类字段之间有几个vx_delay对象。我们必须传递实例(例如,如果是图像的vx_delay,我们必须传递vx_image)和缓冲区大小来初始化vx_delay。vx_delay从delay-s元素读取元数据(图像大小和类型)。例如,frames_delay_ 初始化:

   frames_delay_ = vxCreateDelay(context_, (vx_reference)start_frame, params_.smoothing_window_size + 1);
    NVXIO_CHECK_REFERENCE(frames_delay_);
    NVXIO_SAFE_CALL(nvxuCopyImage(context_, start_frame, (vx_image)vxGetReferenceFromDelay(frames_delay_, 0)));

在initGaussianWeights()函数中初始化高斯权重数组:

vx_status GraphModeStabilizer::initGaussianWeights()
{
    vx_status status = VX_SUCCESS;
    vx_float32 sigma = (vx_float32)params_.smoothing_window_size * 0.7;
    vx_int32 num_items = 2 * (vx_int32)params_.smoothing_window_size + 1;
    std::vector<vx_float32> gaussian_weights_data;
    gaussian_weights_data.resize(num_items);
    vx_float32 sum = 0;
    for (vx_int32 i = 0; i < num_items; ++i)
    {
        gaussian_weights_data[i] = exp(-(i - (vx_float32)params_.smoothing_window_size) * (i - (vx_float32)params_.smoothing_window_size) / (2.f * sigma * sigma));
        sum += gaussian_weights_data[i];
    }
    //normalize weights
    assert((sum > 0.00000000001) || (sum < - 0.00000000001));
    vx_float32 scaler = 1.f / sum;
    for (vx_int32 i = 0; i < num_items; i++)
    {
        gaussian_weights_data[i] *= scaler;
    }
    status |= vxAddArrayItems(gaussian_weights_, (vx_size)num_items, (void *)&gaussian_weights_data[0], sizeof(gaussian_weights_data[0]));
    return status;
}

在initHomographyMatrices()函数中,用身份矩阵初始化单应矩阵的vx_delay:

vx_status GraphModeStabilizer::initHomographyMatrices()
{
    vx_status status = VX_SUCCESS;
    vx_float32 homography_data[3][3] = { {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f} };
    for (vx_size i = 0; i < 2 * params_.smoothing_window_size; i++)
    {
        status |= vxCopyMatrix((vx_matrix)vxGetReferenceFromDelay(homography_matrices_, -i), homography_data, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
    }
    return status;
}

graph的初始化:

void GraphModeStabilizer::createMainGraph()
{
    main_graph_ = vxCreateGraph(context_);
    fast_corners_node_ = vxFastCornersNode(main_graph_,
                                           (vx_image)vxGetReferenceFromDelay(gray_frames_delay_, -1),
                                           params_.s_fast_threshold,
                                           vx_true_e,
                                           points_,
                                           0);
    color_convert_node_ = vxColorConvertNode( main_graph_,
                                              (vx_image)vxGetReferenceFromDelay(frames_delay_, 0),
                                              (vx_image)vxGetReferenceFromDelay(gray_frames_delay_, 0));
    gaussian_pyramid_node_ = vxGaussianPyramidNode(main_graph_,
                                                   (vx_image)vxGetReferenceFromDelay(gray_frames_delay_, 0),
                                                   (vx_pyramid)vxGetReferenceFromDelay(pyr_delay_, 0));
    opt_flow_node_ = vxOpticalFlowPyrLKNode(main_graph_,
                                            (vx_pyramid)vxGetReferenceFromDelay(pyr_delay_, -1),
                                            (vx_pyramid)vxGetReferenceFromDelay(pyr_delay_, 0),
                                            points_,
                                            points_,
                                            corresponding_points_,
                                            VX_TERM_CRITERIA_BOTH,
                                            params_.s_opt_flow_epsilon,
                                            params_.s_opt_flow_num_iterations,
                                            params_.s_opt_flow_use_initial_estimate,
                                            params_.opt_flow_win_size);
    find_homography_node_ = nvxFindHomographyNode(main_graph_,points_,
                                                  corresponding_points_,
                                                  (vx_matrix)vxGetReferenceFromDelay(homography_matrices_, 0),
                                                  params_.homography_method,
                                                  params_.homography_ransac_threshold,
                                                  params_.homography_max_estimate_iters,
                                                  params_.homography_max_refine_iters,
                                                  params_.homography_confidence,
                                                  params_.homography_outlier_ratio,
                                                  NULL);
    registerHomographySmootherKernel(context_);
    homography_smoother_node_ = homographySmootherNode(main_graph_,
                                               gaussian_weights_,
                                               homography_matrices_,
                                               perspective_matrix_);
    warp_perspective_node_ = vxWarpPerspectiveNode(main_graph_,
                                                   (vx_image)vxGetReferenceFromDelay(frames_delay_, -params_.smoothing_window_size),
                                                   perspective_matrix_,
                                                   VX_INTERPOLATION_TYPE_BILINEAR,
                                                   stabilized_frame_);
    //
    // Graph verification
    // Note: This verification is mandatory prior to graph execution
    //
    NVXIO_SAFE_CALL(vxVerifyGraph(main_graph_));
}

4. 执行算法的迭代。

由于大多数算法都转换为图形创建,因此每个步骤只有4个操作:

  • 将当前帧添加到帧的循环缓冲区中;

  • 执行图形;

  • 缓冲区移动;

  • 返回稳定帧。

以下代码中显示了此操作序列

    NVXIO_SAFE_CALL(vxAgeDelay(homography_matrices_));
    NVXIO_SAFE_CALL(vxAgeDelay(pyr_delay_));
    NVXIO_SAFE_CALL(vxAgeDelay(gray_frames_delay_));
    NVXIO_SAFE_CALL(vxAgeDelay(frames_delay_));
    NVXIO_SAFE_CALL(nvxuCopyImage(context_, current_frame, (vx_image)vxGetReferenceFromDelay(frames_delay_, 0)));
    NVXIO_SAFE_CALL(vxProcessGraph(main_graph_));
    return stabilized_frame_;

5. Release objects。

GraphModeStabilizer::~GraphModeStabilizer()
{
    vxReleaseArray(&points_);
    vxReleaseArray(&corresponding_points_);
    vxReleaseArray(&gaussian_weights_);
    vxReleaseDelay(&homography_matrices_);
    vxReleaseMatrix(&perspective_matrix_);
    vxReleaseImage(&stabilized_frame_);
    vxReleaseDelay(&gray_frames_delay_);
    vxReleaseDelay(&pyr_delay_);
    vxReleaseDelay(&frames_delay_);
    vxReleaseGraph(&main_graph_);
};

结果

FastCorners : 0.544 ms
ColorConvert : 0.030 ms
BuildPyramid : 0.090 ms
OpticalFlow : 4.435 ms
FindHomography : 1.295 ms
HomographySmoother : 0.019 ms
WarpPerspective : 0.146 ms
TOTAL : 6.766 ms

这个版本比以前快了5%,立即模式和graph模式的性能优化主要在于,graph模式不需要在执行过程中对内存分配以及内存的复制。

从开发流程上来说最好是先使用opencv或者立即模式开发算法流程,测试处理流程没问题了然后再移植到graph模式下,最大程度的优化性能。这个处理算法不算复杂,所以性能提供有限,对于一些节点可以并行执行的更复杂算法,可以获得更大的性能增益。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VisionWorks快速入门--Graph Mode 的相关文章

  • 博客要写得好,Emoji要用对!

    EMOJI 01 表情与心情 02 动作与身份 03 动物与植物 04 食品与饮料 05 旅行和地点 06 娱乐与活动 07 物品与工具 08 符号与标识 01 表情与心情 02 动作与身份
  • 华为OD机试 - 最差产品奖( Python)

    题目描述 A公司准备对他下面的N个产品评选最差奖 评选的方式是首先对每个产品进行评分 然后根据评分区间计算相邻几个产品中最差的产品 评选的标准是依次找到从当前产品开始前M个产品中最差的产品 请给出最差产品的评分序列 输入描述 第一行 数字M
  • 手把手教你,把3D模型从stl格式导出iges格式的方法

    工具 Hypermesh 注意 下载和安装视频在我的上传资源里面 记得安装路径不能有中文 自己的操作账户名也不能是中文的 方法 第一 按照如下步骤 导入stl模型 第二步 点击Shaded 按钮 显示实体网格 第三步 点击Geom下的sur
  • 自己搭的12V 电机驱动电路设计

    1 单MOS管驱动电路 采用P75NF75为主角构成 2 双MOS管电机驱动电路设计 采用D4184管组合 3 半桥驱动电路设计 采用BTS7960芯片 两路半桥构成全桥驱动电路
  • s3c6410 android 移植Step by step

    Report 2009 03 05 转载请说明出处 不得用于商业用途 Linux forum id hongjiujing Porting android on s3c6410 Environment ubuntu 8 10 Board X
  • KeilMDK编译错误Error: L6218E: Undefined symbol __aeabi_assert (referred from xxx.o).

    问题描述 AirPressure AirPressure axf Error L6218E Undefined symbol aeabi assert referred from mbrtu o 问题原因 Error L6218E Unde
  • 爬虫乱码UnicodeEncodeError: ‘gbk’ codec can’t encode character ‘\xa0’ in position

    在Python中将网址写入文件的时候 会碰到 UnicodeEncodeError gbk codec can t encode character xa0 in position 0这个问题 其实就是在windows中 新建的文本文件的默
  • Connecting the Dots: 基于图神经网络的多元时间序列预测——学习合集

    关于源代码和数据集的理解可以参考以下几篇文章 1 github源代码 数据集 安装环境要求 2 原论文百度云链接 提取码 1234 3 帮助理解论文的文章1 4 帮助理解论文的文章2 5 帮助理解论文的文章3 6 交通流量预测数据集解读 7
  • UnityVR--小程序8--激光门伤害

    本文使用Line Renderer组件 在门框中画出一道激光线 被线照射到的主角将会扣分 另外 激光仅检测ragCast层 所以主角必须添加到ragCast层中 与坦克对战小程序 UnityVR 小程序7 坦克对战 的设置相同 1 在场景中
  • MySQL多表查询 (超详细)

    一 多表关系 项目开发中 在进行数据库表结构设计时 会根据业务需求及业务模块之间的关系 分析并设计表结构 由于业务之间相互关联 所以各个表结构之间也存在着各种联系 基本上分为三种 一对多 多对一 多对多 一对一 1 1 一对多 案例 部门与
  • 在线算法(online algorithm)--竞争性分析

    文章目录 一 Problem Setting 1 1 competitve analysis 1 2 page replacement 二 Deterministic Online Algorithms 2 1 deterministic
  • 穆土 的学习和生活网站

    前端学习 哔哩哔哩 哔哩哔哩中有很多的 up 主 都有学习的资源 你可以学到等多东西 个人关注的 up 主 pink 老师 黑马培训的一位老师 他带领了很多人进入了前端的领域 我看他的 html css js 的入门商品 珠峰培训官方 周萧
  • 任意版本pytorch-gpu环境搭建方法

    任意版本pytorch gpu环境搭建方法 tortorish的博客 CSDN博客 网上关于pytorch gpu环境搭建的教程非常多 但若在国内 直接使用pytorch官网上的命令 经常会遇到下载过慢的情况 而若使用清华源 阿里源等网站
  • WindowBuilder for Eclipse 3.7

    http download eclipse org windowbuilder WB integration 3 7 MyEclipse10 7 1和MyEclipse10 7的下载地址 http downloads myeclipseid
  • 深聊自动化测试之:10年小鱼给你10条建议,让你在自动化界占据一个墙角

    10年小鱼的自动化建议 1 哪一刻 让你想起了自动化 1 1 执行回归测试 1 2 压测场景执行并发 1 3 UI稳定 接口不断升级 2 七问 是否了解自动化风险 2 1 团队成员的资历 2 2 自动化成本投入产出比 2 3 慎重对待UI级
  • Python中eval()函数的使用

    今天给大家分享一下Python中的eval 函数 如果感觉博主的文章还不错的话 希望大家点赞支持一下博主 文章目录 eval 函数 语法 实例 实例1 实例2 实例3 eval 函数 eval 函数用来执行一个字符串表达式 并返回表达式的值
  • 【Spring传播机制底层原理】

    一 Spring的事务传播机制 Spring的事务传播机制是Spring框架中最核心的机制之一 它能够灵活地控制多个事务方法的执行顺序 提交或回滚等行为 在Spring中 事务是通过TxManager来管理的 TxManager是一个接口
  • Hyper-V:无法打开虚拟机,因为虚拟机监控程序未运行

    管理员权打开 cmd 窗口 输入 bcdedit set hypervisorlaunchtype Auto 前提是机器已经开启了 虚拟化和开启了虚拟机监控程序
  • kafka 应用实战

    一 Java 中使用 kafka 进行通信 依赖

随机推荐

  • 孟岩谈通证(11):通证所代表的多维价值观

    通证Token都有那些多维价值观呢 我还是你举一个特别具体的例子来说明 我有一个朋友他开了一个社区 是专门做中小学教育课外辅导老师之间交流的 社区里大家互相交换教学资料 试题等等材料 你说这个东西有没有价值 教书育人 然后帮助孩子们成长 这
  • ssh远程连接Ubuntu(局域网和非局域网)

    文章目录 前言 1 局域网 远程连接 2 非局域网 远程连接 3 Zerotier常用命令 4 远程桌面控制 总结 前言 我们通常使用ssh连接虚拟机中的Ubuntu 方便学习 但是当在项目中遇到远程控制主机的时候 发现ssh连接不到外网主
  • Vue中实现电子围栏/围栏(高德地图)功能:

    1 思路 大部分与车辆轨迹相同 1 先获取key gt 官网 https lbs amap com ref https console amap com 2 下载并导入依赖 npm install vue amap S 3 使用 2 官网
  • 加速乐-AAencode-ob混淆

    加速乐 AAencode ob混淆 多层响应 Cookie 逆向 前言 本次案例是对加速乐 AAEncode OB 混淆方式的破解 破解出多层响应 Cookie 逆向 声明 本文章中所有内容仅供学习交流 相关链接做了脱敏处理 若有侵权 请联
  • Eclipse安装LomBok插件

    1 使用LomBok的好处在于实体类不用手动去生成set get方法了 类会在编译时自动生成 是代码简洁节省工作量 2 maven项目的pom文件添加坐标下载
  • 程序员进阶架构师的必备——思维导图

    架构师是什么 要做什么 架构师 是一个既需要掌控整体又需要洞悉局部瓶颈并依据具体的业务场景给出解决方案的团队领导型人物 架构师不是一个人 他需要建立高效的体系 带领团队去攻城略地 在规定的时间内完成项目 1 确认需求 架构师要懂得用户需求
  • 什么是面向对象思想

    面向对象是一种思想 是基于面向过程而言的 就是说面向对象是将功能等通过对象来实现 将功能封装进对象之中 让对象去实现具体的细节 这种思想是将数据作为第一位 而方法或者说是算法作为其次 这是对数据一种优化 操作起来更加的方便 简化了过程 面向
  • 人工智能作业homework2--------A*算法解决八数码

    1 启发式搜索算法A 启发式搜索算法A 一般简称为A算法 是一种典型的启发式搜索算法 其基本思想是 定义一个评价函数f 对当前的搜索状态进行评估 找出一个最有希望的节点来扩展 评价函数的形式如下 f n g n h n 其中n是被评价的节点
  • 全网最详细中英文ChatGPT接口文档(五)30分钟快速入门ChatGPT——手把手示例教程:如何建立一个人工智能回答关于您的网站问题,小白也可学

    30分钟开始使用ChatGPT Models模型 How to build an AI that can answer questions about your website 如何建立一个人工智能 回答有关您的网站的问题 Getting
  • 整理了27个Python人工智能库,建议收藏

    为了大家能够对人工智能常用的 Python 库有一个初步的了解 以选择能够满足自己需求的库进行学习 对目前较为常见的人工智能库进行简要全面的介绍 1 Numpy NumPy Numerical Python 是 Python的一个扩展程序库
  • ssd m.2接口详解

    ssd有两种接口 一种是sata 一种是m 2 这里主要深入讲解一下m 2接口的ssd 1 ssd 尺寸与规格 我们在买ssd的时候 商家都会说什么ssd是2280还是2242规格的 这里的规格实际上就是代表的ssd的大小 M 2模组的尺寸
  • pytrch手写数字识别

    使用Pytorch实现手写数字识别 目标 知道如何使用Pytorch完成神经网络的构建 知道Pytorch中激活函数的使用方法 知道Pytorch中torchvision transforms中常见图形处理函数的使用 知道如何训练模型和如何
  • Unity:利用 射线Ray 检测物体

    利用 射线Ray 检测物体 Unity射线 Ray 是通过发射一条射线来检测碰撞体或触发器 不带碰撞器组件的物体时无法检测的 可以在物理设置里取消检测触发器 Edit Project Setting Physics Physics2D Ph
  • Spring Boot中的Dozer和MapStruct比较

    Spring Boot中的Dozer和MapStruct比较 在Java开发中 数据对象之间的转换是一个常见的任务 Spring Boot作为一个流行的Java框架 提供了多种方式来处理对象之间的转换 两个常用的工具是Dozer和MapSt
  • call、apply、bind方法详解

    1 每个函数都包含两个非继承而来的方法 call 方法和apply 方法 2 相同点 这两个方法的作用是一样的 只是传参方式不一样而已 call 方法使用 window msg 1 document msg 2 var log msg 3
  • springboot 如何修改控制台输出的图案

    如图 操作步骤 1 在项目的resource文件夹下 新建一个文件命名为banner txt 2 进入网站 http patorjk com software taag p display h 0 v 0 f Big t SpringBoo
  • Spring WebSocket通信应用

    文章目录 前言 一 客户端 服务端双向通信交互图 二 项目说明 1 引入包 2 项目各模块说明 问题 参考 前言 本文章主要记录项目客户端 服务端双向通信解决方案 基于Spring WebSocket架构实现双向数据通信 以及项目实际应用中
  • 【SQLAlchemy】第二篇——连接失效及连接池

    一 背景 为了节约资源 MySQL会对建立的连接进行监控 当某些连接处于不活跃状态的时间超过一个阈值时 则关闭它们 用户可以执行show variables like wait timeout 来查看这个阈值 可以看到 在默认的情况下 这个
  • 04-8_Qt 5.9 C++开发指南_QTableWidget的使用

    文章目录 1 QTableWidget概述 2 源码 2 1 可视化UI设计 2 2 程序框架 2 3 qwintspindelegate h 2 4 qwintspindelegate cpp 2 5 mainwindow h 2 6 m
  • VisionWorks快速入门--Graph Mode

    VisionWorks快速入门 Graph Mode 从立即模式过渡到图形模式 1 创建新节点 2 向GraphModestabilizer类添加新字段和函数 3 初始化字段 4 执行算法的迭代 5 Release objects 结果 本