#WebGLでリアルタイム画像処理
WebGL Advent Calender 1日目。
初投稿です、よろしくお願いします。
WebGLで画像処理やってみます。
今回施すのは以下のような画像の変換です。
- セピア
- ネガポジ
- 色相の変更
https://dl.dropboxusercontent.com/u/27815754/movie_effect/image_effect.html
WebGLは画像中の画素に対して並列演算を行うことに長けているので3Dだけでなくこういった応用ができます。
ソースコードはここに書き捨てていますので参考にしてみてください。
https://github.com/nyamadan/color_texture
仕組み
画素はR, G, Bの3成分を持ちます。
これをR', G', B'に変換します。
f(R, G, B) -> R', G', B'
(あまり詳しくありませんが、単射という関係になっているはず)
具体的な変換ですがR, G, Bを3次元ベクトルであると捉え、3次元テクスチャから画素をフェッチする方法をとります。
3次元テクスチャというのは聞きなれない言葉かもしれません。
通常私たちが使用しているテクスチャは2次元テクスチャです。
関係は以下のようにあらわせます。
f(x, y) -> R, G, B
一方で3次元テクスチャは以下の関係を持ちます。
f(x, y, z) -> R, G, B
得られる結果はどちらもRGBの3色の画素ですが、引数の数が異なっています。
キューブ状のテクスチャを想像していただければと思います。
さて、ここまで書いておいてあれですが、この3次元テクスチャはWebGL 2.0の機能です。
つまり現行仕様では使えない機能です。
そこで2次元テクスチャを横に並べることでキューブを作成し、対応させることにしました。
基本となるのはこのテクスチャです。
正方形の上のほうが緑成分が強く、右のほうが赤成分が強いです。
そして右へいけばいくほど青成分が強くなっています。
たとえばセピア調の画像を作りたい場合はこの画像をPhotoShopなどでセピア調に変換すれば簡単にセピア調画像を作成することができます。
他にもグレースケールや明るさの変更などもテクスチャを作成すれば対応できます。
さて、シェーダを書くときの注意なのですが、前述したとおりWebGLはまだ3Dテクスチャに対応していません。
なのでXY方向の補間はともかく、Z方向の補間は自分でやる必要があります。
https://github.com/nyamadan/color_texture/blob/master/web/image_effect.dart#L76-L81
この手法のメリットですが、アルゴリズムを変更させずとも、
テクスチャを変更させるだけで様々な画像効果を表現することができます。
数式で表現が難しい変換でもこの手法であれば実現できます。
尚、この手法はGoogle IO/2011にて詳しく解説されています。
画像が不足している分はぜひこちらでご確認ください。
http://webos-goodies.jp/archives/webgl_session_at_google_io_2011.html
テクスチャ画像
さて、もう一つ面白いことにお気づきになられたかと思います。
今回テクスチャに動画を使用しています。
テクスチャには<video>, <img>, <canvas>
が使用できます。
つまり動画であってもテクスチャにすることができます。
ですが、幅と高さが2のn乗である動画なんて基本的にありえないので、一度Canvasに書き出してから使うのが便利です。
この場合、別ドメインの動画を使用した場合、Canvasが汚染された状態になり、テクスチャとして使用できなくなってしまうことがあるので注意が必要です。
応用としてカメラ画像もテクスチャにすることができます。
これができるといろいろ夢が広がりますね。
https://dl.dropboxusercontent.com/u/27815754/camera_effect/image_effect.html
oO(なんかアスペクト比おかしい・・・)
終わりに
そういえば最近Dartにはまっております、ソースコードも全部Dartですね。
Dart Advent CalendarではなんでDart使ってるのかって理由書きたいと思っています、興味があればぜひご覧ください。
明日は @sakusan393 ですね。よろしくお願いします!
使用素材
動画はBig Buck Bunnyのトレイラーを使ってます
https://peach.blender.org/
http://creativecommons.org/licenses/by/3.0/