続・2D映像をVR180へ!「周辺の歪み」を追いかけてGUIアプリ化するまで

みなさん、こんにちは。

以前、sbs_convert.py を使って2D動画をVR180 SBS形式に変換するプロセスをご紹介しました。

SKYBOXの標準設定「180度 / 3D SBS」だけで綺麗に見えるようになり、一旦は「これで完璧!」と満足していたのですが……。

実際にOculus Goで色々な動画をじっくり観返しているうちに、どうしても無視できない「ある違和感」に気づいてしまったのです。

「……あれ? 画面の周辺(特に上の方)、上にビヨーンと歪んでないか……?」

今回は、この周辺歪みを完全に直そうと沼にハマって深追いした話と、その猛省から生まれた「GUIアプリ化」の舞台裏をお届けします。


周辺の歪みを直そうとして「沼」にハマる

前回の実装では、ffmpegの v360 フィルタに h_fov=90:v_fov=70 という数値を渡していました。

実はこの v_fov=70、開発当初は 60(前回の計算通りFOV比3:2)だったのですが、なぜか横に間延びして見えたため、急遽70に変更したという強引な経緯がありました。

「なら、FOVの数値を理論通りにきっちり追い込めば直るのでは?」

そう考えた私は、Claudeと一緒に、ffmpegのソースコード(libavfilter/vf_v360.c)までを読みに行きました。すると、重大な見落としを発見したのです。

v360 フィルタには、出力側のパラメータとは別に入力側の視野角を指定する ih_fov / iv_fov が存在します。input=flat(平面入力)の場合、これを省略すると自動的に 90:45 という固定値で処理されるという隠れた仕様があったのです。

クロップ後の映像比率は 3:2(1.5)なのに、内部では 90:45(2.0)として解釈されていた……。「バグの原因はこれだ!」と確信し、クロップ比率に合わせて明示指定するよう修正。

「これで勝つる!」と意気揚々とOculus Goを覗き込んだところ、衝撃のフィードバックが返ってきました。

「以前のバージョンより歪みが酷くなった。全体的に球面っぽくなって、特に上部の歪みが激しい」

理論上は100%正しいはずの修正が、体感では大悪化するという最悪の結果に終わりました……。


迷走の記録(施策と敗北の歴史)

ここから、施策を試しては砕け散る本格的な迷走フェーズに突入します。

施策狙い・意図実際の結末
ih_fov/iv_fov の明示指定入力FOVの解釈ズレを正しく補正球面のような丸みが強調され、上部の歪みが悪化
v360 フィルタ等を撤去そもそも歪みの発生源(投影変換)を削るSKYBOXの「魚眼VR180」モードでしか見れなくなり、標準では横に圧縮される
出力を fisheye に変更SKYBOXの「魚眼」表示に合わせて再設計完全に破綻。 左右の像が結像せず、画角も激狭に

特に3つ目の「魚眼化」の失敗には、幾何学的な深い罠がありました。

当時の処理順序は「①水平方向に視差シフト」→「②v360で左右独立に魚眼変換」というフローです。

しかし、v360のような非線形変換は、出力の縦位置が入力の横位置にも依存する性質を持ちます。そのため、元々は「純粋な水平方向のズレ(視差)」だったものが、変換後に「左右でズレ方の違う垂直方向のズレ」へ化けてしまい、脳が立体として融合できなくなったのです。

数々の実験を経てたどり着いた、身も蓋もない結論はこちら。

「……何もしなかった初期バージョンが一番マシだな」

コードをすべて前回の状態にロールバックしました。


歪みの正体は「プレイヤー側」にあった

コード側での全滅に打ちひしがれていた時、ふとあることに気づきました。

初期バージョンの動画でも、SKYBOX側で手動で「魚眼VR180」に設定を切り替えると、あの上部の歪みがすっきり緩和されるのです。

前回の記事で「なぜか魚眼モードにすると綺麗に見える」と言っていた現象の正体は、これでした。

  1. こちらが出力した映像は、ih_fov/iv_fov 未指定ゆえに正当なEquirectangular形式から微妙に歪んでいる。
  2. その歪みが、SKYBOXの「魚眼展開ロジック」と偶然にも相殺し合っていた。

コード側で「正解」を求めてこねくり回すより、「プレイヤー側の設定一つで綺麗に見せる」 というアプローチこそが、最もシンプルで破綻のない現実解だったのです。


安全に使える「GUIアプリ化」へ方針転換

「パラメータを迂闊にいじると簡単に事故る」

この教訓を得た私は、「コードを追い込む」のをやめ、「今のコードを安全に・快適に使うためのGUI化」に全力を出すことにしました。sbs_convert.py を PySide6 を使ってデスクトップアプリ化します。

GUI化にあたっては、ユーザー(未来の自分)が事故らないよう、パラメータの導線を厳しく分類しました。

パラメータ分類理由
3D強度(視差スケール)基本設定直感的に立体感を調整でき、破綻しにくい。
中央フォーカス幅基本設定同上。人物中心か風景かで気軽に切り替え。
FOV(h_fov / v_fov)詳細設定(折りたたみ+警告表示)今回散々痛い目を見た危険地帯。触れるが事故りやすいことを明示。
深度クリップ範囲詳細設定通常は触らなくてよい安全化用。

さらに、「間違えて変換を始めてしまった!」という時のために、安全に処理を止められる「中断ボタン」を実装。

深度推定のループ中にキャンセル判定(cancel_token)を挟み、ffmpeg のサブプロセスも 0.2秒間隔で監視して綺麗に kill される仕組みにしました。途中で止めても一時ファイルが残らないので、やり直しもストレスフリーです。

# 深度推定ループでの中断チェック(抜粋)
while True:
    if cancel_token and cancel_token.is_cancelled:
        cap.release()
        out.release()
        raise ConversionCancelled()

    ret, frame = cap.read()
    if not ret:
        break
    # ...

動画を選べば出力名が自動で 元ファイル名_vr180.mp4 になる地味ながら便利な機能も添えて、非常に使い勝手の良いツールへ進化しました。

sbs3d-vrデスクトップアプリ
sbs3d-vrデスクトップアプリ

まとめと学び

今回もまた、エンジニアらしい(?)手痛い学びを得ることになりました。

課題発生した原因最終的なアプローチ
周辺・上部の歪みv360のFOV解釈とクロップ比率のミスマッチプレイヤー側で「魚眼VR180」に設定して解決
FOV修正で悪化理論上の正しさがSKYBOXの内部展開と噛み合わない沼から撤退。コード側の変更を見送り
事故りやすいパラメーター危険な設定値がむき出しになっていたGUI化。 安全な項目と詳細設定を分離

コードの完全改修こそ叶いませんでしたが、「プレイヤー設定でいなす」という現実解と、「誰もが安全に使えるGUIツールを作る」という別方向の着地により、実用性は跳ね上がりました。

GUIアプリのコードは、前回同様 GitHubリポジトリ(taoman26/sbs3d-vr) にマージ済みです。

パラメータをいじって「なんか歪むな……」と悩みをかかえている開発者の方がもしいたら、コードを修正する前に、プレイヤー側の表示モードをそっと変えてみてください。案外、あっけなく解決するかもしれません。


「自分も何か作ってみたい」と思われた方、そのアイデア、頭の中で寝かせておくのはもったいないかもしれません。

ビューローみかみでは、構想段階の壁打ちからPoC・実装・現場導入まで、現場で「使い続けられる」ものづくりを支援しています。

アイデアを短期間で「動くもの」にし、PoCで終わらせず、実運用まで伴走します。まずは「これ、作る価値ありますか?」という壁打ちからでも大歓迎です。

▶ PoC・MVP開発サービスの詳細はこちら

気になることがあればお気軽にご相談ください。

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

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

カテゴリ: Tips

コメントする

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

上部へスクロール