【ゼロからのTellusの使い方】AVNIR-2のオルソ補正画像プロダクトを表示させる
JAXAの「だいち」という衛星に搭載されたAVNIR-2(あぶにーるつー)というセンサのオリジナルデータのAPIをTellus上で公開しました!その使い方をご紹介します。
記事作成時から、Tellusからデータを検索・取得するAPIが変更になっております。該当箇所のコードについては、以下のリンクをご参照ください。
https://www.tellusxdp.com/ja/howtouse/access/traveler_api_20220310_
firstpart.html
2022年8月31日以降、Tellus OSでのデータの閲覧方法など使い方が一部変更になっております。新しいTellus OSの基本操作は以下のリンクをご参照ください。
https://www.tellusxdp.com/ja/howtouse/tellus_os/start_tellus_os.html
TellusでJAXA提供のAVNIR-2のオリジナルデータ(GeoTiff)を利用できるようになりました。オリジナルデータを利用することで、これまでよりも広い範囲のデータを一度に扱えるようになります。
本記事では、開発環境でAVNIR-2(オルソ補正画像プロダクト)のオリジナルデータを取得する方法を紹介します。
AVNIR-2はJAXAが提供する衛星データです。Tellus内で利用が可能で、二次成果物を作成した際は、(c)JAXAの表記が必要となります。詳しくはTellusのデータカタログをご覧ください。
AVNIR-2(オルソ補正画像プロダクト)のオリジナルデータを取得してみよう
オリジナルデータは、次の3ステップで取得できます。
1. ファイル検索
取得したい条件に一致するファイルのメタ情報を検索します。
↓
2.ダウンロードURL発行
ファイルのメタ情報から、ファイルをダウンロードするためのURLを発行します。
↓
3.ダウンロード
ファイル取得URLからファイルを開発環境にダウンロードし、保存します。
Tellusで開発環境(Jupyter Lab)を使う方法は、「Tellusの開発環境でAPI引っ張ってみた」をご覧ください。
ファイル検索API
ファイル検索は、以下のAPIを利用します。
https://file.tellusxdp.com/api/v1/origin/search/avnir2-ori
引数
名称 | クエリ | 型 | 絞り込み条件 |
検索開始時刻 | after | str(ISO8601) | observation_datetimeがこれ以降なら返却します。 |
検索終了時刻 | before | str(ISO8601) | observation_datetimeがこれ以前なら返却します。 |
雲量 | cloud_cover | float | cloud_coverがこの値以下のものを返却します。 引数が有効な値だった場合、エラー値(99)は返却されません。 |
RSPパス番号 | rsp_path_number | int | 完全一致 |
RSPフレーム番号 | rsp_frame_number | int | 完全一致 |
最小ポインティング角 | min_pointing_angle | float | pointing_angleがこの値以上のものを返却します。 |
最大ポインティング角 | max_pointing_angle | float | pointing_angleがこの値以下のものを返却します。 |
シーンID | scene_id | str | 完全一致 |
検索範囲 | left_bottom_lon right_top_lon left_bottom_lat right_top_lat |
アウトライン(min_lat, min_lon, max_lat, max_lon)の矩形が一部でもこの範囲に含まれていれば返却します。 https://tools.ietf.org/html/rfc7946#section-5 |
|
取得数 | page_size | int | 1回のリクエストで取得する件数を指定できます。 デフォルト100件 最大1000件 |
返却値
データ名称 | プロパティ名 | 型とサンプル |
位置(四隅) | coordinates | array of float
[ 例) |
シーン中心時刻(UTC) | center_datetime | str(ISO8601)
例) 2006-11-10T01:48:05.325279+00:00 |
軌道方向 | orbit_direction | str
Dがディセンディング軌道、 Aがアセンディング軌道 |
RSPパス番号 | rsp_path_number | int |
RSPフレーム番号 | rsp_frame_number | int |
シーン中心通算軌道番号 | total_orbit_number | int |
シーン中心フレーム番号 | frame_number | int |
シーンシフト量 | scene_shift | int |
雲量参考情報 | cloud_cover | int |
太陽仰角 | sun_elevation_angle | float |
太陽方位角 | sun_azimuth_angle | float |
ポインティング角 | pointing_angle | float |
各バンド値のゲイン | gain | array of float
[band1, band2, band3, band4] 例) [0.588, 0.573, 0.502, 0.557] |
各バンド値のオフセット | offset | array of float
[band1, band2, band3, band4] 例) [0.0, 0.0, 0.0, 0.0] |
シーンID | scene_id | str
例) ALAV2A042302850 |
dataset名 | dataset_id | str
例) ALAV2A042302850-OORIRFU-D075P0-20061110-001 |
データセットのファイル一覧 | files | array of string [ filename1, filename2, … ]例) [ ‘IMG-02-ALAV2A042302850-OORIRFU-D075P0-20061110-001.tif’, … , ‘HDR-ALAV2A042302850-OORIRFU-D075P0-20061110-001.txt’ ] |
Tellusでの公開日 | date_added | str(ISO8601) |
代表時刻 | observation_datetime | str(ISO8601)
center_datetimeと同じ値です。 |
範囲 | bbox | array of float
[left_lon, bottom_lat, right_lon, top_lat] 例) [138.9756564, 36.174298, 140.1360529, 37.0726605] |
発行リンク | publish_url | 例)
https://file.tellusxdp.com/api/v1/origin/publish/avnir2-ori/ALAV2A042302850-OORIRFU-D075P0-20061110-001 |
1.ファイル検索
まずは、ファイル検索APIを実行するメソッドを作成しましょう。
トークンはマイページのAPIアクセス設定(要ログイン)から取得してください。
import os, requests
import pprint
TOKEN = ‘ここには自分のアカウントのトークンを貼り付ける'
DOMAIN = 'tellusxdp'
# ファイル検索メソッド
def search_file(params={}, next_url=''):
if len(next_url) > 0:
url = next_url
else:
url = 'https://file.{}.com/api/v1/origin/search/avnir2-ori'.format(DOMAIN)
headers = {
'Authorization': 'Bearer ' + TOKEN
}
r = requests.get(url, params=params, headers=headers)
if not r.status_code == requests.codes.ok:
r.raise_for_status()
return r.json()
このメソッドは辞書型のparamsを受け取り、該当するファイルのヘッダテキストファイルをjson型で返却します。
ファイル検索を実行してみましょう。
今回は検索条件として、以下を設定しています。
– 雲量10%以下
– ポインティング角が20deg以下
– 一度に取得する件数は3件
# サンプル1
# 雲量10%以下 かつ ポインティング角が20deg以下、一度に取得する件数は3件
metas = search_file({'cloud_cover': 10, 'min_pointing_angle': 20, 'page_size': 3})
# 検索結果を表示
pprint.pprint(metas)
実行すると、次のような結果が表示されます。
{'count': 3,
'items': [{'bbox': [138.9756564, 36.174298, 140.1360529, 37.0726605],
'center_datetime': '2006-11-10T01:48:05.325279+00:00',
'cloud_cover': 0,
'coordinates': [[138.9756564, 36.3759473],
[139.8980412, 36.174298],
[140.1360529, 36.8693836],
[139.2058268, 37.0726605]],
'dataset_id': 'ALAV2A042302850-OORIRFU-D075P0-20061110-001',
'date_added': '2020-01-10T15:42:32.298772+00:00',
'files': ['IMG-02-ALAV2A042302850-OORIRFU-D075P0-20061110-001.tif',
'IMG-04-ALAV2A042302850-OORIRFU-D075P0-20061110-001.tif',
'IMG-03-ALAV2A042302850-OORIRFU-D075P0-20061110-001.tif',
'HDR-ALAV2A042302850-OORIRFU-D075P0-20061110-001.txt',
'IMG-01-ALAV2A042302850-OORIRFU-D075P0-20061110-001.tif'],
'frame_number': 2850,
'gain': [0.588, 0.573, 0.502, 0.557],
'observation_datetime': '2006-11-10T01:48:05.325279+00:00',
'offset': [0.0, 0.0, 0.0, 0.0],
'orbit_direction': 'D',
'pointing_angle': 21.5,
'publish_link': 'https://file.tellusxdp.com/api/v1/origin/publish/avnir2-ori/ALAV2A042302850-OORIRFU-D075P0-20061110-001',
'rsp_frame_number': 2850,
'rsp_path_number': 75,
'scene_id': 'ALAV2A042302850',
'scene_shift': 0,
'sun_azimuth_angle': 168.9431399,
'sun_elevation_angle': 35.5860298,
'total_orbit_number': 4230},
{'bbox': [138.3449177, 34.2143897, 139.4736153, 35.10965],
},
{'bbox': [138.1906085, 33.7231867, 139.3123251, 34.6170302],
}],
'next': 'https://file.tellusxdp.com/api/v1/origin/search/avnir2-ori?cursor=eyJjdXJzb3JfbGFzdF90aW1lIjogIjIwMDYtMTEtMTBUMDE6NDg6NDYuMzg2Mzg2IiwgImN1cnNvcl9iZWdpbl90aW1lIjogIjIwMDYtMTEtMTBUMDE6NDg6MDUuMzI1Mjc5IiwgInN0YXJ0X3RpbWUiOiAiMTk3MS0wMS0wMVQwMDowMDowMCIsICJlbmRfdGltZSI6ICIyMDIwLTAxLTE4VDEzOjQyOjIxLjQ1MTY5MSIsICJtaW5fcG9pbnRpbmdfYW5nbGUiOiAyMC4wLCAiY2xvdWRfY292ZXIiOiAxMC4wfQ=='}
返却値の一番最後、nextというキー名でURLが設定されています。
これは、設定した条件に該当するデータ数が多く一度に全件を取得しきれなかった場合や、取得件数の上限を設定した場合に、今回の実行結果の続きからデータを取得するためのURLです。
次はこのURLを引数に設定して、続きの1件を取得してみましょう。
# サンプル2
# 同じ条件で続きを取得する、取得件数を1件にする
metas = search_file({'page_size': 1}, next_url = metas['next'])
pprint.pprint(metas)
こちらの実行結果は以下のようになります。
{'count': 1,
'items': [{'bbox': [138.749406, 34.426666, 140.3650394, 35.4539698],
'center_datetime': '2011-04-01T01:55:29.999478+00:00',
'cloud_cover': 0,
'coordinates': [[138.749406, 34.7618061],
[140.1085505, 34.426666],
[140.3650394, 35.1162994],
[138.9952686, 35.4539698]],
'dataset_id': 'ALAV2A276132870-OORIRFU-D080P0-20110401-000',
'date_added': '2020-01-10T15:42:32.298772+00:00',
'files': ['IMG-02-ALAV2A276132870-OORIRFU-D080P0-20110401-000.tif',
'HDR-ALAV2A276132870-OORIRFU-D080P0-20110401-000.txt',
'IMG-01-ALAV2A276132870-OORIRFU-D080P0-20110401-000.tif',
'IMG-03-ALAV2A276132870-OORIRFU-D080P0-20110401-000.tif',
'IMG-04-ALAV2A276132870-OORIRFU-D080P0-20110401-000.tif'],
'frame_number': 2870,
'gain': [0.588, 0.573, 0.502, 0.557],
'observation_datetime': '2011-04-01T01:55:29.999478+00:00',
'offset': [0.0, 0.0, 0.0, 0.0],
'orbit_direction': 'D',
'pointing_angle': 38.0,
'publish_link': 'https://file.tellusxdp.com/api/v1/origin/publish/avnir2-ori/ALAV2A276132870-OORIRFU-D080P0-20110401-000',
'rsp_frame_number': 2870,
'rsp_path_number': 80,
'scene_id': 'ALAV2A276132870',
'scene_shift': 0,
'sun_azimuth_angle': 156.295176,
'sun_elevation_angle': 57.2636783,
'total_orbit_number': 27613}],
'next': 'https://file.tellusxdp.com/api/v1/origin/search/avnir2-ori?cursor=eyJjdXJzb3JfbGFzdF90aW1lIjogIjIwMTEtMDQtMDFUMDE6NTU6MjkuOTk5NDc4IiwgImN1cnNvcl9iZWdpbl90aW1lIjogIjIwMTEtMDQtMDFUMDE6NTU6MjkuOTk5NDc4IiwgInN0YXJ0X3RpbWUiOiAiMTk3MS0wMS0wMVQwMDowMDowMCIsICJlbmRfdGltZSI6ICIyMDIwLTAxLTE2VDEwOjUyOjU4LjEwNzczOCIsICJtaW5fcG9pbnRpbmdfYW5nbGUiOiAyMC4wLCAiY2xvdWRfY292ZXIiOiAzMC4wfQ=='}
同じ条件で、次の1件のデータが取得できました。
さらに条件を絞って検索してみましょう。
今度は、指定した時刻以降に撮影されたファイルを取得します。
# サンプル3
# 指定時刻以降
metas = search_file({'after': '2010-10-05T15:00:00.000000+00:00', 'page_size': 3})
pprint.pprint(metas)
こちらの実行結果は以下のとおりです。
{'count': 3,
'items': [],
'next': 'https://file.tellusxdp.com/api/v1/origin/search/avnir2-ori?cursor=eyJjdXJzb3JfbGFzdF90aW1lIjogIjIwMTAtMTAtMDZUMDE6NDg6MTcuOTUzODEwIiwgImN1cnNvcl9iZWdpbl90aW1lIjogIjIwMTAtMTAtMDZUMDE6NDg6MDEuNTIwMjU5IiwgInN0YXJ0X3RpbWUiOiAiMjAxMC0xMC0wNVQxNTowMDowMCIsICJlbmRfdGltZSI6ICIyMDIwLTAxLTIxVDE1OjI2OjUyLjA5ODY4OSJ9'}
「2010年10月5日以降に撮影」という条件で検索した結果を、page_sizeで指定した件数の3件表示しています。
2.ダウンロードURL発行
検索したファイルは、ダウンロードすることで実際のデータを確認できます。
次は、ファイルをダウンロードするためのURLを発行しましょう。
ファイルをダウンロードするためのURLを発行するメソッドを作成します。
# ダウンロードURL発行メソッド
def publish_file(dataset_id='', searched_url=''):
if len(searched_url) > 0:
url = searched_url
else:
url = 'https://file.{}.com/api/v1/origin/publish/avnir2-ori/{}'.format(DOMAIN, dataset_id)
headers = {
'Authorization': 'Bearer ' + TOKEN
}
r = requests.get(url, headers=headers)
if not r.status_code == requests.codes.ok:
r.raise_for_status()
return r.json()
ダウンロードURL発行メソッドを実行してみましょう。
このメソッドは、2種類の方法で実行できます。
まずは、先ほどのファイル検索メソッドを用いて、検索結果の先頭にあるデータからURLを発行する方法です。
# サンプル4
# 取得用URL発行(検索結果から取得したい場合)
# ファイル検索
metas = search_file({'page_size': 10})
# ダウンロードURL発行
published = publish_file(searched_url=metas['items'][0]['publish_link'])
# 結果を表示する
pprint.pprint(published)
こちらの実行結果は以下です。
{'dataset_id': 'ALAV2A013272710-OORIRFU-D066P3-20060425-000',
'expires_at': '2020-01-18T20:29:06.307812+00:00',
'files': [{'file_name': 'IMG-02-ALAV2A013272710-OORIRFU-D066P3-20060425-000.tif',
'file_size': 58112471,
'url': 'https://file.tellusxdp.com/api/v1/origin/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzkzMzYxNDYsImV4cCI6MTU3OTM3OTM0NiwiYXBpX3Rva2VuIjoiVEgwRS04UWRlTFZnIiwiZGF0YXNldCI6ImF2bmlyMi1vcmkiLCJrZXkiOiJBTEFWMkEwMTMyNzI3MTAtT09SSVJGVS1EMDY2UDMtMjAwNjA0MjUtMDAwIiwiZmlsZV9uYW1lIjoiSU1HLTAyLUFMQVYyQTAxMzI3MjcxMC1PT1JJUkZVLUQwNjZQMy0yMDA2MDQyNS0wMDAudGlmIn0.uI3qG28YKg6EbAnYVQiFVcMHQWeeWSTInIfKvXIsxbI'},
],
'project': 'avnir2-ori'}
filesの配列の中に、各ファイルの名前(file_name)、ファイルサイズ(file_size)、URL(url)があります。
このurlの値が、ファイルをダウンロードするためのURLです。
URLには有効期限があり、expires_atに設定されています。これを過ぎるとURLが使えなくなるので、再発行をしてください。
もう一つ、dataset_idからダウンロードURLを発行する方法があります。
dataset_idは、ファイル検索APIの実行結果から取得することができます。
# サンプル5
# ダウンロードURL発行(dataset_idがわかっている場合)
published = publish_file('ALAV2A013272800-OORIRFU-D066P3-20060425-000')
pprint.pprint(published)
こちらでも同様に、files.urlの値からダウンロードURLを取得できます。
{'dataset_id': 'ALAV2A013272800-OORIRFU-D066P3-20060425-000',
'expires_at': '2020-01-18T20:29:17.943066+00:00',
'files': [{'file_name': 'IMG-01-ALAV2A013272800-OORIRFU-D066P3-20060425-000.tif',
'file_size': 58024471,
'url': 'https://file.tellusxdp.com/api/v1/origin/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzkzMzYxNTcsImV4cCI6MTU3OTM3OTM1NywiYXBpX3Rva2VuIjoiVEgwRS04UWRlTFZnIiwiZGF0YXNldCI6ImF2bmlyMi1vcmkiLCJrZXkiOiJBTEFWMkEwMTMyNzI4MDAtT09SSVJGVS1EMDY2UDMtMjAwNjA0MjUtMDAwIiwiZmlsZV9uYW1lIjoiSU1HLTAxLUFMQVYyQTAxMzI3MjgwMC1PT1JJUkZVLUQwNjZQMy0yMDA2MDQyNS0wMDAudGlmIn0.BfqWgxI5Ns7JhveOCsK2wJdZ17RAjsmAibQHhIxI_XY'},
],
'project': 'avnir2-ori'}
3.ダウンロード
最後に、発行したURLからファイルをダウンロードします。
# サンプル6
# 画像データをダウンロードし保存
# ※サンプル5の実行後でないとエラーになります。
for file in published['files']:
if re.match(r'.*tif$', file['file_name']):
pprint.pprint(file['file_name'])
download_file(file['url'], file['file_name'], published['dataset_id'])
ファイルサイズが大きいので、実行が終わるまでに少し時間がかかります。
シーン(データ)の取得条件をより詳しく知りたい場合は、ヘッダーテキストをダウンロードしてみてください。
# サンプル7
# ヘッダーテキストをダウンロードし保存
# ※サンプル5の実行後でないとエラーになります。
for file in published['files']:
if re.match(r'.*txt$', file['file_name']):
pprint.pprint(file['file_name'])
download_file(file['url'], file['file_name'], published['dataset_id'])
ヘッダーテキストの中身については、JAXAが提供するプロダクトフォーマット説明書を参照してください。
最後に、ダウンロードしたGeoTiffファイルの読み込みと表示をしてみましょう。
# 読み込み
from skimage import io
from osgeo import gdal, gdalconst, gdal_array
# 青の波長
tif = gdal.Open('./ALAV2A013272800-OORIRFU-D066P3-20060425-000/IMG-01-ALAV2A013272800-OORIRFU-D066P3-20060425-000.tif', gdalconst.GA_ReadOnly)
# GeoTiffのタグコードを表示
pprint.pprint(tif.GetProjection())
pprint.pprint(tif.GetGeoTransform())
pprint.pprint((tif.RasterXSize, tif.RasterYSize))
pprint.pprint(tif.GetMetadata())
pprint.pprint(tif.RasterCount)
io.imshow(tif.GetRasterBand(1).ReadAsArray())
AVNIR-2のデータは、波長(バンド)ごとにファイルが分かれています。
AVNIR-2ではバンド1に青、2に緑、3に赤、4に近赤外が設定されています。
(データ詳細:https://www.tellusxdp.com/ja/dev/data/avnir-2)
上記のサンプルコードは青の波長のファイルのみを扱ったものです。
青の波長のファイルを画像表示した結果が以下になります。単バンドのため画像はモノクロで表示されます。
最後に、各波長ごとに分かれているファイルを合成して、私たちが普段見ている画像と同じようにカラー表示してみましょう。
赤、青、緑にあたる01から03の番号の3ファイルを読み込んで合成します。
# 可視光
import numpy as np
tif_b = gdal.Open('./ALAV2A013272800-OORIRFU-D066P3-20060425-000/IMG-01-ALAV2A013272800-OORIRFU-D066P3-20060425-000.tif', gdalconst.GA_ReadOnly)
tif_g = gdal.Open('./ALAV2A013272800-OORIRFU-D066P3-20060425-000/IMG-02-ALAV2A013272800-OORIRFU-D066P3-20060425-000.tif', gdalconst.GA_ReadOnly)
tif_r = gdal.Open('./ALAV2A013272800-OORIRFU-D066P3-20060425-000/IMG-03-ALAV2A013272800-OORIRFU-D066P3-20060425-000.tif', gdalconst.GA_ReadOnly)
x_size = tif_b.RasterXSize
y_size = tif_b.RasterYSize
dtype = tif_b.GetRasterBand(1).ReadAsArray().dtype
rgb_array = np.zeros((y_size, x_size, 3), dtype=dtype)
rgb_array[:,:,0] = tif_r.GetRasterBand(1).ReadAsArray()
rgb_array[:,:,1] = tif_g.GetRasterBand(1).ReadAsArray()
rgb_array[:,:,2] = tif_b.GetRasterBand(1).ReadAsArray()
io.imshow(rgb_array)
以上、Tellusの開発環境で、AVNIR-2(オルソ補正画像プロダクト)の提供元オリジナルデータを取得する方法を紹介しました。
今後も様々な衛星の提供元オリジナルデータを公開していく予定です。楽しみにお待ちください。