G-API 背后的动机
G-API 模块为 OpenCV 带来了基于图形的执行模型。本章将简要介绍这一新模型如何在优化和移植图像处理算法两个方面为软件开发人员提供帮助。
使用图形 API 进行优化
传统上,OpenCV 提供了大量独立的图像处理函数(参见 core
和 imgproc
模块)。其中许多函数都经过了很好的优化(如针对特定 CPU 的矢量化、并行化等),但开箱即用的优化范围仍然仅限于单个函数–优化建立在该函数之上的整个算法是程序员的责任。
OpenCV 3.0 引入了透明 API(或 T-API),允许将 OpenCV 函数调用透明地卸载到 OpenCL 设备上,并通过 cv::UMat 节省主机/设备数据传输的成本,这是向前迈出的一大步。然而,T-API 是一个动态 API,用户代码仍然不受约束,OpenCL 内核以任意顺序排队,因此无法进一步发挥流水线级别的优化潜力。
G-API 为 OpenCV 4.0 带来了隐式图模型。图模型捕获了流水线中的所有操作及其数据依赖关系,因此为 G-API 框架提供了额外的信息来进行流水线级优化。
基于图形的优化的基石是平铺。平铺允许将处理分成较小的部分,并重新组织操作,以实现数据并行性、提高数据局部性并节省内存占用。数据局部性是软件优化的一个特别重要的方面,因为在现代计算机体系结构中,内存访问的成本各不相同–一级缓存中重复使用的数据越多,流水线的效率就越高。
上述技术当然可以手动应用,但这需要额外的技能和对目标平台的了解,而且算法的实现也会发生不可逆转的变化,变得更加具体、更加不灵活、更加难以扩展和维护。
G-API 从用户手中接过了这一责任和复杂性,自己完成了大部分工作,使算法代码不受设备或优化细节的影响。不过,这种方法也有其局限性,因为图形模型是一种受限模型,并不是每种算法都能用图形来表示,所以 G-API 的范围仅限于常规图像处理–各种滤镜、算术、二进制操作和定义明确的几何变换。
图形应用程序接口的移植
G-API 的本质是声明要运行的操作序列,然后执行该序列。G-API 是一种受约束的应用程序接口,因此它对哪些操作可以组成流水线以及这些操作可以相互交换哪些数据做出了一系列限制。
这种形式化实际上有助于使算法具有可移植性。G-API 将操作界面与其实现明确分开。
一个操作(内核)即使在一个设备上也可能有多个实现(例如,基于 OpenCV 的 "参考 "实现和平铺优化实现,两者都在 CPU 上运行)。图形(或 G-API 术语中的计算)仅使用操作界面而非实现来构建,因此同一图形可在不同设备上执行(当然也可使用不同的优化技术),而图形本身几乎不会发生任何变化。
G-API 支持插件(后端),这些插件汇总了在特定平台上执行的最佳方式的逻辑和智能。一旦使用 G-API 构建了管道,就可以对其进行参数化,使其使用任一后端(或后端组合),这样就可以轻松地将图形移植到新的平台上。