【JS】360°パノラマ写真からCanvasを使って惑星「リトルプラネット」を作る

#<i class="fa fa-camera" style="font-size:1em;"></i> 概要

「リトルプラネット(Little Planet）」というのをご存知でしょうか？
こういう写真です。


![stock-photo-beautiful-small-green-village-from-above-aerial-view-little-planet-concept-115348069.jpg](https://qiita-image-store.s3.amazonaws.com/0/67591/6ddf9099-19f6-6220-69b1-950a17dfca37.jpeg)

ドラゴンボールの界王星みたいな感じのやつですね。

最近THETAが普及して、気軽に360°撮影が可能になりSNSで投稿する機会が増えたことから、こういうキレイな写真を見かけたことがある方は多いと思います。

実はこれ、特別な画像変換ソフトウェアを使わなくてもTHETA等で撮った360°パノラマ写真さえあれば、canvasタグとJavaScriptだけで、Little Planetに加工することができます。
もちろんPhotoShopでも加工が可能です。
加工の仕方さえわかってしまえば、様々な場面で応用ができるでしょう。

自分も最初はどういう加工を施せばいいのかわかりませんでしたが、

[Webクリエイターボックス](http://www.webcreatorbox.com/)さんの以下の記事で、意外に簡単であることがわかり、ブラウザ上で加工・変換することを思いつきました。
> 	- [まるで界王星！Photoshopで作る惑星風360度パノラマ写真](http://www.webcreatorbox.com/inspiration/polar-panorama-photo/)


#<i class="fa fa-camera" style="font-size:1em;"></i> 作り方

使う素材はこちら

![test.jpg](https://qiita-image-store.s3.amazonaws.com/0/67591/0dabc6e7-2015-bed6-906b-68657018d81b.jpeg)

チャリンコに乗りながら公園で適当に撮った一枚です。
この正距円筒方式の写真をLittle Planetにしてみました。

canvasでどういう処理を行えばいいのかというと、それは至ってシンプルで
以下の3つのポイントだけおさえておけば大丈夫です。

> 	- 写真の幅と高さを同じサイズで正方形にする
> 	- 写真を180°反転させる

![スクリーンショット 2015-12-28 1.44.22.png](https://qiita-image-store.s3.amazonaws.com/0/67591/771c288f-9503-a113-c9bd-483e40cb918e.png)

これが正方形に変形させて、反転した状態です。
そして、、

> 	- canvasを**極座標**に変換する

「**極座標**」って何？って話ですが、、

通常、x軸とy軸で交わる部分を点であらわすことが多いと思いますが、これは直交座標というもので、

これに対し極座標と言うのは原点からの方向（角度）と距離で位置を表します。


![Untitled.png](https://qiita-image-store.s3.amazonaws.com/0/67591/350addf9-3b01-fea0-81e2-045145bd29f1.png)


世界地図で言えば、南極点を中心に円状に広がっていくあの地図です。

電測(レーダー）にも使われてますね。


#<i class="fa fa-camera" style="font-size:1em;"></i> プログラムで画像を処理

以下使用したコードの詳細です。

Canvasを極座標に変換する方法についてはこちらのサイトを参考にしました。というより一部コードを引用させていただきました。

> 	- [ゲーム製作でHTML5-Canvasを勉強するぞ！！ 第6回](http://murakya.net/blog/2011/02/html5-canvas-6.html)

参考先でも述べられているように、Canvasを極座標に変換する適当な関数が無いので自前で作る必要があります。

変換元のフィールドに描画して、そこからgetImageDataで取得して、変換された形で再描画しています。


```js:js



var WIDTH = 500;
var HEIGHT = 500;
var img = new Image();
img.src = "test.jpg";
var rotDig = 0;

window.onload = function (){
	test();
}

function test() {

	var canvas = document.getElementById('canvas');

	var hw = WIDTH / 2;
	var hh = HEIGHT / 2;
	var r = Math.sqrt(hw * hw + hh * hh);
	var lut = [];
	var pos = 0;

	for (var y = 0; y < HEIGHT; y++){
		for (var x = 0; x < WIDTH; x++){
			var sx = Math.atan2(y - hh, x - hw) * hw / Math.PI + hw;
			var sy = Math.sqrt((x - hw) * (x - hw) + (y - hh) * (y - hh));
			sy = (r - sy) / r;
			sy = HEIGHT - sy * sy * HEIGHT - 1;

			if (sx < 0) sx = 0;
			if (WIDTH - 1 < sx) sx = WIDTH - 1;
			if (sy < 0) sy = 0;
			if (HEIGHT - 1 < sy) sy = HEIGHT - 1;

			sx = Math.round(sx);
			sy = Math.round(sy);

			lut[pos++] = (sy * WIDTH + sx) * 4 + 0;
			lut[pos++] = (sy * WIDTH + sx) * 4 + 1;
			lut[pos++] = (sy * WIDTH + sx) * 4 + 2;
			lut[pos++] = (sy * WIDTH + sx) * 4 + 3;
		}
	}

	if (canvas.getContext) {
		var ctx = canvas.getContext('2d');
		var angle = 180*Math.PI/180;
		ctx.rotate(angle);
		ctx.translate(-WIDTH, -HEIGHT);
		ctx.drawImage(img, 0, 0, WIDTH, HEIGHT);

		var output = ctx.getImageData(0, 0, WIDTH, HEIGHT);

		var imageData = ctx.getImageData(0, 0, WIDTH, HEIGHT);
		var src = imageData.data;
		var dst = output.data;
		for (var n = 0; n < HEIGHT * WIDTH * 4; n++){
			dst[n] = src[lut[n]];
		}
		ctx.putImageData(output, 0, 0);
	}

}


```

#<i class="fa fa-camera" style="font-size:1em;"></i> 完成形

![スクリーンショット 2015-12-28 0.41.12.png](https://qiita-image-store.s3.amazonaws.com/0/67591/978ef7fc-675f-52ad-edf7-fe508eaedc12.png)

意外にきれいに仕上がります！


#<i class="fa fa-camera" style="font-size:1em;"></i> 最後に

これ、、、、恐らくvideoタグを読み込めば同じ方法でできると思うので、また時間あるときにやってみます。

360°パノラマはやはりLittle Planetに加工するのがやはり一番きれい！
なんで、これからどんどん撮影して惑星を作っていきたいと思います。

#<i class="fa fa-camera" style="font-size:1em;"></i> 参考

> 	- [まるで界王星！Photoshopで作る惑星風360度パノラマ写真](http://www.webcreatorbox.com/inspiration/polar-panorama-photo/)
> 	- [ゲーム製作でHTML5-Canvasを勉強するぞ！！ 第6回](http://murakya.net/blog/2011/02/html5-canvas-6.html)