Edited at

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

読了時間は約7分です。

スクリーンショット 2018-09-07 14.29.58.png

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


Bye bye GPUImage2

iOS12からのGPUImage2非推奨へ

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

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

Apple公式ソース(英語):

リンク

Apple公式ソース(日本語):

リンク

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

Bye Bye GPUImage - Apple is Deprecating OpenGL ES


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時点の簡単な比較表で各プロジェクトの比較をしてみます。

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

リポ名
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

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

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

特徴としては


  • パフォーマンスがいい

  • ビルドインフィルターを使ってパイプラインを構築することができる、その種類が非常に豊富

  • 直接コードを書いて定義することができるか

使えるビルドインフィルターの種類はCore Image Filter Reference

で確認することができます。

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

// UIImage -> CIImage

let ciImage:CIImage? = CIImage(image: uiImage)

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

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

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

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

最後にfilterを施します。

let output = filter.outputImage

非常に簡単な印象です。


GPUImage3

BradLarson/GPUImage3

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

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

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

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

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


  • 静止画をキャプチャしてフィルタリングする

  • 動画から画像をキャプチャする

  • 静止画を処理する

  • 動画を再エンコーディングする


FlexibleImage

kawoou/FlexibleImage

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

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

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

/// 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

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

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


  • 使いやすいAPI

  • パフォーマンスがいいこと

  • 拡張性の高さ

  • Swiftyにかける

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

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


  • 頂点とフラグメントの関数を完全にカスタマイズできる

  • MRTをサポートしている

  • 一般的にはパフォーマンスがいい

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

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

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

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

// CIImage -> MTIImage

let imageFromCIImage = MTIImage(ciImage: ciImage)

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

let filter = MTISaturationFilter()

filter.saturation = 0
filter.inputImage = inputImage

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

let outputImage = filter.outputImage


MetalAcc

wangjwchn/MetalAc

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

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

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

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 を使った画像処理について説明しました