Tellus公式データAPIを使って指定した住所の周辺の衛星画像を取得する

仕事でTellus公式データAPIを使うことになり、数日間悪戦苦闘してようやく仕組みがわかってきました。

指定した住所の周辺の衛星画像を取得するという例で、Tellus公式データAPIの使い方をコード例とともにわかりやすくまとめます。

数日前の自分が読みたかった記事です。比較的新しいサービスのせいか、まだ解説記事があまりありませんでした。

パッケージのインストール方法やループ、関数など、Pythonの基本は理解しているという前提で書きます。

 

1.コード例

私の手元で動作確認をしたコード例を示します。

わかりやすさのために、エラー処理はしておらず、トークンや住所などをコードに書き込んでいますので、そのあたりは適当に処理してください。

・main.py

import time
import my_latlng
import my_tellus
import my_images

# 定数の設定
address = "京都府京都市左京区下鴨宮河町"
dataset_id = "ea71ef6e-9569-49fc-be16-ba98d876fb73"
the_number_of_images = 5

# 住所から緯度経度を取得
latlng = my_latlng.get_latlng(address)

# 取得した緯度経度からtellus用の矩形の緯度経度を算出
tellus_rectangle_latlng = my_latlng.get_rectangle_latlng(latlng)

# tellus用の矩形の緯度経度からシーンを検索してdata_id(シーンID)を取得
scenes = my_tellus.search_scene(
    dataset_id=dataset_id,
    intersects={
        "type":"Polygon","coordinates":[
            tellus_rectangle_latlng
        ]
    }
)
print(f"{len(scenes["features"])}件のシーンがヒットしました")

# シーンごとにファイル情報を取得して 形式の画像を処理
for scene in scenes["features"][:the_number_of_images]:
    data_id = scene["id"]
    file_information = my_tellus.get_file_information(dataset_id, data_id)
    
    for file in file_information["results"]:
        if "webcog" in file["name"]:
            file_name = file["name"]
            file_id = file["id"]
            print(f"{file_name}を処理しています")
            download_url = my_tellus.get_download_url(dataset_id, data_id, file_id)
            my_images.get_tellus_image(download_url["download_url"], file_name)
            my_images.clip_image(file_name, tellus_rectangle_latlng)
            time.sleep(1)

・my_latlng.py

import urllib
import requests

def get_latlng(address):
    """国土地理院の住所検索APIを利用して、指定された住所の緯度経度を取得する。

    Args:
        address (str): 緯度経度を検索する住所

    Returns:
        latlng (list): 経度と緯度のリスト [lng, lat]

    """
    address_search_url = "https://msearch.gsi.go.jp/address-search/AddressSearch?q="
    quoted_address = urllib.parse.quote(address)
    response = requests.get(address_search_url + quoted_address)
    response.raise_for_status()
    latlng = response.json()[0]["geometry"]["coordinates"]
    return latlng

def get_rectangle_latlng(latlng):
    """緯度経度からTellus用の矩形の緯度経度リストを生成する。

    Args:
        latlng (list): 中心の緯度経度 [lng, lat]

    Returns:
        tellus_rectangle_latlng (list): 矩形の頂点座標のリスト(二次元リスト)

    """
    margin = 0.01
    lng = latlng[0]
    lat = latlng[1]
    
    tellus_rectangle_latlng = [
        [lng - margin, lat - margin], 
        [lng + margin, lat - margin], 
        [lng + margin, lat + margin], 
        [lng - margin, lat + margin],
        [lng - margin, lat - margin],
    ]
    return tellus_rectangle_latlng

・my_tellus.py

import json
import requests

TOKEN = "TOKENXXXXXXXXXXXXXXXXXX"

# API 呼び出しの共通設定
BASE_URL = "https://www.tellusxdp.com/api/traveler/v1"
REQUESTS_HEADERS = {
    "Authorization": "Bearer " + TOKEN,
    "Content-Type": "application/json",
}

def search_scene(dataset_id, intersects):
    """Tellus APIでシーンを検索する。

    Args:
        dataset_id (str): 検索対象のデータセットID
        intersects (dict): 検索範囲を指定するGeoJSON形式のPolygon、例: {"type": "Polygon", "coordinates": [[...]]}

    Returns:
        scenes (dict): 検索にヒットしたシーンの情報のリストを含む辞書

    """
    url = f"{BASE_URL}/datasets/{dataset_id}/data-search/"
    payloads = {
        "intersects": intersects,
        "query": {},
        "sortby": [
            {"field":"properties.end_datetime","direction":"desc"}
        ],
    }
    response = requests.post(url, headers=REQUESTS_HEADERS, data=json.dumps(payloads))
    response.raise_for_status()
    scenes = response.json()
    return scenes

def get_file_information(dataset_id, data_id):
    """Tellus APIで指定したシーンのファイル情報を取得する。

    Args:
        dataset_id (str): データセットID
        data_id (str): シーンID

    Returns:
        file_information (dict): ファイル情報の一覧を含む辞書

    """
    url = f"{BASE_URL}/datasets/{dataset_id}/data/{data_id}/files/"
    response = requests.get(url, headers=REQUESTS_HEADERS)
    response.raise_for_status()
    file_information = response.json()
    return file_information

def get_download_url(dataset_id, data_id, file_id):
    """Tellus APIでファイルのダウンロードURLを取得する。

    Args:
        dataset_id (str): データセットID
        data_id (str): シーンID
        file_id (str): ファイルID

    Returns:
        download_url (dict): ダウンロードURLを含む辞書

    """
    url = f"{BASE_URL}/datasets/{dataset_id}/data/{data_id}/files/{file_id}/download-url/"
    response = requests.post(url, headers=REQUESTS_HEADERS)
    response.raise_for_status()
    download_url = response.json()
    return download_url

・my_images.py

import requests
import rioxarray
import matplotlib.pyplot as plt

def get_tellus_image(download_url, file_name):
    """Tellusから画像ファイルをダウンロードして保存する。

    Args:
        download_url (str): ダウンロードURL
        file_name (str): 保存するファイル名

    """
    response = requests.get(download_url)
    response.raise_for_status() 
    with open(file_name, 'wb') as file:
        file.write(response.content)

def clip_image(file_name, tellus_rectangle_latlng):
    """画像を指定された矩形領域でクリップし、PNGファイルとして保存する。

    Args:
        file_name (str): クリップ対象の画像ファイル名
        tellus_rectangle_latlng (list): Tellus用の矩形の緯度経度リスト(二次元リスト)

    """
    bounding_box = [
        tellus_rectangle_latlng[0][0], 
        tellus_rectangle_latlng[0][1], 
        tellus_rectangle_latlng[1][0],
        tellus_rectangle_latlng[2][1],
    ]
    data = rioxarray.open_rasterio(file_name, masked=True)
    clipped_data = data.rio.clip_box(*bounding_box)
    fig, ax = plt.subplots(figsize=(8, 8))
    clipped_data.sel(band=[1, 2, 3]).astype("uint8").plot.imshow(ax=ax)
    ax.set_title('')
    plt.savefig(f"clipped_{file_name}.png")

 

この4つのファイルを同じディレクトリに入れ、python main.pyと実行すれば、コードに書いた住所付近の衛星画像が指定枚数分だけ作成されます。

2025年10月30日に、この例で書いたように京都府京都市左京区下鴨宮河町付近の衛星画像を5枚作成すると、以下のようになりました。

画像の著作権はすべてJAXAにあります。

鴨川デルタと呼ばれる、川がYの字に合流する地点を住所として指定しました。雲がない画像だときれいに写っていますね。画像左下の緑の部分は御所です。

 

2.大きな流れ

(1) 住所→住所の緯度経度(1点)

(2) 住所緯度経度(1点)→住所を中心とする矩形の緯度経度(5点)

(3) dataset_idと矩形の緯度経度(5点)→data_id(シーンID)

(4) dataset_idとdata_id→ファイル情報一覧

(5) dataset_idとdata_idとfile_id→(COG形式の画像ファイルの)ダウンロードURL

(6) ダウンロードURL→COG形式の画像ファイル

(7) COG形式の画像ファイル→住所を中心とする矩形の緯度経度でクリップしたPNG形式の画像ファイル

(1)と(2)の緯度経度関係の処理をmy_latlng.pyに、(3)と(4)と(5)のTellus公式データAPIの処理をmy_tellus.pyに、(6)と(7)の画像処理をmy_images.pyに書いています。

この大きな流れの見通しをつかむまでに苦労しました。

 

3.緯度経度の処理

(1)の住所から緯度経度への変換は、Pythonで地名/住所から緯度/経度を取得し地図にプロットする方法 #folium – Qiitaを参考に国土地理院のAPIを利用するとあっけなくできました。これはありがたいです。

(2)は(1)で取得した緯度経度にそれぞれ0.01を足したり引いたりすることで、指定した住所付近の矩形にしました。指定した住所を中心とする約2キロメートル四方の矩形です(緯度により0.01の東西の距離が変わってしまい正方形になりませんが、今回は周辺画像を大まかに取得したいという目的なので、これでよしとしました)。

 

4.Tellus公式データAPIの使い方

tellus-traveler-pythonというパッケージを使ってもよかったのですが、ここでは原理的な理解を目指して、公式のAPIをそのまま利用しました。

How to Use|TellusHow to Use|Tellusが最重要の資料です。

それをもとに試行錯誤を繰り返し、できるだけわかりやすい形にしたのが冒頭で示したコードです。

この公式ドキュメントがわかりづらかったので、別記事で詳しくまとめられたらと思っております。

 

5.取得した画像の後処理

この部分はTellus APIを利用した衛星データ活用 可視化偏からほぼそのまま拝借しました。

COG形式の画像ファイルを活用すると緯度経度でクリップできるというのがポイントです。

ただ、それをそのまま保存しても人間が見てすぐにわかるような衛星写真の画像にはならなかったので、Matplotlibで可視化しました。

私はこのあたりの処理がよくわかっておらず、もっとよい方法があるかもしれません。

ともあれ、やりたいことは実現できたので、知見を共有します。

 




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です