宙畑 Sorabatake

Tellusの使い方

【ゼロからのTellus】2021年打ち上げ予定のALOS-3相当データを確認する(Tellus OS/開発環境)

本記事ではTellus OSで取得したALOS-3のデータ紹介と、開発環境でのAPIの利用方法を紹介しています。

2021年度に打ち上げ予定の人工衛星ALOS-3。その特徴は地上分解能が0.8mと非常に高解像度なデータでありながら観測幅が70kmと、1シーンで広範囲の撮像が可能であること。これはすなわち、日本全国を月1回など高頻度なペースで撮影できることを意味します。

そんなALOS-3に相当するデータが運用開始に先駆けてTellus上で公開されており、本記事ではTellus OSで取得したALOS-3のデータ紹介と、開発環境でのAPIの利用方法を紹介します。
※データは、World Viewデータ(プロダクト名:AW3D)を処理したもので、ALOS-3とは厳密には観測波長帯は異なります。

また、ALOS-3相当データは現在以下の10枚です。
①長野市:2016/06/03 – 2019/12/25の期間中のモザイク画像3枚
②福岡市:2015/04/18 – 2019/5/15の期間中のモザイク画像3枚
③ハノイ:2017/12/20 – 2019/11/25の期間中のモザイク画像2枚
④マニラ:2018/05/12 – 2019/10/13の期間中のモザイク画像2枚

※本記事で紹介している内容を実践するにはTellusの登録が必須になります

(1)ALOS-3相当データをTellus OSで確認する

ALOS-3相当データは、Tellus OSのライブラリタブの中に「高解像度光学 | ALOS-3相当データ」として登録されています。
福岡市のデータを確認するため、「福岡空港」を検索窓で検索して「高解像度光学 | ALOS-3相当データ」を表示した結果が以下になります。

飛行機の形や家の輪郭が綺麗に見えているのが分かりますね。以下はハノイの画像なのですが、家の形が複雑で各国の文化の違いを感じます。

また、本データでは以下6つの観測波長帯も確認できます。バンド1のコースタルは水中が見えると言われており、バンド5のレッドエッジは植物の生育が捉えやすいと言われています。

バンド1 0.40~0.45µm(コースタル)
バンド2 0.45~0.51µm(青)
バンド3 0.52~0.58µm(緑)
バンド4 0.63~0.69µm(赤)
バンド5 0.70~0.74µm(レッドエッジ)
バンド6 0.77~0.89µm(近赤外)

ぜひいろいろとTellus OS上で遊んでみてください。
では、次に開発環境でALOS-3相当データを表示する方法を紹介します。

(2)ALOS-3相当データを開発環境で画像として表示させる

ALOS-3相当データは、次の4ステップで表示できます。

1. ファイル検索
取得したい条件に一致するファイルのメタ情報を検索します。

2.ダウンロードURL発行
ファイルのメタ情報から、ファイルをダウンロードするためのURLを発行します。

3.ダウンロード
ファイル取得URLからファイルを開発環境にダウンロードし、保存します。

4.画像表示
ダウンロードしたファイルからバンドごとに合成し、画像を表示します。

Tellusで開発環境(Jupyter Lab)を使う方法は、「Tellusの開発環境でAPI引っ張ってみた」をご覧ください。

ファイル検索API
ファイル検索は以下のAPIを利用します。

https://file.tellusxdp.com/api/v1/origin/search/alos3-pseudo

※1 RSP:Reference System for Planningの略。検索システムと思っておけばOK。
※2 ポインティング角:
対象の地点をどれほど斜めから撮影しているかの角度。0deg. で真上からの撮影、90deg.で真横から撮影となる。

返却値

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 = f"https://file.{DOMAIN}.com/api/v1/origin/search/alos3-pseudo"
    
    headers = {
        'Authorization': f"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型で返却します。

実際に、ファイル検索を実行してみましょう。
今回は検索条件として、以下を設定しています。
– 一度に取得する件数は3件

# サンプル1
# 雲量10%以下 かつ ポインティング角が20deg以下、一度に取得する件数は3件
metas = search_file({'page_size': 3})
# 検索結果を表示
pprint.pprint(metas)

実行すると、次のような結果が表示されます。

{'count': 3,
 'items': [{'bbox': [130.1990675, 33.4411108, 130.3169171, 33.7018372],
            'coordinates': [[130.1990675, 33.4411108],
                            [130.3169171, 33.4411108],
                            [130.3169171, 33.7018372],
                            [130.1990675, 33.7018372]],
            'dataset_id': 'alos3-pseudo_ortho_1030010040c36f00',
            'date_added': '2020-08-25T07:10:36.524131',
            'files': ['ObsDate.txt',
                      'pan_ortho_16bit_1030010040c36f00_1.tif',
                      'pan_ortho_16bit_1030010040c36f00_2.tif',
                      'mul_ortho_16bit_1030010040c36f00_1-6band.tif',
                      'mul_ortho_16bit_1030010040c36f00_2-6band.tif'],
            'observation_datetime': '2015-04-18T02:25:02.841574+00:00',
            'off_nadir_angle': 27.45,
            'publish_link': 'https://file.tellusxdp.com/api/v1/origin/publish/alos3-pseudo/alos3-pseudo_ortho_1030010040c36f00',
            'start_datetime': '2015-04-18T02:25:02.841574+00:00',
            'type': 'a'},
           {'bbox': [130.2833888, 33.4926222, 130.4611712, 33.615915],
             <2件目省略>
           },
           {'bbox': [130.3150367, 33.5071697, 130.4953247, 33.7129745],
             <3件目省略>
           }],
 'next': 'https://file.tellusxdp.com/api/v1/origin/search/alos3-pseudo?cursor=eyJjdXJzb3JfbGFzdF90aW1lIjogIjIwMTYtMDMtMTdUMDI6MDg6MTAuMzEwMTE5IiwgImN1cnNvcl9iZWdpbl90aW1lIjogIjIwMTUtMDQtMThUMDI6MjU6MDIuODQxNTc0IiwgInN0YXJ0X3RpbWUiOiAiMTk3MS0wMS0wMVQwMDowMDowMCIsICJlbmRfdGltZSI6ICIyMDIwLTA5LTE0VDEyOjEzOjA0LjUxNzI1NyJ9'}

返却値の一番最後、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.1604347, 36.5139777, 138.3189499, 36.7656609],
            'coordinates': [[138.1604347, 36.5139777],
                            [138.3189499, 36.5139777],
                            [138.3189499, 36.7656609],
                            [138.1604347, 36.7656609]],
            'dataset_id': 'alos3-pseudo_ortho_104001001d101e00',
            'date_added': '2020-08-25T07:10:36.524131',
            'files': ['ObsDate.txt',
                      'pan_ortho_16bit_104001001d101e00.tif',
                      'mul_ortho_16bit_104001001d101e00-6band.tif'],
            'observation_datetime': '2016-06-03T01:42:30.433484+00:00',
            'off_nadir_angle': 28.3,
            'publish_link': 'https://file.tellusxdp.com/api/v1/origin/publish/alos3-pseudo/alos3-pseudo_ortho_104001001d101e00',
            'start_datetime': '2016-06-03T01:42:30.433484+00:00',
            'type': 'b'}],
 'next': 'https://file.tellusxdp.com/api/v1/origin/search/alos3-pseudo?cursor=eyJjdXJzb3JfbGFzdF90aW1lIjogIjIwMTYtMDYtMDNUMDE6NDI6MzAuNDMzNDg0IiwgImN1cnNvcl9iZWdpbl90aW1lIjogIjIwMTYtMDYtMDNUMDE6NDI6MzAuNDMzNDg0IiwgInN0YXJ0X3RpbWUiOiAiMTk3MS0wMS0wMVQwMDowMDowMCIsICJlbmRfdGltZSI6ICIyMDIwLTA5LTE0VDEyOjEzOjA0LjUxNzI1NyJ9'}

同じ条件で、次の1件のデータが取得できました。

本来は条件によって絞ることができるのですが、今回はデータが少ないこともあり、割愛します。
興味のある方はAVNIR-2の記事をご覧ください。

2. ダウンロード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//publish/alos3-pseudo/{}'.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発行メソッドを実行してみましょう。

先ほどのファイル検索メソッドを用いて、検索結果の先頭にあるデータから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': 'alos3-pseudo_ortho_1030010040c36f00',
 'expires_at': '2020-09-15T00:20:54.585179+00:00',
 'files': [{'file_name': 'ObsDate.txt',
            'file_size': 1883,
            'url': 'https://file.tellusxdp.com/api/v1/origin/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MDAwODYwNTQsImV4cCI6MTYwMDEyOTI1NCwiYXBpX3Rva2VuIjoiMGRmOGE4ZmJmNGE5IiwiZGF0YXNldCI6ImFsb3MzLXBzZXVkbyIsImtleSI6ImFsb3MzLXBzZXVkb19vcnRob18xMDMwMDEwMDQwYzM2ZjAwIiwiZmlsZV9uYW1lIjoiT2JzRGF0ZS50eHQifQ.TBz5DH0lBU6VKg_EGEH9nht_vKvt-gtREai441X2BVw'},
           {'file_name': 'mul_ortho_16bit_1030010040c36f00_1-6band.tif',
            'file_size': 427820635,
            'url': 'https://file.tellusxdp.com/api/v1/origin/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MDAwODYwNTQsImV4cCI6MTYwMDEyOTI1NCwiYXBpX3Rva2VuIjoiMGRmOGE4ZmJmNGE5IiwiZGF0YXNldCI6ImFsb3MzLXBzZXVkbyIsImtleSI6ImFsb3MzLXBzZXVkb19vcnRob18xMDMwMDEwMDQwYzM2ZjAwIiwiZmlsZV9uYW1lIjoibXVsX29ydGhvXzE2Yml0XzEwMzAwMTAwNDBjMzZmMDBfMS02YmFuZC50aWYifQ.JS3AH_41bSvpceoo6wuGrQziLCshwhXKFnAluDKHDI4'},
            <省略>

           ],
 'project': 'alos3-pseudo'}

filesの配列の中に、各ファイルの名前(file_name)、ファイルサイズ(file_size)、URL(url)があります。

このurlの値が、ファイルをダウンロードするためのURLです。

URLには有効期限があり、expires_atに設定されています。これを過ぎるとURLが使えなくなるので、再発行をしてください。

3. ダウンロード

ファイルをダウンロードするメソッドを先に定義します。

def download_file(url, dir, name):
    headers = requests.utils.default_headers()
    headers["Authorization"] = "Bearer " + TOKEN

    r = requests.get(url, headers=headers, stream=True)
    if not r.status_code == requests.codes.ok:
        r.raise_for_status()
    if os.path.exists(dir) == False:
        os.makedirs(dir)
    with open(os.path.join(dir,name), "wb") as f:
        for chunk in r.iter_content(chunk_size=1024):
            f.write(chunk)

次に、発行したURLからファイルをダウンロードします。

for file in published['files']:
    if re.match(r'.*tif$', file['file_name']):
        pprint.pprint(file['file_name'])
        download_file(file['url'], published['dataset_id'], file['file_name'],)

ファイルサイズが大きいので、実行が終わるまでに少し時間がかかります。

4. 画像表示

最後に、ダウンロードしたGeoTiffファイルの読み込みと表示をしてみましょう。

import numpy as np
import rasterio as rio
import matplotlib.pyplot as plt
from skimage.exposure import rescale_intensity

file_name = "mul_ortho_16bit_103001004677e700-6band.tif"
src_file = f"{published['dataset_id']}/{file_name}"
with rio.open(src_file) as src:
    bands = src.read()
    
bgr = np.dstack((bands[1,:,:], bands[2,:,:], bands[3,:,:]))
p_low, p_high = np.percentile(bgr,(0,99.5))
bgr_8bit = rescale_intensity(bgr,in_range=(p_low, p_high), out_range=(0,255)).astype(np.uint8)
plt.imshow(bgr_8bit)
plt.show()

これを実行すると以下のような画像が表示されます。

Credit : DigitalGlobe, Inc.,NTT DATA Corporation

この画像を保存する場合は、以下のコードを実行します。

import cv2
cv2.imwrite("hogehoge.png", bgr_8bit)

ALOS-3相当データは、mulという頭文字がついたファイルに1-6の波長が全て入っています。
ALOS-3では
バンド1: コースタル
バンド2: 青
バンド3: 緑
バンド4: 赤
バンド5: レッドエッジ
バンド6: 近赤外域
が設定されています。
(データ詳細:http://www.satnavi.jaxa.jp/project/alos3/ )
上記のサンプルコードはバンド2, 3, 4を合成してカラー画像として表示させたものです。

バンドの設定は以下のようになっています。

今回はカラー画像なので、青にバンド2の青、緑にバンド3の緑、赤にバンド4の赤を設定しています。

以上、Tellusの開発環境で、ALOS-3相当データを取得する方法を紹介しました。

ぜひ、打ち上げ前のALOS-3相当のデータをTellus上で見て、触ってみてください。

Tellusの登録はこちら