【VR】パノラマ画像の傾きを補正するアプリを作る【Unity】【Windows】
パノラマ画像の撮影も進化したものでして、昔とは違い、最近はハード側にジャイロ補正が付いていたり天頂補正が付いていたりと、今では基本的に「パノラマ写真が傾いちゃった」という概念すらなくなってきました。嬉しいことです。
一方でパノラマ機材が出始めた初期の頃(もう6、7年前になるのでしょうか。)に撮ったパノラマ画像とかは天地補正情報がなかったりで補正できずお手上げだったりします。同じこと考えている人は結構いるでしょうから同志の方々がアプリを作って配信されているのかもしれませんが、個人的に最近プログラムをゴリゴリ書く機会がちょっと少なくていろいろ溜まっているものもあり、ということで息抜きに遊んでみました。
アプリのダウンロード
Downloadsからどうぞ。Windows版です。
http://christinayan01.main.jp/architecture/archives/3741
以降はこういったアプリの開発に興味がある方向けの内容です。
やってみよう
今回はUnityを使用して次のようなアプローチでやってみることにしました。
簡単に言いますと、
1.自分(=視点)は原点にいることにし、補正前のパノラマ画像を法線が内側を向いた球体に貼り付けます。
2.その球体をくるくる回すと、あるところでパノラマ画像が完全に水平になったかのように見える瞬間があるはずです。
3.この球体の回転状態で、アスペクト比1:1で視野角90度のカメラで上下左右前後の6枚を撮影すればキューブマップが作れまして、キューブマップをパノラマ画像(Equirectangular形式)に変換する(※)。
という作戦です。
※:技術情報は以下を参照。
[Converting a Cubemap into Equirectangular Panorama – stackoverflow]
https://stackoverflow.com/questions/34250742/converting-a-cubemap-into-equirectangular-panorama
アセット
まずは基本となるアセットを配置しましょう。
・でっかい球体(以下skyboxと呼ぶ。)
パノラマ画像のテクスチャをこのskyboxに貼り付けます。法線は全部内側向き。
このオブジェクトのポリゴンが荒いと成果物の品質に影響するのでできるだけ細かいものにしました。今回は30万ポリゴン程度です。
・skyboxマテリアルのシェーダはUnlit。
明るい・暗いなどは無関係にしたいのでこの設定をお忘れなく。
・メインカメラ (MainCamera)
原点に配置してはいますが、殆ど使いません。
スクリプト:マウスイベント
・バッファ取得用カメラ (BGCamera)
ピクセルバッファを取得するためだけのカメラです。原点に配置します。
後で上下左右前後の向きにパシャパシャっと撮るために必要。
・プレビュー用カメラ×4 (CameraEast、CameraWest、CameraSouth、CameraNorth)
今どのくらい天地補正ができたかリアルタイムで確認するためのプレビュー画面に表示するためのピクセルバッファを取得する用のカメラです。天地を知りたいので、左右前後を向いた4つで十分です。位置は原点です。
GUI
Canvasに配置するボタンなどです。
・[開く]ボタン
パノラマ画像ファイルを開く処理が動きます。
・[保存]ボタン
保存処理まで一気に行います。現在の回転状態のskyboxで上下左右前後にBGCameraでピクセルバッファを取得し、補正後の画像を出力するところまでおこなう。
・[X]、[Y]、[Z]回転のスライダー
スライダーを動かすことでskyboxを回転します。上からX軸(左右に傾ける)、Y軸(コマみたいに回す)、Z軸(前後に傾ける)を意味しています。
・[プレビュー]画面
補正具合がひと目でわかるようにしたいのでこういう表示があったほうがいいですよね。これはCameraEastなどのRenderTextureEastと連動させています。4つを水平に並べています。
構築
レイアウト
・skyboxを配置。原点(x,y,z)=(0,0,0)に。
・Main Cameraを配置。これでskyboxが画面いっぱいに入るくらいにする。
・もう1個Cameraを配置。skyboxと同じ座標(0,0,0)。名前は「BGCamera」。Perspective=90 にする。
Render Textureをアセットに追加。BGCameraの[Render Target]にセット。
・さらにもう4個プレビュー用のCameraを置きます。
全部原点に配置。名前はそれぞれ「CameraEast」「CameraSouth」「CameraWest」「CameraNorth」。
Perspective=90にする。
またRender Textureを4つアセットに追加。名前は「RenderTextureEast」「RenderTextureSouth」「RenderTextureWest」「RenderTextureNorth」。これもカメラの[Render Target]にセット。
スクリプト
いくつか作ります。
スライダー
スライダーX:skyboxをX軸で回転する。
スライダーY:skyboxをY軸で回転する。
スライダーZ:skyboxをZ軸で回転する。
スライダーを動かすと、0~359の範囲で処理が動きます。
SliderScript::OnValueChanged()関数がイベントを受け取って、とりあえずテキストだけ更新します。
次に共通関数でRotationCubeScript::UpdateCube()関数でスライダー3つの値を寄せ集めて、実際にskyboxを回転します。
開く
開く:パノラマ画像を開く。
保存:回転した画像を保存する。
Windows版と割り切っているのでWindowsコモンダイアログを表示させています。
単純にソースを書いてもだめです。Assets/Plugin/フォルダを作り、System.Windows.Forms.dllファイルをコピー配置します。DLLファイルはC:\Windowsではなくて必ずUnity付属のものにします。たとえば私のUnity環境だと F:\Program Files\Unity\2019.1.6f1\Editor\Data\MonoBleedingEdge\lib\mono\4.5-api\System.Windows.Forms.dll にあるDLLファイルになります。
ファイルを開いたらパノラマ画像の幅と高さを変数にセットしておきましょう。
保存
ちょっと一工夫しまして2段階で処理します。
1.まずはキューブマップを作成します。
解像度はパノラマ画像に依存します。例えばパノラマ画像が4000×2000だとすれば、解像度4000x3000pxの1つの大きなテクスチャを作ります。つまり1面あたり1000x1000pxですね。式にすると元画像の幅がwidth、高さをheightとしたとき、1面の長さlengthは length = width / 4; となります。
このキューブ画像を保持しつつ、次はアスペクト比2:1のパノラマ画像(Equirectangular形式)を作ります。マッピングするテクスチャは入力時と同じで4000x2000pxです。
キューブにしたことで、Equirectangularのどこの位置であるかが対応付けしやすくなっていますから、ゴリゴリとマッピングしていきます。
このでっかい4000x3000pxのテクスチャに一旦以下のようにマッピングし直します。
これは視野角90度でアスペクト比1:1のバッファ取得用のカメラBGCameraオブジェクトを用意していますから、こいつでピクセルバッファを取って、所定の位置に載せていきます。これを上・下・左・右・前・後と6回やります。
2.次にキューブマップをパノラマ画像(Equirectangular形式)に変換します。
最後にパノラマ画像を保存します。<元ファイル名>_adj.png としています。
という流れです。
画質の劣化について
この方法・・・画質落ちるでしょ? と思われるでしょうが、思ったほどでもないです。等倍で見てみても、そうでもないかなと思います。というよりこの画質劣化よりも15秒で補正できるメリットの方が大きいと思っています。私自身意外と使ってます。
Insta360 oneって天地情報をハードに設定できるのですが、どう頑張っても何度補正しても真上にならないので結局こういうソフトが必須だったのです。
ソースコード
公開していますのでよければご利用ください。UnityバージョンはUnity 2019.1.6f1です。
https://github.com/christinayan01/demo/tree/master/EquiAjust
参考サイト
[Converting a Cubemap into Equirectangular Panorama – stackoverflow]
https://stackoverflow.com/questions/34250742/converting-a-cubemap-into-equirectangular-panorama
2 thoughts on “【VR】パノラマ画像の傾きを補正するアプリを作る【Unity】【Windows】”