はじめに
2年ぐらい前から監視しているGitHub Repositoryがある。PyTorchを用いたリタイムのアプリケーションのRIFEと呼ばれるものだ。元のペーパーはこちら
最初はKhakiの水野さんが教えてくださった。以後ずっとペーパーやコードを読んでは理解できないと悶えて、読んでは頭を抱え、読んでは全身蕁麻疹になり、果ては読んではモニターに向かって罵詈雑言を言い放つというのを繰り返し、数ヶ月前からようやく少し仲直りし始めたような感じにはなってきた。
だいたい全3回でRIFEを通じてリタイムとneural networkを探索していこうと思います。本ポストは第一回目です。
Optical Flow
アプリケーションの目的としは動画のリタイム(モーションエスティメーション)をneural networkを用いて行うというものであり、結果が素晴らしくスムースである(そして速い!)。正直にいうと、このアプリケーションを触り始めた頃は、モーションエスティメーションがどのようなアルゴリズムで行われているなんて全く知り得なかった。存在しないフレームで絵がスムースに連続的に繋がっていることから、モーフィング的なことをやっているのだろうというざっくりとした理解のみであった。順序が逆であるのは承知だけどその後ペーパーを読み進めて、リタイムで用いられるモーションエスティメーションはComputer VisionベースのアルゴリズムであるOptical Flowを用いたものが一般的であるということを知る。
またこのOptical Flowを用いたアプリケーションの例としてはKronosやOFlowが挙げられるであろう。Optical Flowというのはざっくりというと、あるピクセルが次のフレームまたは前のフレームへの画像上でのオフセット分つまりを二次元のベクトルである。nukeではこのベクトルを(forward.u,forward.v)と(backward.u,backward.v)という形で保持することが通例となっている。もしくはその二つをまとめてmotion(forward.u,forward.v,backward.u,backward.v)として扱われることもある。ちなみにnukeでは予約チャンネル名である。
I0 と I1 の間のこと
もう少しリタイムについて考えてみる。仮に動画を撮影したものが連番で存在しているとする。ここでは時刻0での画像をI0、時刻1での画像をI1と呼ぶことにする。さらに時刻0と時刻1は時間的に連続しているものとする。例えばリタイムのいくつかのケースでI0とI1の間のある時点での画像を作ることをタスクとしていることがある。またここではこの間の時点を時刻tとして、その時刻tでの画像のことをItと呼ぶこととする。さらに話をややこしく言ってる気概はあるが、時刻0,時刻1は0フレーム目と1フレーム目ということではなく、始点と終点という感じで捉えてほしい。なので、例えば時刻tが時刻0と時刻1のちょうど真ん中であるとして、時刻0が0フレーム目、時刻1が2フレーム目を指しているとすると、時刻tは1フレーム目のことを指し、この場合はその動画で収録されている画像の中にこのItは存在していると期待できる。そして事はt=0.5フレーム目のように収録されている画像の中にそれが存在しないケースである・・・
リタイムとフローベクトル
リタイムというタスクにおいてOptical Flowがどのように使われるのかを見てみよう。Optical Flowを用いてすでにI0の各ピクセルをI1へと移す(forward.u,forward.v)ベクトルがI0それぞれのピクセルに画像座標上で対応する形で存在しているとする。またさらにその逆でItの各ピクセルをI0へと移す(backward.u,backward.v)ベクトルを同様に得ているものとする。この(forward.u,forward.v)ベクトル、(backward.u,backward.v)ベクトルは画像上のピクセルの流れを表しているのでフローベクトルと呼ばれたりする。またフローベクトルで画面は満たされているのでつまりこれらはいわゆるvector fieldだと考えられる。
vector field
モーションエスティメーション
ものすごく雑に考えると、ItのピクセルはI0での対応ピクセルを(forward.u,forward.v)ベクトルを用いて移動させたもの、もしくはをI1での対応ピクセルを(backward.u,backward.v)ベクトルを用いて移動させたものいずれかで表現できる。しかしこれは雑すぎる・・・実際にはサブフレーム時においてしか見えないピクセルもあれば、サブフレーム時にしかない動きもある。例えばカメラの細かな揺れは整数フレーム時だけを考慮するとモーションブラー等で破綻を起こす。これは別の話ではあるが・・・ このポストではサブフレーム時の曲線的な動きについては一旦無視させてもらいます。
ともあれモーションエスティメーション的なリタイムでは与えられたI0とI1を用いてOptical Flowを用いてフローベクトルを生成し、そのフローベクトルとI0とI1でItに相当する画像を生成する。
おわりに
今回は、PyTorchを用いたリアルタイムアプリケーション「RIFE」の紹介に始まり、リタイム(モーションエスティメーション)のプロセスとその内部で起こる動作について解説した。オプティカルフローというComputer Visionベースのアルゴリズムを利用して、動画のリタイムを実現する技術に焦点を当て、その仕組みと実装の方法をある程度説明した(つもり)。次回は、フローベクトルの生成方法の違いとRIFEに関するさらなる掘り下げを行う予定です。