ASNARO-1の光学画像を取得

Tag

はじめに

このチュートリアルを通してAPIを利用してASNARO-1の光学画像を取得する方法を学びます。

APIを用いてASNARO-1のシーンデータを取得する

Tellusでは、ASNARO-1(一般財団法人宇宙システム開発利用推進機構とNECが開発した衛星)に搭載された詳細撮影を目的とした光学センサで、解像度0.5mの白黒画像と2mのカラー画像を提供しています。ASNARO-1は、2014年から可視光領域から近赤外領域にかけての波長で地上を観測しています(2020年時点で運用中)。

APIの使い方はリファレンスにまとめられています。

※画像を利用する際は、利用ポリシーを確認して、規約を違反しないように注意してください。

ASNARO-1の衛星画像のシーンデータ(メタデータ)を取得するには座標指定する必要があります。

https://gisapi.tellusxdp.com/api/v1/asnaro1/scene?min_lat={min_lat}&min_lon={min_lon}
&max_lat={max_lat}&max_lon={max_lon}

dev2-1asnaro_20200220_table1.pngそれでは実際にASNARO-1の画像を取得するコードを書いてみましょう。

import os, json, requests, math
from skimage import io
from io import BytesIO
import matplotlib.pyplot as plt
%matplotlib inline
TOKEN = "ここには自分のアカウントのトークンを貼り付ける"
def get_ASNARO_scene(min_lat, min_lon, max_lat, max_lon):
    url = "https://gisapi.tellusxdp.com/api/v1/asnaro1/scene" \
        + "?min_lat={}&min_lon={}&max_lat={}&max_lon={}".format(min_lat, min_lon, max_lat, max_lon)
    headers = {
    	"Authorization": "Bearer " + TOKEN
	}
    r = requests.get(url, headers=headers)
    return r.json()
scene = get_ASNARO_scene(20.425278, 122.933611, 45.557222, 153.986389)

dev2-1asnaro_20200220_1.png

TOKEN = "ここには自分のアカウントのトークンを貼り付ける"

この部分を自分のトークン(APIキー)で上書きします。Tellusで利用できるASNARO-1のシーン情報を取得することができます。取得できたシーンがいくつあるか確認しましょう。

print(len(scene))

このコードを貼り付けて、ツールにある三角マークをクリックしてください。

dev2-1asnaro_20200220_8.png

2019年11月執筆時点では314シーンあることがわかりました。次にシーン情報の中身を確認します。

print(scene[-1])

実行すると、その時点で最新の観測シーンに関する情報が表示されます。 dev2-1asnaro_20200220_7.png

acquisitionDateが撮影日を表すことから、このシーンは2014年12月25日に観測した結果と分かります。場所は福島県福島市のあたりであることが画像中心の緯度経度(clat, clon)からわかります。thumbs_urlをブラウザで開くと、サイズは小さいですが、サムネイルから大体の映り具合を確認できます。

dev2-1asnaro_20200220_2.png

entityIdは光学画像を取得する上で必要な識別番号です。thumbs_urlに含まれる情報でサムネイル画像が表示できることは既に説明しました。オリジナル画像は、さらに高い解像度を持った大きいファイルです。この画像を扱いやすいようにしたものが地図タイル画像となります。TellusではentityIdを知ることで、この地図タイル画像を取得できるAPIを提供しています。

APIを用いてASNARO-1の地図タイル画像を取得する

APIでASNARO-1のタイル画像を取得するには、シーンID、ズーム率とタイル座標のパラメータを設定する必要があります。シーンIDとは、ASNARO-1の観測毎につけられた識別番号のことです。

https://gisapi.tellusxdp.com/ASNARO-1/{scene_id}_AS1/{z}/{x}/{y}.png

dev2-1asnaro_20200220_table2.png 地図タイルとは世界地図を256*256サイズのタイルに切り出したものです。各タイルにXY座標が設定されており、一枚のタイルはズーム率に応じて分割され、高倍率のズームほど詳細な情報の地図タイル画像が取得できます。 地図タイルはTellus OS上でも確認することができます。二分割ツールの右隣にあるグリッドツールから、タイル座標にチェックを入れてください。下図のようにベース地図上にメッシュが作成されます。このようにTellus OS上で地図タイルの座標を調べて用いることもできますが、今回はシーンデータに含まれる座標データ(clat,clon)から、地図タイルの座標を調べてみます。 dev2-1asnaro_20200220_5.png

今回は利用するシーン(entityId:20190115064552292_AS1)の観測範囲内のタイル座標を指定する必要があります。ズーム率と点(緯度経度)を指定すると、その点を含んでいるタイル座標を求める数式があるのでこれを使いましょう。

下ではタイル座標を求める関数を定義しています。タイル座標を求めるために必要な情報は、緯度と経度、そしてズーム率です。関数は与えられた変数に応じて、タイル座標の値を返します。

def get_tile_num(lat_deg, lon_deg, zoom):
    # https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Python
    lat_rad = math.radians(lat_deg)
    n = 2.0 ** zoom
    xtile = int((lon_deg + 180.0) / 360.0 * n)
    ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
    return (xtile, ytile)
zoom = 13 # ズーム率は13とする
(xtile, ytile) = get_tile_num(scene[-1]['clat'], scene[-1]['clon'], zoom)
print(xtile, ytile)

ズーム率を13とした場合、今回のシーンの中心座標(37.6287834761219, 127.1820608503)を含むタイル座標は、(6990, 3170)であることがわかりました。地図タイル画像を取得するために、シーンIDと求めたタイル座標を関数の中で設定しましょう。

scene_id = '20181226061336632_AS1'
zoom = 13
xtile = 6990
ytile = 3170
url = "https://gisapi.tellusxdp.com/ASNARO-1/{}/{}/{}/{}.png".format(scene_id, zoom, xtile, ytile)

変数が与えられ、urlには'https://gisapi.tellusxdp.com/ASNARO-1/20181226061336632_AS1/13/6990/3170.png'が入り、これがデータの場所を示しています。このデータにアクセスするためには、アクセストークンが必要です。

headers = {"Authorization": "Bearer " + TOKEN} # トークンを貼る
r = requests.get(url, headers=headers)
io.imread(BytesIO(r.content))

リクエストが正常に行われていれば、取得した情報から地図タイルの配列情報が表示できているはずです。 dev2-1asnaro_20200220_6.png 一連の流れを関数として定義しましょう。

def get_ASNARO_image(scene_id, zoom, xtile, ytile):
    url = " https://gisapi.tellusxdp.com/ASNARO-1/{}/{}/{}/{}.png".format(scene_id, zoom, xtile, ytile)
    headers = {
        "Authorization": "Bearer " + TOKEN
    }
    r = requests.get(url, headers=headers)
    return io.imread(BytesIO(r.content))

取得された配列情報を画像として表示します。

img = get_ASNARO_image(scene[-1]['entityId'], zoom, xtile, ytile)
io.imshow(img)

dev2-1asnaro_20200220_3.png

Credit : Original data provided by NEC

ASNARO-1による地図タイル画像を取得することができました。 以上が、TellusのJupyter Notebookを使ってASNARO-1の光学画像を取得する方法でした。ズーム率をさらに上げると、建物の形まではっきりわかる解像度の画像を取得することもできます。下図ではzoom = 17へ上げています。

dev2-1asnaro_20200220_4.png

Credit : Original data provided by NEC

TellusではASNARO-1以外の衛星画像も公開されています。是非ご活用ください。 今回使用したスクリプトです。

import os, json, requests, math
from skimage import io
from io import BytesIO
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
TOKEN = "ここに自分のアカウントのトークンを貼り付ける"
def get_ASNARO_scene(min_lat, min_lon, max_lat, max_lon):
	url = "https://gisapi.tellusxdp.com/api/v1/asnaro1/scene"     	+ "?min_lat={}&min_lon={}&max_lat={}&max_lon={}".format(min_lat, min_lon, max_lat, max_lon)
	headers = {
    	"content-type": "application/json",
    	"Authorization": "Bearer " + TOKEN
	}
	r = requests.get(url, headers=headers)
	return r.json()
scenes = get_ASNARO_scene(20.425278, 122.933611, 45.557222, 153.986389)
ext_scene = scenes[-1]
img_thumbs = io.imread(ext_scene['thumbs_url'])
io.imshow(img_thumbs)
def get_tile_num(lat_deg, lon_deg, zoom):
	# https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Python
	lat_rad = math.radians(lat_deg)
	n = 2.0 ** zoom
	xtile = int((lon_deg + 180.0) / 360.0 * n)
	ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
	return (xtile, ytile)
zoom = 13
(xtile, ytile) = get_tile_num(ext_scene['clat'], ext_scene['clon'], zoom)
print(xtile, ytile)
def get_ASNARO_image(scene_id, zoom, xtile, ytile):
	url = " https://gisapi.tellusxdp.com/ASNARO-1/{}/{}/{}/{}.png".format(scene_id, zoom, xtile, ytile)
	headers = {
    	"Authorization": "Bearer " + TOKEN
	}
	r = requests.get(url, headers=headers)
	return io.imread(BytesIO(r.content))
print(ext_scene)
img = get_ASNARO_image(ext_scene['entityId'], zoom, xtile, ytile)
io.imshow(img)
zoom = 17
(xtile, ytile) = get_tile_num(ext_scene['clat'], ext_scene['clon'], zoom)
img = get_ASNARO_image(ext_scene['entityId'], zoom, xtile, ytile)
io.imshow(img)