2D映像をVR180へ!Oculus GoとPythonで挑んだ立体視への試行錯誤

みなさん、こんにちは。

最近のYouTubeを見ていると、多くのクリエイターが固定カメラでの自撮りスタイルで、その日のテーマを熱く語る動画を投稿していますよね。人物が中心にいて動きが少ない。実はこのフォーマット、「VR化」と非常に相性が良いのではないかと直感したのが今回の始まりです。

手元には、今となっては懐かしい名機 Oculus Go があります。

「普通の2D動画を、VRゴーグルで没入感のある立体映像として見たい」

そんな欲求から始まった、Pythonスクリプトによる自動変換への試行錯誤を記録としてまとめました。

 


 

そもそも2DからVR化なんてできるのか?(AIへの相談)

 

最初の疑問は単純でした。「2D動画をDepth-Anything(深度推定AI)などを使って、立体的なVR映像に変換できるのか?」ということです。

ChatGPTやPerplexityに壁打ちした結果、見えてきた現実がこちらです。

判明したこと

  • できること
    各フレームの奥行き(Depth Map)を推定し、擬似的な3D(視差)を生成してVR風に見せることは可能。3DoF(首振りのみのVR)なら実用レベルになる。
  • 難しいこと
    2Dには「裏側の情報」がないため、遮蔽された部分は補完になる。また、フレーム間で奥行きが揺れやすい。

結論として、「目の前に人物がいるような擬似立体3D」なら十分狙えると判断しました。

 


 

変換の戦略 – VR180 SBS形式を目指す

 

Oculus Goの定番プレイヤー「SKYBOX」で再生するための最短ルートは、VR180 SBS(Side-by-Side)形式への変換です。

  1. 深度推定
    動画の各フレームから奥行きマップを生成。
  2. ピクセルシフト
    奥行きに応じて、左目用・右目用の映像を横方向にずらす。
  3. SBS書き出し
    左右の映像を横に並べて1本の動画にする。
  4. 投影変換
    平面(Flat)から全球面の一部(Equirectangular)へ変換。

 


 

最初の実装と、直面した「SKYBOXの謎」

 

最初に作成したスクリプト(sbs_convert_360.py)では、深度推定に MiDaS を使い、ffmpegの v360 フィルタで一気に変換をかけました。

ところが、完成した動画をSKYBOXで開くと、なぜか 「180度VR / 魚眼 / モノスコープ」 という、本来の3D設定とは異なる組み合わせでないとまともに見えないという事態に。

なぜそうなったのか?(逆算のロジック)

  • モノスコープ判定の理由
    v360 フィルタに左右結合済みの映像をそのまま渡していたため、左右の分離情報が消滅し、1枚の球面マップとして処理されてしまっていました。
  • 魚眼設定の理由
    正距円筒図法(Equirectangular)特有の周辺の伸びが、SKYBOXの「魚眼モード」による逆補正(バレル歪み)と偶然打ち消し合い、自然に見えていただけでした。

 


 

根本解決 – 正しいパイプラインの再設計(sbs_convert.py

 

「偶然うまく見える」状態から脱却し、SKYBOXの標準設定 「180度 / 3D SBS」 だけで完璧に見える形式を目指して再設計しました。

1. 左右の個別処理

v360 フィルタをかける際、左右の映像を一度バラバラにしてから個別に変換し、最後に再結合するように修正しました。

# 左右を分割して変換、最後に結合するFFmpegフィルタ
filter_complex = (
    "[0:v]crop=iw/2:ih:0:0[L];"
    "[0:v]crop=iw/2:ih:iw/2:0[R];"
    "[L]v360=input=flat:output=equirect:h_fov=90:v_fov=60[LE];"
    "[R]v360=input=flat:output=equirect:h_fov=90:v_fov=60[RE];"
    "[LE][RE]hstack[OUT]"
)

2. 「縦伸び」と「横間延び」の解消

ここが一番のハマりどころでした。VR180は、各眼の映像が「180度×180度」の正方形(1:1)であることを前提としています。

  • 縦伸び対策
    16:9の映像をそのまま変換すると密度に差が出るため、上下に黒帯(Padding)を入れて 1:1の正方形 にしました。
  • 横間延び対策
    視野角(FOV)の比率が計算と合っていないと歪みます。v360に渡す前に映像を 3:2(1.5:1)にクロップ し、FOV比(90°:60°=1.5)と一致させることで解消しました。

 


 

完成したソースコードはこちら

 

今回の試行錯誤の結果、最終的にPythonスクリプト1本で2D動画をVR180に変換できるようになりました。

VR専用コンテンツには及びませんが、それなりに立体化できているなという感じはします。当初の目的だった「人物が中心にいて動きが少ない映像」の立体化には、期待通りの効果を発揮してくれました。

全ソースコードはGitHubで公開しています。

GitHub Repository: taoman26 / sbs3d-vr

使い方のポイント

  • sbs_convert_360.py
    初期の試行錯誤版(SKYBOXでの特殊設定が必要)
  • sbs_convert.py
    推奨版(VR180 SBS標準形式)

深度推定には MiDaS を使用しており、時間はかかりますがCPUでも処理可能です。もちろん、GPU(CUDA)環境があれば高速に処理可能です。

 


 

学びと今後の展望

 

今回の開発を通して痛感したのは、「現象から逆算して理論を埋める」 ことの面白さです。

最初は「なぜか魚眼設定にすると綺麗に見える」という謎の現象から始まりましたが、その理由(歪みの相殺)を突き止める過程で、VRの投影理論やFOVの関係性が一つひとつクリアになっていきました。

課題原因解決策
変な設定が必要左右眼情報が消失個別変換後に結合
映像が縦に伸びるアスペクト比のズレ1:1正方形にPadding
映像が横に間延びFOV比との不一致3:2に事前クロップ

今後は、深度推定モデルを最新の Depth-Anything-V2 に入れ替えて精度を高めたり、被写体の動きに合わせて視差をダイナミックに変える処理などを試してみたいと考えています。

みなさんも、眠っている古いVRゴーグルがあれば、Pythonの力で新しい命を吹き込んでみてはいかがでしょうか?

 

本日も最後までお読みいただきありがとうございました。

それでは、よいVRライフを!

カテゴリ: Tips

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール