iOS12からOpen GL(ES)の非推奨化。グラフィックAPIフレームワークの動向まとめ

読了時間は**約7分**です。

<img width="127" alt="スクリーンショット 2018-09-07 14.29.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/153320/b5955c49-4a0d-1a83-3092-7701903b047f.png">

画像引用: https://developer.apple.com/jp/metal/


## Bye bye GPUImage2

iOS12からのGPUImage2非推奨へ

少し語弊があるので説明するとGPUImage2自体が非推奨なわけではなくて、**GPUImage2内部で使われているOpen GL(ES)がiOS12から非推奨になる**とのことです。

もう一つ追記すると、非推奨なので元のものをすぐに使えなくなるわけではありません。

**Apple公式ソース(英語):**
[リンク](https://developer.apple.com/ios/whats-new)

**Apple公式ソース(日本語):**
[リンク](https://developer.apple.com/jp/ios/whats-new/)

実際にGPUImage内でも以下のようなIssueが上がっています。

[Bye Bye GPUImage - Apple is Deprecating OpenGL ES](https://github.com/BradLarson/GPUImage2/issues/250)

## Why

これはKhronos Groupが開発したVulkanと似たようなシチュエーションです。

実はすでにOpen GLやその組み込み版であるOpen GL(ES)など、オープンソースで、かつ、GPUによるグラフィック処理をすることができるものはありました。

しかし、**近年のGPUをはじめとしたハードウェアの進化は凄まじく、OpenGLのような抽象化されすぎて、利便性を追い求めたものがオーバーヘッドを生んでしまい、ハードウェアの限界性能を引き出せなくなっていたという現実**がありました。

その解決策として、より低レベルのAPIを提供したグラフィックAPIVulkanが出た歴史があります。

同様にApple MetalもVulkanと競合するフレームワークです。同様の問題があって、オーバーヘッド軽減に関する効果があることから開発されたと推測することができます。

**Apple公式ソース(日本語): **
[https://developer.apple.com/jp/ios/whats-new](リンク)

## Hello XXX?

では、どのような対応をすればいいのでしょうか。

公式のドキュメントでは**Apple製のグラフィック処理フレームワークMetalを使うことが推奨されています**。

しかし、Metalを使うとなっても直接低レベルのAPIをアプリケーションで呼び出すには開発コストや既存のGPUImage2などのライブラリからの置き換えを考えると無理難題です。

そこで以下のようなGPUImageに置き換わるようなライブラリがいくつか開発されているので検討してみようと思います。

- CoreImage
- GPUImage3
- FlexibleImage
- MetalPetal
- MetalAcc

詳細を述べる前に、**2018/09/07時点**の簡単な比較表で各プロジェクトの比較をしてみます。

なお、ドキュメントの充実度は主観により、⭐️３つで正則化しています。

| リポ名 | star数 | fork数 | contributor数 | ドキュメントの充実度 | ライセンス |
| :---: | :---: |:---: | :---: | :---: | :---: |
| `Core Image` | - | -  | - | ⭐️⭐️⭐️| - |
| `BradLarson/GPUImage3` | 1124 | 42  | 4 | ⭐️⭐️| BSD 3-Clause |
| `kawoou/FlexibleImage` | 724 | 33 | 1 | ⭐️⭐️⭐️ | MIT |
| `MetalPetal/MetalPetal` | 238 | 31 | 5 |⭐️⭐️⭐️ | MIT |
| `wangjwchn/MetalAcc` | 213 | 18 | 1 | ⭐️ | MIT |

また現時点での必要条件は以下の通りです。記載がないものは`-`を使っています。

| リポ名 | swift | iOS | Xcode | OSX | tvOS |
|:---:|:---:|:---:| :---: | :---: | :---: |
| `Core Image` | - | 5.0以上  | 9.0以上 | 10.11以上 | 9.0以上 |
| `BradLarson/GPUImage3` | 4.0以上 | 9.0以上  | 9.0以上 | 10.11以上 | - |
| `kawoou/FlexibleImage` | 3.0以上  | 8.0以上 | - | 10.10以上 |  9.0以上 |
| `MetalPetal/MetalPetal` | - | - | - | - | - |
| `wangjwchn/MetalAcc` | - | - | - | - | - |

### Core Image

[Core Image](https://developer.apple.com/documentation/coreimage:title)

ここでは取り上げませんでしたが、Core Graphicの後継ライブラリです。

Appleのビルドインの静止画や動画に任意のフィルターをかけるものです。

特徴としては

- パフォーマンスがいい
- ビルドインフィルターを使ってパイプラインを構築することができる、その種類が非常に豊富
- 直接コードを書いて定義することができるか

使えるビルドインフィルターの種類は[Core Image Filter Reference](https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html#//apple_ref/doc/uid/TP40004346)
で確認することができます。

基本的にはCore Imageクラス`CIImage`を使うので`UIImage`をキャストする必要があります。逆も然りです。

```swift
// UIImage -> CIImage
let ciImage:CIImage? = CIImage(image: uiImage)

// CIImage -> UIImage
let uiImage:UIImage? = UIImage(ciImage: ciImage)
```

そして`CIFilter`を使ってフィルターを定義して

```swift
let filter = CIFilter(name: "CIPhotoEffectMono")!

filter.setDefaults()
filter.setValue(ciImage, forKey: kCIInputImageKey)
```

最後にfilterを施します。

```swift
let output = filter.outputImage
```

非常に簡単な印象です。

### GPUImage3

[BradLarson/GPUImage3](https://github.com/BradLarson/GPUImage3)

GPUImageフレームワークの第三世代目です。

GPUImageはObjective-Cで書かれていて、GPUImage2はそれをSwiftに書き直したものです。

そのGPUImage2ではOpen GL(ES)をラッピングしていたましたが、この世代はMetalをラッピングしていて、パフォーマンスの最適化やMetalをベースに作られたフレームワークと高い統合性を示します。

しかしながら、GPUImage2の機能を完全にカバーしているわけではなくて、フルカバー終え次第、外部コントリビュータからのIssueやPull Requestを受け付けるそうです。

**2018/09/07時点で未実装**の機能は以下の通りです。

- 静止画をキャプチャしてフィルタリングする
- 動画から画像をキャプチャする
- 静止画を処理する
- 動画を再エンコーディングする

### FlexibleImage

[kawoou/FlexibleImage](https://github.com/kawoou/FlexibleImage)

FlexibleImageはMetalを使って静止画のみに対応しているグラフィックプラットフォームです。

特にドキュメントが非常に簡潔で、わかりやすく、`examples`以下にいろんなプラットフォームでの使用例があるので、**静止画ならとっつきやすい**印象があります。

一般的なフィルターには以下のようにフィルターをかけます。

```swift
/// Generate Example
let image1 = UIImage
    .circle(
        color: UIColor.blue,
        size: CGSize(width: 100, height: 100)
    )!
    
    .adjust()
    .offset(CGPoint(x: 25, y: 0))
    .margin(UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5))
    .padding(UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15))
    .normal(color: UIColor.white)
    .border(color: UIColor.red, lineWidth: 5, radius: 50)
    .image()!
    
    .adjust()
    .background(color: UIColor.darkGray)
    .image()
```

特に使いやすいイメージがあります。


### MetalPetal

[MetalPetal/MetalPetal](https://github.com/MetalPetal/MetalPetal)

MetalPetalはGPUImage3と同様にMetalを使ってリアルタイムで動画や静止画を処理するためのフレームワークです。

以下のように設計されています。

- 使いやすいAPI
- パフォーマンスがいいこと
- 拡張性の高さ
- Swiftyにかける

また、コアなコンポーネントはApple Core Image Frameworkに近いです。

しかし、何がCore Imageと何がちがうのかというと

- 頂点とフラグメントの関数を完全にカスタマイズできる
- MRTをサポートしている
- 一般的にはパフォーマンスがいい

そうです。しかしながら、ベンチマークを取っていないので注意が必要です。

以下のようにフィルターを施します。

処理の対象は`MTIImage`クラスのでキャストする必要があります。

入力画像としてはCore ImageかCore Graphicクラスである必要があります。

```swift
// CIImage -> MTIImage
let imageFromCIImage = MTIImage(ciImage: ciImage)
```

そしてフィルターを定義します。

```swift
let filter = MTISaturationFilter()
filter.saturation = 0
filter.inputImage = inputImage
```

そして以下のようにして、出力を取得できます。

```swift
let outputImage = filter.outputImage
```

### MetalAcc

[wangjwchn/MetalAc](https://github.com/wangjwchn/MetalAcc)

こちらもSwiftで書かれたMetalのGPUベースの処理ライブラリで、GPUImageにインスパイアされて作成されています。

しかしながら、ドキュメントが整っておらず、機能も静止画のフィルターに限られているという印象です。

一般的な使用方法は以下の通りです。

```swift
let accImage = AccImage()
        
accImage.Input(inimage)
        
accImage.AddProcessor(AccBrightnessFilter())
        
accImage.Processing()
        
let outimage = accImage.Output()
```

## 総括

パフォーマンスについてはベンチマークを取っていないので今回は比較できません。

あとは比較できるとすると機能面、設計ではないでしょうか。

機能については、以下の表に比較します。

なお、ライブラリやフレームワークそれ単体で実現できない機能も❌としています。
(たとえば動画に対応していなくても、スクショなど静止画にするという対応を前処理として取るなど)

また、GPUImage3については、GPUImage2で実装されていた項目について実装されるので🚧をつけています。

### Blur

`FlexibleImage`は単にBlurしか書かれていないので❓をつけています。

| 機能                             | `Core Image` |`GPUImage3` | `FlexibleImage` | `MetalPetal` | `MetalAcc` |
|:-----------:| :----: |:---------: | :---------------: | :-----------: | :----------: |
|  静止画に対応             | ✅                    | ✅                    |✅                        |✅                   |✅                |
|  動画に対応            　 | ✅                    |✅                     |❌                        |✅                   |✅                |
|  BoxBlur            　       | ✅                    | 🚧                   |❓                        | ❌                  |❌                |
|  DiscBlur                 　 | ✅                    | ❌                    |❓                        |❌                   |❌                |
|  GaussianBlur         　 | ✅                    | 🚧                    |❓                        | ✅                  |❌                |
|  SingleComponentGaussianBlur| ❌    | 🚧                   | ❓                       | ❌                  |❌                |
|iOSBlur                         | ❌                    | 🚧                   |❓                       | ❌                  |❌                |
|  MaskedVariableBlur  | ✅                    | ❌                    |❓                        |❌                   | ❌               |
|  MedianFilter               | ✅                    |🚧                     | ❓                       |❌                   |❌                |
|  MotionBlur                  | ✅                    |🚧                     |❓                        |❌                   |❌                |
|  NoiseReduction          | ✅                    |❌                     |❓                        |❌                   |❌                |
|  ZoomBlur                    | ✅                    | 🚧                    | ❓                       |❌                   |❌                |
|Lens(Hexagonal Bokeh) Blur|❌            |❌                    |❓                         |✅                   |❌                |

### 他機能

他の機能については、どんどん追記していきます。

## まとめ

iOS12からOpen GL(ES)を使ったライブラリは非推奨となるのでWarningが出るようになるので組織としても技術的負債を抱えるのは辛いと思います。

この記事が少しでも参考になれば嬉しいです。

今度、ベンチマークを取れればいいなと思います。

読んでいただきありがとうございました！

## 参考文献

**Core Imageについて**
[プログラミング教室で Core Image を使った画像処理について説明しました](https://qiita.com/mironal/items/36a0d6912522071b946a:embed:cite)