これは MIERUNE AdventCalendar 2022 22日目の記事です。
昨日は @asahina820 さんによる Cesium for Unityを使って3D Tiles形式のPLATEAUデータを表示する でした。
初めに
ラスタータイル、というデータ形式をご存知でしょうか?
WebGISではとてもよく利用される概念ですが、以下のように背景となる地図(画像)をズームレベルという概念に沿って倍率を変え、ズームレベルが上がるごとに地図の詳細度が上がっていきます。
(地理院タイルについてより)
表示区画があらかじめ決まっているため、地図画像を事前に作成しておくことが可能で、軽量かつ高速に全世界分の背景地図をブラウザで表示することができます。
こんなラスタータイルですが、通常はhttps://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png
のように{ズームレベル}/{X座標}/{Y座標}.png(.jpg)
のようなZXYのタイル座標を指定する形式で配信され、ブラウザなどから利用することを想定しています。
ただ、国土地理院が配信する標高タイルのようにピクセルの値そのものに意味があるラスタータイルも存在していたり、航空写真などであればブラウザ以外でも一部の箇所だけ取得し、単なる背景画像以外の用途で利用したいなぁと思う場面はちょこちょこあります。
ラスタータイル自体は、それ自体に地理的な意味を全く持たないただの画像データなんで、そんな時にいちいち緯度経度からズームレベルごとのタイル座標を計算し、ダウンロードして、地理情報を埋め込んで〜みたいなことはしたくないわけです。
こういう悩みを持つ人は多そうなんで、みなさんが利用できるようにPythonでパッケージを作成して、PyPIに公開しました!
使い方
今回作ったのは、tile-operatorというツールです。
PyPIでも公開しているので、Python実行環境があれば「pip」などを利用して誰でも簡単に利用することができます。
https://pypi.org/project/tile-operator/0.0.6/
pip install tile-operator
CLIツールとしても利用できますが、多少めんどくさい設定が必要になります
CLIとして利用するための準備
CLIとして利用する場合にはこちらからSource code(zip)をクリックしてコード一式をダウンロードしてください。
その後、zipを解凍し、ターミナルなどを利用してtile-operatorディレクトリの中に入ってください。
$ cd ~/Downloads/tile-operator-0.0.6
$ ls -al
total 224
drwxrwxr-x@ 10 satoru staff 320 12 17 16:11 ./
drwx------@ 9 satoru staff 288 12 17 21:44 ../
-rw-rw-r--@ 1 satoru staff 3277 12 17 16:11 .gitignore
-rw-rw-r--@ 1 satoru staff 1069 12 17 16:11 LICENSE
-rw-rw-r--@ 1 satoru staff 1904 12 17 16:11 README.md
-rw-rw-r--@ 1 satoru staff 91048 12 17 16:11 poetry.lock
-rw-rw-r--@ 1 satoru staff 1023 12 17 16:11 pyproject.toml
drwxrwxr-x@ 5 satoru staff 160 12 17 16:11 tests/
drwxrwxr-x@ 4 satoru staff 128 12 17 16:11 tile_operator/
-rw-rw-r--@ 1 satoru staff 1338 12 17 16:11 to.py
次に、poetryをインストールします。
curl -sSL https://install.python-poetry.org | python -
echo 'export PATH="/Users/satoru/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
poetry --version
バージョンが表示されれば、正常にインストールできています。できていない場合はググってください!!!
Pythonの仮想空間の管理をしやすくさせるために、ディレクトリ内に仮想環境を作成されるよう変更しておきましょう。
poetry config virtualenvs.in-project true
ここまで終了したら、以下のコマンドを入力して、tile-operatorの依存パッケージをインストールします。
poetry install
poetry shell
ここまでの準備が終わったら、ようやく指定範囲のラスタータイルをダウンロードしていきます。
初めに画像を取得したい範囲の矩形を示すGeoJSONを作成しましょう。
geojson.ioなんかを利用すると以下のように手軽に作成できます。
範囲が広すぎるとデータ数も増えてしまうので、札幌駅周辺のみを取得することとしましょう。
右に表示されているGeoJSONをaoi.geojson
など適当な名前をつけて作成し、書き込んでおきます。
次に、取得したいラスタータイルのURLを設定します。
今回はOpenStreetMapのデータを利用していきましょう。
URLは以下のようになります。
https://tile.openstreetmap.jp/{z}/{x}/{y}.png
最後に取得したいズームレベルを決めましょう。
今回は18を指定します。
ズームレベル18はとても詳細度の高いズームレベルですので、広い範囲で取得するときはお気をつけください。
東京都全域とか指定すると、10万ファイルは超えると思います。
それではコマンドを実行してみましょう。
$ python to.py -v download https://tile.openstreetmap.jp/{z}/{x}/{y}.png aoi.geojson 17
Tile Download
Options:
tile_url=https://tile.openstreetmap.jp/{z}/{x}/{y}.png
file_path=aoi.geojson
zoom_level=17
100%|█████████████████████████████████████████████████████████████████████████████████████| 20/20 [00:10<00:00, 1.94it/s]
プログレスバーの表示から、20枚の画像がダウンロードされたことがわかりますね。
ダウンロードされた画像はこのようにoutputフォルダが生成され、そこに格納されます。
ね、簡単でしょ?
Pythonのパッケージとして利用する
こちらはPyPIからインストールすればすぐに使える上、CLIツールより高機能です。
まずは以下のようにクラスとユーティリティ関数をインポートします。
from tile_operator.operate import TileOperate, file_to_bounds
次に、インポートしたfile_to_boundsを利用して、先ほど作成したaoi.geojsonのバウンディングボックスを作成しましょう。
file_path = "./aoi.geojson"
bbox = file_to_bounds(file_path).bounds()
bbox
# (141.34524527865244, 43.06547110473289, 141.3568432889649, 43.07128825219701)
その後、作成したbboxとデータを取得したいズームレベルのみ指定してインスタンス化します。
to = TileOperate(
bbox=bbox,
zoom_level=17,
)
そしてset_tile_listメソッドを利用し、その後、geo_tile_listメソッドを呼び出してセットされたタイル座標の一覧を取得しましょう。
to.set_tile_list()
tile_list = to.get_tile_list()
print(len(tile_list))
ダウンロードされるタイルが、CLIを利用した時と同様に20個であることがわかりました。
20
さらに、タイル座標の一覧も取得できます。
to.get_tile_list()
[(116998, 48126),
(116998, 48127),
(116998, 48128),
(116998, 48129),
(116999, 48126),
(116999, 48127),
(116999, 48128),
(116999, 48129),
(117000, 48126),
(117000, 48127),
(117000, 48128),
(117000, 48129),
(117001, 48126),
(117001, 48127),
(117001, 48128),
(117001, 48129),
(117002, 48126),
(117002, 48127),
(117002, 48128),
(117002, 48129)]
set_tile_listメソッドを呼び出して、タイル座標の一覧が生成された後であれば、download_all_tilesメソッドを呼び出し、タイルをダウンロードすることが可能です。
tile_url = "https://tile.openstreetmap.jp/{z}/{x}/{y}.png"
to.download_all_tiles(tile_url)
100%|██████████| 20/20 [00:05<00:00, 3.70it/s]
その他便利そうな機能
タイル座標に応じたグリッド(ポリゴン)を作成し、geopandasのGeoDataFrameで返すメソッドも用意されています。
to.create_tile_grid_from_bbox_list()
ディレクトリ構成が{z}/{x}/{y}.png(.jpg)になっている必要がありますが、タイル画像へのパスを与えて、GeoTIFFに変換するメソッドもあります。
tile_path = "./output/17/116998/48126.png"
to.tile_to_geotiff(tile_path)
指定ファイルと同じディレクトリに48126.tifというファイルが生成されるので、QGISで表示させてみましょう。
背景地図とぴったり重なります。
終わりに
ということで、ありそうでなかった(実はあるかも)手軽にタイルをローカルマシンにダウンロードしたり、色々できるツールを作ってみました!!
これからも機能を追加していこうと思いますんで、使ってみてください!
明日は@soramiさんです!お楽しみにー!