RIFE (仮) #1

## はじめに
　2年ぐらい前から監視しているGitHub Repositoryがある。PyTorchを用いたリタイムのアプリケーションの[RIFE](https://github.com/megvii-research/ECCV2022-RIFE "megvii-research
/ECCV2022-RIFE")と呼ばれるものだ。元のペーパーは[こちら](https://arxiv.org/abs/2011.06294)

![I2_slomo_clipped.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057501/160263dd-b533-f3b1-3fd1-346cfd47cbf5.gif)![D2_slomo_clipped.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057501/826a67c4-56a9-19db-4c8b-fd76b523aff7.gif)

　最初はKhakiの水野さんが教えてくださった。以後ずっとペーパーやコードを読んでは理解できないと悶えて、読んでは頭を抱え、読んでは全身蕁麻疹になり、果ては読んではモニターに向かって罵詈雑言を言い放つというのを繰り返し、数ヶ月前からようやく少し仲直りし始めたような感じにはなってきた。
　だいたい全３回で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では予約チャンネル名である。<br>
![Kronos node](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057501/0bc2f7de-a335-4df9-f35e-38244a6158ce.png "Kronosノード")　![motion channel](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057501/7097f58f-e5cc-5f5e-93b4-95466dbeb916.png "motion チャンネル")



## <em>I0</em> と <em>I1</em> の間のこと
　もう少しリタイムについて考えてみる。仮に動画を撮影したものが連番で存在しているとする。ここでは時刻0での画像を<em>I0</em>、時刻1での画像を<em>I1</em>と呼ぶことにする。さらに時刻0と時刻1は時間的に連続しているものとする。例えばリタイムのいくつかのケースで<em>I0</em>と<em>I1</em>の間のある時点での画像を作ることをタスクとしていることがある。またここではこの間の時点を時刻<em>t</em>として、その時刻<em>t</em>での画像のことを<em>It</em>と呼ぶこととする。さらに話をややこしく言ってる気概はあるが、時刻0,時刻1は0フレーム目と1フレーム目ということではなく、始点と終点という感じで捉えてほしい。なので、例えば時刻tが時刻0と時刻1のちょうど真ん中であるとして、時刻0が0フレーム目、時刻1が2フレーム目を指しているとすると、時刻tは1フレーム目のことを指し、この場合はその動画で収録されている画像の中にこの<em>It</em>は存在していると期待できる。そして事はt=0.5フレーム目のように収録されている画像の中にそれが存在しないケースである・・・



## リタイムとフローベクトル
　リタイムというタスクにおいてOptical Flowがどのように使われるのかを見てみよう。Optical Flowを用いてすでに<em>I0</em>の各ピクセルを<em>I1</em>へと移す(forward.u,forward.v)ベクトルが<em>I0</em>それぞれのピクセルに画像座標上で対応する形で存在しているとする。またさらにその逆で<em>It</em>の各ピクセルを<em>I0</em>へと移す(backward.u,backward.v)ベクトルを同様に得ているものとする。この(forward.u,forward.v)ベクトル、(backward.u,backward.v)ベクトルは画像上のピクセルの流れを表しているのでフローベクトルと呼ばれたりする。またフローベクトルで画面は満たされているのでつまりこれらはいわゆるvector fieldだと考えられる。<br>
<img src="https://mapserver.org/_images/uv.png">vector field</img>



## モーションエスティメーション
　ものすごく雑に考えると、<em>It</em>のピクセルは<em>I0</em>での対応ピクセルを(forward.u,forward.v)ベクトルを用いて移動させたもの、もしくはを<em>I1</em>での対応ピクセルを(backward.u,backward.v)ベクトルを用いて移動させたものいずれかで表現できる。しかしこれは雑すぎる・・・実際にはサブフレーム時においてしか見えないピクセルもあれば、サブフレーム時にしかない動きもある。例えばカメラの細かな揺れは整数フレーム時だけを考慮するとモーションブラー等で破綻を起こす。これは別の話ではあるが・・・ このポストではサブフレーム時の曲線的な動きについては一旦無視させてもらいます。
![crazyMotionBlurTrail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057501/65d134e5-b60e-bbe2-b001-345ce83764ca.png)<br>
　ともあれモーションエスティメーション的なリタイムでは与えられた<em>I0</em>と<em>I1</em>を用いてOptical Flowを用いてフローベクトルを生成し、そのフローベクトルと<em>I0</em>と<em>I1</em>で<em>It</em>に相当する画像を生成する。


![retime_flowvector1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057501/69269c5d-7653-0097-bb4d-efacad439072.png) ![retime_flowvector2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3057501/ba0dcaa8-55fc-4312-f138-b8f4e49a0efa.png)

## おわりに
　今回は、PyTorchを用いたリアルタイムアプリケーション「RIFE」の紹介に始まり、リタイム（モーションエスティメーション）のプロセスとその内部で起こる動作について解説した。オプティカルフローというComputer Visionベースのアルゴリズムを利用して、動画のリタイムを実現する技術に焦点を当て、その仕組みと実装の方法をある程度説明した(つもり)。次回は、フローベクトルの生成方法の違いとRIFEに関するさらなる掘り下げを行う予定です。