MPOファイルの構造を解析してVR180用に変換するPythonツールを作った
きっかけ
FujiFilm の FinePix REAL 3D W1 という古いステレオカメラで撮った MPO 形式のステレオ写真を、 VRヘッドセットで立体視したいというのが以前からやりたくて、VEGAS Pro で3D動画編集を行い、VR180形式に変換することで、一応立体視ができる様にはなっていました。
しかし、画像が湾曲した状態になり非常に違和感が残る状態でしたが、その修正方法がわからなかった。
最近、ステレオフォトメーカーProで、エクイレクタングラー変換できることを知って、試してみると、VR空間上で平面のスクリーン上にステレオ画像を投影しているような状態を作ることができました。
かなり視聴しやすい状態になり、このような表示を実現する方法がやっと判明したというところです。

やりたかったこと
普通にエクイレクタングラー変換すると、180度×180度の半天球を前提にした画像になってしまいます。
180度写るカメラならばそれでよいのですが、FinePix REAL 3D W1の視野角はせいぜい60度くらいです。
半天球のうちの中央の一部にしか画像がなく、あとは黒い背景となります。
画像部分の解像度を維持しようとすると、とんでもなく大きな画像を扱わなければなりません。
VR180動画の場合、編集ソフトの関係で解像度は4Kまで。
そのほんの一部しか実際の画像に使われないため、オリジナルのステレオ写真の解像度と比べるとかなり解像度が低くなってしまう。すなわち荒い映像となってしまいます。
対策として、視野角を制限することで、できる限り動画解像度全体を有効利用できるようにします。
最終的にVR180 Creatorでメタ情報を埋め込む際に「視野角60度」という設定を行うことで、これが可能となります。

と、ここまでは、今までにも出来ていたことです。
問題はVRヘッドセットで見たときに写真が大きく湾曲しているところです。
エクイレクタングラー変換を行うことで、ステレオ写真をVR空間に置いた60度幅の仮想平面スクリーンに投影した状態を作ることが出来ます。
しかし1枚1枚手作業で変換が必要で、枚数が多いと非常に面倒くさい単純作業を繰り返さないといけないのですが、過去に作ったVR180動画を頑張って作り直してみました。
あまりに苦痛な作業だったので、Claude で変換ツールを作成してみることにしました。
(左が元の写真の左目側、右が変換後。赤枠がキャンバス全体で、写真の周囲は黒で埋まります)
わずかに樽型に変換されていますが、これによりVR空間では平面的に見えるようになります。

できたもの
Python のスクリプトを2本作ってもらいました。自分ではコードを一切書いていません。やりたいことを伝えて、見た目がおかしいところを都度直してもらっただけです。
batch_vr180_60deg.py— REAL 3D W1 の MPO ファイル(ステレオペア)をフォルダごと一括変換equirect_mono_60deg.py— 普通のデジタルカメラの JPEG 写真用
ソースは GitHub に置きました(MIT ライセンス)
https://github.com/takesa03/batch_vr180_60deg
どちらも元の EXIF 情報(撮影日時やカメラ機種名)を引き継いだまま、指定した画角(既定60度)のぶんだけ画像を配置し、それ以外は黒で埋める形にしています。
使い方はフォルダを指定して実行するだけです。
pip install -r requirements.txt
python batch_vr180_60deg.py --src <MPOフォルダ> --out <出力先>
python equirect_mono_60deg.py --src <JPEGフォルダ> --out <出力先>
MPOファイルの中身を解析することに
ステレオの MPO ファイルは JPEG が2枚、独自の構造(MPF)でひとつのファイルにまとまっています。
Pillow というライブラリで開く分には何でもなかったのですが、StereoPhoto Maker という検証用のソフトで開こうとすると「開けません」とだけ表示されて弾かれてしまいました。
Claude に、StereoPhoto Maker 自身が書き出したファイルを渡して元ファイルとバイト単位で比較してもらったところ、原因が分かりました。
- ステレオの基線長・輻輳角を記録している部分(Attribute IFD)が、変換後のファイルから欠けていた
- 2枚目の画像(右目側)にも、1枚目と同じように独自のExif情報とMPF情報が必要 だった。1枚目にだけ付けていたのが原因
どちらも、元ファイルの該当する部分をそのままバイト単位で複製することで解決しました。
ファイルサイズが小さくなって不安になった話
変換後、元の写真より明らかにファイルサイズが小さくなっていることに気付きました。情報が欠けているのではと心配になり、画質をできるだけ落とさないよう直してもらいました。
理由を聞くと、黒く塗りつぶした部分は JPEG の圧縮が非常に効きやすいため、見た目の画質を保ったままファイルサイズが小さくなるのは自然なことだそうです。
とはいえ圧縮設定自体はまだ画質優先にできる余地があったとのことで、画質最大・色情報を間引かない設定に変更してもらいました。
画角を正確に再現する方向から、思い切って単純化
通常のデジタルカメラ用のスクリプトを作ってもらう際、最初は EXIF に記録されたレンズの焦点距離から実際の画角を計算する、という精密な作りにしてもらいました。
ただ、よく考えると今回やりたいのは「カメラが実際に写した範囲を正確に再現すること」ではなく、「写真を仮想スクリーンとして配置すること」です。
そこで方針を変え、画角の計算はやめて「写真の横幅がそのまま指定した角度になる」という単純な考え方に直してもらいました。縦方向は写真自体の縦横比から決まるので、画面が歪むことはありません。
