見出し画像

2D動画を3DにしてARで見る

リュミエール兄弟

リュミエール兄弟をご存じでしょうか。メディア論を大学で受講した方や映像系の研究や製作をされている方だったら聞き覚えがあるのではないでしょうか。彼らは映画を発明したフランスの兄弟です。(彼らの映画は4Kリマスターされて2018年に上映もされています。)

彼らが発明したのは初期の映画装置であるシネマトグラフです。1台で撮影・映写・現像ができる装置で、現代のビデオカメラの祖先にあたります。シネマトグラフは持ち運びができ、リュミエール兄弟はこれを使って多くの映画作品を作りました。

彼らが撮影した世界初の実写映画は「工場の出口」というものです。現代にこの動画を見るとただ工場の出口から労働者が出てくるだけで退屈じゃないかと思われるかもしれませんが、実写の映画を初めてみた当時の観客はどんな気持ちになったでしょう。。。そういう得も言われぬ感覚を体験してみたいものです。

もう一つ彼らの作品で有名なのが「ラ・シオタ駅への列車の到着」です。この作品も駅のプラットフォームで向こう側から列車が来るのを撮影しているだけと思われるかもしれませんが、当時の観客は自分らに向かって近付いてくる実物大の列車の動きに圧倒され、叫び声を上げながら部屋の後方へ走り出したという都市伝説が残っているほどです。

本記事のモチベーション

上記のラ・シオタ駅への列車の到着のウィキペディアの中に下記のような記載があります。今から約100年前に、三次元動画を作っていたなんて驚きですよね。

""フィルムの歴史ではあまり語られないが、リュミエール兄弟はこの最初に公開された動画に先だって三次元画像の実現を試みていた。ルイ・リュミエールはステレオカメラを用いて『列車の到着』を撮影し直し、他の三次元映像シリーズとともに1935年のフランス科学アカデミー会議において上映した。""

彼らの映像に対する熱意に敬意をこめつつ、現代の技術を使って当時の観客が体験したような作品を作るにはどうしたらいいかというのがこの記事の根源的なモチベーションです。

製作

様々なアプローチがあると思いますが、今回はタイトル通りのモノ(2D動画を3DにしてARで見る)を作りたいと思います。大まかな流れは下記の通りです。ここからはこの流れに沿って説明します

1. 3D化したい動画を用意する。
2. 機械学習を用いて2Dの動画から深度情報を計算する。
3. Unityへのインポート、3D化の処理。
4. ARで見る。

1. 3D化したい動画を用意する。

ここから著作権フリーの動画をとってきました。リュミエール兄弟にリスペクトを込めて電車の動画を使います。

https://www.pexels.com/video/a-train-passing-by-the-railway-station-5593088/

解像度が大きすぎると深度画像の出力に時間がかかるのでffmpegで適当に縮小します。

ffmpeg -i train1.mp4 -vf scale=640:-1 train1out.mp4

次に縮小した動画を次に使うpythonのプログラムに読み込ませるために連番画像に変換します。

ffmpeg -i train1out.mp4 -vcodec png train1/%d.png

2. 機械学習を用いて2Dの動画から深度情報を計算する。

Githubから学習済みモデルを取ってきてセットアップします。CVPR2021に投稿された”Learning to Recover 3D Scene Shape from a Single Image”を今回は利用します。NVIDIAのGPUが乗っているPCで作業するのがおすすめです。今回は試してないですが、CPUで実行するとかなり時間がかかると思います。このリポジトリに入っているtest_depth.pyを今回は利用します。

Githubにあるチュートリアルどおりに進めるとoutputフォルダに連番のdepth画像が出力されると思います。pytorchやcuda周りの設定で手間取ることがあるかもしれないですが、本論からずれるのでここでは割愛します。(めんどくさいだけ)

3. Unityへのインポート、3D化の処理

この部分についてのUnityプロジェクトをGitHubに置いておきました。使い方についてはREADMEを参照してもらうとして、ここでは処理の説明と注意点を記載しておきます。

画像の再投影の方法について

動画のRGB連番画像とDepth連番画像のペアをパラパラ漫画的にロードすることで3Dのボリュメトリックビデオを表示します。

このUnityプロジェクトで最も大事な部分は、PointCloudScript.csのReprojectPointCloud関数の中の下記の部分です。RGB画像とDepth画像を読み込んで、RGB画像とDepth画像の各ピクセルについてRGB画像のカラー情報をDepth情報の深度を付与して3次元座標に描画するという処理です。crop_thは表示される点群の見た目の調整用に入れています。

        for(int depth_y = 0; depth_y < height_depth; depth_y++)
       {
           index_dst = depth_y * width_depth;
           for(int depth_x = 0; depth_x < width_depth; depth_x++)
           {
               colors[index_dst] = m_CameraTexture.GetPixelBilinear((float)depth_x/(width_depth), (float)depth_y / (height_depth));

               depth = depthPixels[index_dst].r;
               if(depth < crop_th){
                   depth = crop_th;
               }
               if (depth > near && depth < far)
               {
                   vertices[index_dst].z = depth;
                   vertices[index_dst].x = -depth * (depth_x - cx) / fx;
                   vertices[index_dst].y = -depth * (depth_y - cy) / fy;
               }
               else
               {
                   vertices[index_dst].z = -999;
                   vertices[index_dst].x = 0;
                   vertices[index_dst].y = 0;
               }
               index_dst++;
           }
       }

fx, fy, cx, cyは本来であればカメラの内部パラメータを入れる変数ですが、今回の例ではカメラが未知であるため、画素中心をそれぞれ設定しています。とりあえず3Dっぽく見るだけであればこれで十分です。より厳密にやるのであれば、既存の動画ではなく自分のカメラを使って、カメラキャリブレーションをする方法や、ARFoundationのTryGetIntrinsicsメソッドを使って取得する方法もあります。

        if(vertices==null || colors == null)
       {
           vertices = new Vector3[width_depth * height_depth];
           colors = new Color[width_depth * height_depth];
         
           fx = m_CameraTexture.width / 2;
           fy = m_CameraTexture.height /2;
           cx = m_CameraTexture.width / 2;
           cy = m_CameraTexture.height /2;

       }

上記Unityプロジェクトを利用する際に気を付ける点としては画像をただインポートするだけではだめで、ピクセルの値を取ってこれるようにするためにDepth画像とRGB画像のインスペクタにある"Read/Write Enabled"にチェックを付ける必要があります。結構時間がかかります。

スクリーンショット 2021-11-17 200045

LeanTouchを利用して、点群をタッチ操作できるようにしてあるので、自分の好きな場所におくことができます。

4. ARで見る

ここまで終わればスマホにデプロイして完了です。現実世界の好きなところで電車が出てくるのはとても違和感があって面白いです。リュミエール兄弟の時代の観客の驚きを追体験するまではいかないかもしれないですが、いろんな表現の可能性がありそうです。

終わりに

AR/VR、メタバースの世界観を実現するにあたって、体験できるコンテンツの量やバリエーションが問題になってくるのではないかなとぼんやりと思っています。基本的には3Dモデルが主になってくると思いますが、3Dデータは画像や動画、音声などと比べると気軽に作れるものではありませんし、まだまだインターネット上に公開されている絶対数が少ないのではないかと思います。もちろん3Dモデルを簡易に作れるようにするアプローチもありますが、既存のメディアのコンテンツをうまく3D空間に落とし込めたら、メタバースの世界がもっと多様で面白い世界になるのではないかと思っています。

謝辞

Takashi Yoshinagaさんのこのリポジトリに公開されている深度画像を3D空間に再投影する方法を参考にして作成しました。


この記事が気に入ったらサポートをしてみませんか?