GDAL で RICOH THETA 画像を再投影

FOSS4G AdventCalendar 4日目です。

## RICOH THETA

RICOH の THETA という360度カメラがあります。撮影した画像を [THETA の閲覧用ソフト](https://support.theta360.com/ja/download/)を使って開くと、ぐりぐり動かして遊ぶことができます。

* [【宇宙からの写真】宇宙初搭載 RICOHとJAXAの共同開発によるTHETA S ISS(国際宇宙ステーション)船外搭載](https://www.thetalab.ricoh/article/2651/)


THETA で撮影した、このぐりぐり動かせるデータはどのようなデータかというと、こんな横長の単なる画像です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215290/d7510cbe-b447-a6b1-e544-286913f54d5c.jpeg" width="50%" style="margin:0;padding:0;">

写真は Wikimedia Commons に CC BY 2.0 で公開されているものを使用させていただきました。

* [File:Photo from Ricoh Theta S after horizont correction (31850880602).jpg](https://commons.wikimedia.org/wiki/File:Photo_from_Ricoh_Theta_S_after_horizont_correction_(31850880602).jpg)
  * Artem Svetlov from Moscow, Russia, CC BY 2.0 <https://creativecommons.org/licenses/by/2.0>, via Wikimedia Commons


たとえば、このようにグリッド線を追加して、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215290/7cd34b88-6fb1-181f-36ba-0bcffe186078.jpeg" width="50%">

THETA アプリで表示させるとこんなふうになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215290/177bb818-c833-38d1-6327-e67da920ed19.jpeg" width="50%">

実は RICOH THETA の写真データは正距円筒図法で投影変換されて保存されており、 THETA アプリでは単なる画像を動的に投映変換しながら表示しています。

* [360度カメラの仕組み、エクイレクタングラー形式についてRICOH THETAを題材にご紹介！](https://www.thetalab.ricoh/article/8212/)

## さあ！　再投影の時間だ！

元のデータが正距円筒図法ということがわかっていれば、他のプロジェクションに変換することも可能ですよね！

というわけで GDAL で再投影してみましょう。

### 下準備

まずは写真データを世界地図とみなして位置情報を付与します。横が $\left[ -180^\circ, 180^\circ \right]$ 、縦が $\left[ -90^\circ, 90^\circ \right]$ に相当することを、ワールドファイルで示してやればよいのです。ワールドファイルは非常に単純な形式なので手書きやスクリプトで生成してもいいのですが、今回は GDAL でワールドファイル付きの画像を生成し、いらない画像を削除することで入手します。

```shell-session
# もともと theta.jpg があるとする
$ gdal_translate -a_ullr -180 90 180 -90 -of JPEG -CO WORLDFILE=YES theta.jpg theta_.jpg

# 生成されたワールドファイル theta_.wld を theta.wld にリネームし、もとの画像に紐付ける
$ mv theta_.wld theta.wld

# いらないデータを削除
$ rm theta_.*
```

作成されたワールドファイルの中身はこんなやつです。

```shell-session
$ cat theta.wld
0.0669642857
0.0000000000
0.0000000000
-0.0669642857
-179.9665178571
89.9665178571
```

RICOH THETA S の場合、画像サイズは5,376 × 2,688なので、解像度は $res_x = \frac{360}{5376}, res_y = -\frac{180}{2688}$、左上ピクセルの中心位置は $\left( -180+\frac{res_x}{2}, 90+\frac{res_y}{2} \right)$ になります。

### メルカトル図法

このデータを、まずはみんな大好きメルカトル図法に再投影してみます。

地球のように楕円体を考慮する必要はないので、単に `+R=6378137` としています。別に統一されていればなんでもいいはずなので、 $\pi R$ がきれいになるように `+R=572.9578` とかでもいいんですけどね。

表示する範囲を `-te` で指定します（半径 `R` の球とみなし、球表面を `proj` の手法で平面投映したあとの紙面上の範囲）。今回は、生成する範囲は縦横ともに $\[-\pi{}R, \pi{}R\]$ とします。これは経度 $\[-180^\circ, 180^\circ\]$, 緯度 $\[-85.051^\circ, 85.051^\circ\]$ に相当します。

```shell-session
$ gdalwarp -s_srs "+proj=longlat +R=6378137" -t_srs "+proj=merc +R=6378137 +lat_0=0 +lon_0=0" -r cubic -te -20037508.34 -20037508.34 20037508.34 20037508.34 -ts 1000 1000 theta.jpg theta_merc.tif
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215290/16d82a9c-a117-bdf1-750e-8809b4d395de.jpeg" width="50%">

広角レンズ（魚眼レンズ）の歪みはもちろんありますが、上下が圧縮されていない分、だいぶ自然な感じがしますね。更に地面部分や天頂部分を削除すると、全周パノラマ画像といった感じになるでしょう。

なお、 `gdalwarp` の出力は JPEG 形式非対応なので、 GTiff で生成しています。

### 横メルカトル図法

メルカトルの次は横メルカトルです。基準経度は0度でやってみます。 

```shell-session
$ gdalwarp -s_srs "+proj=longlat +R=6378137" -t_srs "+proj=tmerc +R=6378137 +lat_0=0 +lon_0=0" -r cubic -te -10000000 -10000000 10000000 10000000 -ts 1000 1000 theta.jpg theta_tmerc.tif
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215290/5584e8e8-5acf-dd7b-382d-5b2bc93fd3e5.jpeg" width="50%">

メルカトル図法は垂直方向はまっすぐ表現できていますが、横メルカトルだと水平方向がちゃんと表現されていますね。

大縮尺で詳細な地図では横メルカトル図法である、平面直角座標系や UTM が多く使われます。基準とする子午線から離れることによって、北の方位（真北）が地図上の北（方眼北）とは異なる方位となる性質を持つことは留意しておく必要があります。

### 正距方位図法

次に、自分が中心である全天モデルを考え、通常のカメラで撮影したときのことを考えてみます。

ある程度画角が狭い場合、ある点を中心とする方位図法を使うとよさそうです。そのなかでも、画角が2倍になればその画角で切り取られる円弧長も2倍になるような特徴を表現できる正距方位図法を使えばいい気がします。なんとなくですが。

とりあえず正距方位図法で再投影してみます。

中心点は $\left(0^\circ, 40^\circ\right)$ 、範囲は水平画角80度、垂直画角60度相当にしてみます。つまり正距方位図法の場合、水平範囲は $\left[-\frac{40}{180}\pi{}R, \frac{40}{180}\pi{}R\right]$ 、垂直範囲は $\left[-\frac{30}{180}\pi{}R, \frac{30}{180}\pi{}R\right]$ とすればよいです。

```shell-session
$ gdalwarp -s_srs "+proj=longlat +R=6378137" -t_srs "+proj=aeqd +R=6378137 +lat_0=40 +lon_0=0" -r cubic -te -4452779.61 -3339584.72 4452779.61 3339584.72 -ts 1200 900 theta.jpg theta_aeqd.tif
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215290/be4db637-54c0-085f-1bac-c90171b6d6ca.jpeg" width="50%">

おー。いい感じに変換できていますね。

水平画角80度だと、35mmフィルム換算で焦点距離21mmくらいの広角レンズに相当します。

## おわりに

RICOH THETA って周囲の状況をつかむのに適していますし、単純に結構おもしろくて楽しいんですが、いざ静止画として切り出すのに困るんですよね。

ということで、 GDAL を使った写真の再投影をしてみました。また、実用性はないかもしれませんが、他のプロジェクションを使うとおもしろい絵になるかもしれません。