GPUImage 3

Janie Larson

http://redqueencoder.com

@RedQueenCoder @RedQueenCoder@appdot.net

Brad Larson

http://www.sunsetlakesoftware.com

@bradlarson@hachyderm.io

contact@sunsetlakesoftware.com

概述

GPUImage 3 是 GPUImage 框架的第三代,这是一个开源项目,用于在 Mac 和 iOS 上执行 GPU 加速的图像和视频处理。 最初的 GPUImage 框架是用 Objective-C 编写的,目标是 Mac 和 iOS,第二个迭代版本使用 OpenGL 在 Swift 中重写,目标是 Mac、iOS 和 Linux,而现在的第三代版本则被重新设计为使用 Metal 代替 OpenGL。

该框架的目标是尽可能轻松地设置和执行针对图像或视频源的实时视频处理或机器视觉。 该框架的先前迭代版本包装了 OpenGL (ES),隐藏了使用自定义顶点和片段着色器在 GPU 上渲染图像所需的大量样板代码。 此版本的框架用 Metal 替换了 OpenGL (ES)。 主要受 Apple 在其平台上弃用 OpenGL (ES) 而转向 Metal 的推动,这将允许探索优于 OpenGL 的性能优化,以及与基于 Metal 的框架和操作更紧密的集成。

API 是 GPUImage 2 中使用的 API 的克隆版本,旨在作为该框架版本的直接替代品。 在框架的 Metal 和 OpenGL 版本之间进行交换应该像更改应用程序链接的框架一样简单。 一些底层接口,例如围绕纹理输入和输出的接口,必然是 Metal 或 OpenGL 特定的,但其他一切都旨在在两者之间兼容。

截至目前,我们不接受来自外部贡献者的增强请求。 我们正在积极努力在 GPUImage 的此版本和先前版本之间移植所有功能。 一旦此任务完成,我们将很乐意接受社区贡献。

许可证

BSD 风格,完整许可证随框架在 License.txt 中提供。

技术要求

通用架构

该框架依赖于处理管道的概念,其中图像源针对图像消费者,依此类推,直到图像输出到屏幕、图像文件、原始数据或录制的影片。 摄像头、影片、静态图像和原始数据可以作为此管道的输入。 可以通过一系列较小操作的组合来构建任意复杂的处理操作。

这是一个面向对象的框架,其中的类封装了输入、处理操作和输出。 处理操作使用 Metal 顶点和片段着色器在 GPU 上执行图像操作。

下面显示了在常见应用程序中使用该框架的示例。

在 Mac 或 iOS 应用程序中使用 GPUImage

GPUImage 以 Swift 包的形式提供。 要将其添加到您的 Mac 或 iOS 应用程序,请转到您的项目设置,选择“Package Dependencies”(包依赖项),然后单击加号按钮。 在右上角输入此存储库的 URL,然后按 Enter 键。 GPUImage 将显示为项目的包依赖项。

在任何引用 GPUImage 类的 Swift 文件中,只需添加

import GPUImage

您应该就可以开始使用了。

请注意,您可能需要构建项目一次以解析和构建 GPUImage 框架,以便 Xcode 停止警告您框架及其类丢失。

执行常见任务

过滤实时视频

要过滤来自 Mac 或 iOS 摄像头的实时视频,您可以编写如下代码

do {
    camera = try Camera(sessionPreset:.vga640x480)
    filter = SaturationAdjustment()
    camera --> filter --> renderView
    camera.startCapture()
} catch {
    fatalError("Could not initialize rendering pipeline: \(error)")
}

其中 renderView 是您放置在视图层次结构中某处的 RenderView 的实例。 上述代码实例化了一个 640x480 摄像头实例,创建了一个饱和度滤镜,并将摄像头帧定向为通过饱和度滤镜处理,然后显示到屏幕上。 startCapture() 启动摄像头捕获过程。

--> 运算符将图像源链接到图像消费者,并且可以在同一行中链接许多此类运算符。

捕获和过滤静态照片

功能未完成。

从视频捕获图像

功能未完成。

处理静态图像

功能未完成。

过滤和重新编码影片

功能未完成。

编写自定义图像处理操作

该框架使用一系列协议来定义可以输出要处理的图像、接收要处理的图像或两者兼而有之的类型。 这些分别是 ImageSource、ImageConsumer 和 ImageProcessingOperation 协议。 任何类型都可以遵守这些协议,但通常使用类。

许多常见的滤镜和其他图像处理操作可以描述为 BasicOperation 类的子类。 BasicOperation 提供了从一个或多个输入接收图像帧、使用指定的着色器程序从这些输入渲染矩形图像(四边形)以及将该图像提供给其所有目标所需的大部分内部代码。 BasicOperation 的变体,例如 TextureSamplingOperation 或 TwoStageOperation,向着色器程序提供了某些类型的操作可能需要的其他信息。

要构建一个简单的单输入滤镜,您甚至可能不需要创建自己的子类。 您只需在实例化 BasicOperation 时提供片段着色器和所需的输入数量即可

let myFilter = BasicOperation(fragmentFunctionName:"myFilterFragmentFunction", numberOfInputs:1)

着色器程序由匹配的顶点和片段着色器组成,这些着色器被编译并链接到一个程序中。 默认情况下,该框架使用一系列基于输入到操作中的图像数量的库存顶点着色器。 通常,您只需要提供用于执行过滤或其他处理的自定义片段着色器即可。

GPUImage 使用的片段着色器如下所示

#include <metal_stdlib>
#include "OperationShaderTypes.h"

using namespace metal;

fragment half4 passthroughFragment(SingleInputVertexIO fragmentInput [[stage_in]],
                                   texture2d<half> inputTexture [[texture(0)]])
{
    constexpr sampler quadSampler;
    half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);

    return color;
}

并保存在 .metal 文件中,这些文件与框架/您的项目同时编译。

分组操作

如果您希望将一系列操作分组到一个单元中以传递,则可以创建 OperationGroup 的新实例。 OperationGroup 提供了一个 configureGroup 属性,该属性接受一个闭包,该闭包指定应如何配置组

let boxBlur = BoxBlur()
let contrast = ContrastAdjustment()

let myGroup = OperationGroup()

myGroup.configureGroup{input, output in
    input --> self.boxBlur --> self.contrast --> output
}

进入 OperationGroup 的帧由上述闭包中的输入表示,而整个组输出的帧由输出表示。 设置完成后,上面的 myGroup 将像任何其他操作一样显示,即使它由多个子操作组成。 然后可以像单个操作一样传递或处理此组。

与 Metal 交互

[待办事项:为 Metal 重做]

常用类型

该框架使用几种平台无关的类型来表示常用值。 通常,浮点输入以 Floats 形式接收。 尺寸使用 Size 类型指定(通过使用宽度和高度初始化构造)。 颜色通过 Color 类型处理,您可以在其中为红色、绿色、蓝色以及可选的 alpha 分量提供归一化为 1.0 的颜色值。

位置可以以 2D 和 3D 坐标提供。 如果仅通过指定 X 和 Y 值来创建 Position,则将其视为 2D 点。 如果还提供了可选的 Z 坐标,则将其视为 3D 点。

矩阵有 Matrix3x3 和 Matrix4x4 两种类型。 这些矩阵可以使用 Floats 的行优先数组构建,也可以从 CATransform3D 或 CGAffineTransform 结构初始化。

内置操作

操作当前正在从 GPUImage 2 移植过来。 以下是目前可用的操作

颜色调整

图像处理

混合模式

视觉效果