背景
「地図を背景に路線図を作りたい」という場合、これまで自分の手作業で地理院地図タイル画像Excel方眼紙にコピペして敷き詰めていましたが、たいへん面倒な作業ですのでPythonにやらせることにしました。
地理院地図タイルとは
詳しいことはこちらに記載されていますが、要するに国土地理院が作成した地形図をタイル画像で利用できますよということです。
タイル画像には座標値があって、今回はそれを指定することで、欲しい領域の地図を取得することにしています。
その座標値は国土地理院のタイル座標確認ページでご確認ください。
タイル画像を取得する
まず必要なライブラリをimportしておきます。
必要に応じてinstallしておいてください。
(pip install requests
など)
import cv2
import numpy as np
import os
import requests
タイル画像を取得し、保存する関数を次のように定義します。
下記ではカレントディレクトリにtile
というフォルダを用意して保存しています。
ちなみに1枚分だけなので、
こんな感じです。
def get_tile(z, x, y):
"""
今回は標準地図を取得するとしてURLを指定する。
与えられた座標に対応する地理院地図タイル画像を保存する。
"""
url = "https://cyberjapandata.gsi.go.jp/xyz/std/{}/{}/{}.png".format(z, x, y)
file_name = "tile/{}_{}_{}.jpg".format(z, x, y)
response = requests.get(url)
image = response.content
with open(file_name, "wb") as aaa:
aaa.write(image)
領域を指定してタイル画像を取得する
先のget_tile
関数では地図タイル1枚分しか取得できませんので、領域まるごと取得するようにします。
将来に備えて、欲しい画像がすでに存在している場合はスキップさせています。
ただし、前回の取得からあまりにも時間が経過している場合、地図が更新されている場合もあるので、そういった場合は画像を削除するといいと思います。
次節で複数のタイル画像を1枚にまとめるので、個別の画像はその都度消してしまってもいいかもしれません。
そのあたりは皆さんにおまかせします。
def get_tile_area(north_west, south_east):
"""
北西端・南東端のタイル座標を指定した上で、タイル画像を取得する。
"""
assert north_west[0] == south_east[0], "ズームレベルzを確認してください。"
zoom = north_west[0]
im_v_lst = []
for i in range(south_east[1]-north_west[1]+1):
for j in range(south_east[2]-north_west[2]+1):
filepath = path = "tile/{}_{}_{}.jpg".format(zoom, i+north_west[1], j+north_west[2])
if os.path.exists(filepath) == True:
continue
get_tile(zoom, i+north_west[1], j+north_west[2])
領域内のタイル画像を1枚の画像にまとめる
膨大な時間を費やしていた敷き詰め作業は次のようにして克服します。
最後の画像の名前は自由に変更してください。
def cat_tile(north_west, south_east):
zoom = north_west[0]
im_v_lst = []
for i in range(south_east[2]-north_west[2]+1):
im_h_lst = []
for j in range(south_east[1]-north_west[1]+1):
path = "tile/{}_{}_{}.jpg".format(zoom, j+north_west[1], i+north_west[2])
im1 = cv2.imread(path,-1)
im_h_lst.append(im1)
im_h = cv2.hconcat(im_h_lst)
im_v_lst.append(im_h)
im_v = cv2.vconcat(im_v_lst)
cv2.imwrite("tile/tile.png", im_v)
やってみる
やってみます。
north_west = (15, 28223, 13124)
south_east = (15, 28244, 13144)
get_tile_area(north_west, south_east)
cat_tile(north_west, south_east)
こんな感じです。福岡県の糸島半島です。
手作業だと何時間かかることか…
これで楽できますね。ちなみに、この画像そのままだと30MBくらいあります。
画質を落としてもいい場合は、サイズダウンしたほうがいいかもしれません。
出典
地図画像:国土地理院