OpenCV 4.12.0
开源计算机视觉
加载中...
搜索中...
无匹配项
高级设计概述

G-API 高级设计概述

G-API 是一个异构框架,提供了一个统一的 API 来编程具有多个支持后端的图像处理流水线。

关键的设计思想是保持流水线代码本身与平台无关,同时在图编译(配置)时使用额外的参数指定要使用的内核以及要使用的设备。 这个要求导致了以下架构

G-API 框架架构

此架构中有三层

  • API 层 – 这是顶层,实现了 G-API 公共接口、其构建块和语义。 当用户使用 G-API 构建流水线时,他直接与此层交互,用户操作的实体(例如 cv::GMatcv::GComputation)由此层提供。
  • 图编译器层 – 这是中间层,它将用户计算展开到图中,然后对其应用多个转换(例如优化)。 这一层建立在 ADE 框架之上。
  • 后端层 – 这是最低层,其中列出了多个后端。 与上述两层相比,后端与底层平台细节高度耦合,每个后端都代表每个平台。 后端处理经过处理的图(来自图编译器),并针对特定平台或设备以最佳方式执行该图。

API 层

API 层是用户在定义和使用流水线(G-API 术语中的计算)时与之交互的层。 API 层定义了一组 G-API 动态对象,这些对象可以用作图中的输入、输出和中间数据对象

API 层指定了一组对这些数据对象定义的操作 – 称为内核。 有关 G-API 默认提供的操作的详细信息,请参见 G-API coreimgproc 命名空间。

G-API 不仅限于这些操作 – 用户可以使用特殊宏 G_TYPED_KERNEL() 轻松定义自己的内核。

API 层还负责在流水线创建时编组和存储操作参数。 除了上述 G-API 动态对象外,操作还可以接受任意参数(有关此内容的更多信息请参见 此处),因此 API 层会在执行时捕获其值并在内部存储。

最后,cv::GComputationcv::GCompiled 是 API 层的其余重要组件。 前者将一系列 G-API 表达式包装到一个对象(图)中,后者是图编译的产物(有关详细信息,请参见 本章)。

图编译器层

每个 G-API 计算在执行之前都会被编译。 编译过程以两种方式触发

对于预先不知道输入数据格式的情况,建议使用第一种方法 – 例如,当它来自任意输入文件时。 对于输入数据特征通常是预定义的部署(生产)场景,建议使用第二种方法。

图编译过程建立在 ADE 框架之上。 最初,从 API 层捕获的表达式生成二分图。 该图包含两种类型的节点:DataOperations。 图始终以 Data 节点开始和结束,Operations 节点位于两者之间。 每个 Operation 节点都有输入和输出,两者都是 Data 节点。

生成初始图后,实际上会通过多个图变换(称为passes)进行处理。 ADE 框架充当编译器传递管理引擎,传递是专门为 G-API 编写的。

有不同的传递,它们检查图的有效性,细化操作和数据的细节,根据亲和力或用户指定的区域[TBD]将节点组织成集群(“Islands”),等等。 后端也能够将后端特定的传递注入到编译过程中,有关此内容的更多信息,请参见 专用章节

图编译的结果是一个已编译的对象,由类 cv::GCompiled 表示。 无论是否存在显式或隐式编译请求(请参见上文),始终会创建一个新的 cv::GCompiled 对象。 实际的图执行发生在 cv::GCompiled 中,并由参与图编译的后端确定。

另请参见
cv::GComputation::apply(), cv::GComputation::compile(), cv::GCompiled

后端层

上图列出了两个后端,OpenCVFluidOpenCV 是所谓的“引用后端”,它使用普通的旧 OpenCV 函数来实现 G-API 操作。 此后端对于在熟悉的开发系统上进行原型设计很有用。 Fluid 是一个用于在 CPU 上进行缓存高效执行的插件 – 它实现了不同的执行策略,并使用其自己的特殊内核进行操作。 Fluid 后端允许在 CPU 上运行时实现更少的内存占用和更好的内存局部性。

可能还有更多后端可用,例如 Halide、OpenCL 等 – G-API 提供了一个统一的内部 API 来开发后端,因此任何爱好者或公司都可以自由地在新平台或加速器上扩展 G-API。 就 OpenCV 基础设施而言,每个新后端都是一个新的独立的 OpenCV 模块,当作为 OpenCV 的一部分构建时,它会扩展 G-API。

图执行

图的执行方式由为编译选择的后端定义。 实际上,每个后端都在图编译过程的最后阶段构建自己的执行脚本,此时会生成一个可执行(已编译)对象。 例如,在 OpenCV 后端中,此脚本只是要调用的 OpenCV 函数的拓扑排序序列; 对于 Fluid 后端,类似 – 在每次迭代中处理输入线的代理的拓扑排序列表。

图执行以两种方式触发

两种方法都是多态的,并采用可变数量的参数,并在运行时执行有效性检查。 如果传递的数据对象的数量、形状和格式与预期不同,则会引发运行时异常。 G-API 还提供了类型化包装器,以将这些检查移动到编译时 – 请参见 cv::GComputationT<>

G-API 图执行被声明为无状态的 – 这意味着已编译的函子 (cv::GCompiled) 的行为类似于纯 C++ 函数,并为同一组输入参数提供相同的结果。

两种执行方法都采用 \(N+M\) 个参数,其中 \(N\) 是输入数,\(M\) 是定义 cv::GComputation 的输出数。 请注意,虽然 G-API 类型(cv::GMat 等)在定义中使用,但执行方法接受 OpenCV 的传统数据类型(例如 cv::Mat),这些类型保存实际数据 – 请参见 参数编组中的表。

另请参见
实现细节, 内核 API