アオカケスの鳥かご

日々の出来事を綴っていきたい

市区町村を構成する座標について

日本全国の市区町村はいくつあるのかご存知でしょうか。

日本政府が運用しているe-statによると、2019年2月23日現在で1724となっています。


f:id:aokakes:20190223145817p:plain
市区町村数を調べる | 政府統計の総合窓口

しかし、この1724という数字は真の市区町村の数ではありません。


そこで、真の市区町村数を特定するために日本全国の郵便番号の数を調べてみます。

日本郵便から郵便番号のデータをダウンロードすることができます。
www.post.japanpost.jp

多少データを整形し、不要と思われるデータを省いた結果、以下のようになりました。
f:id:aokakes:20190223150945p:plain

真の市区町村の数は119029でした。
なんとe-statの約69倍です。


さて、ここからが本題です。

目標

私は今、日本全国の市区町村においてそれぞれを構成している座標を取得したいと考えています。

ネットで調べてみると市区町村の緯度経度のデータはすぐに見つかりますが、これらのデータはすべて地方公共団体の位置データです。
雑に言い換えると、市区町村の中で最も栄えている場所、でしょうか。

ですので、市区町村の境界線近くになってくると、その座標がどちらの市区町村か分からなくなるといった事が起こります。

そして、最も致命的なのがデータの数が全く足りていないことです。
上述したように市区町村のデータは12万近くあり、対して地方公共団体のデータは2000もありません。

この60倍近い差はどうしようも無く、正直に言ってあまり使い物になりません。


もっと探してみると様々な緯度経度のデータを見つけることができますが、同じような理由で使えません。
こういったデータを複数組み合わせれば多少は穴を埋めることも出来るかもしれませんが、過疎っている地域は本当に過疎っていて、緯度経度のデータは全く見つかりません。

ならどうするか。自分で作ればいいのです。

特定の地点の座標を調べる方法

ある特定の座標を調べるのはgoogleマップが一番楽そうです。

例えば、富士山の頂上には日本最高峰の碑があります。
この碑の緯度経度を知りたいときは、その近くをクリックすると、地図の下らへんに郵便番号・住所・緯度経度が表示されます。

市区町村の境界線を調べる方法

普通にgoogleマップで市区町村名を検索するだけです。
とはいえ、日本全国の市区町村名は一意ではありません。

思っていた場所とは違う場所が表示されることがわりと多いので、県名から検索するのが確実です。

群馬県高崎市の榛名湖町で検索してみると以下のようになります。

境界線が赤線で表示されます。
この赤線の緯度経度を調べていけば榛名湖町を構成する緯度経度が分かりそうです。

...

......

.........

これを12万回やったとして、全部終わるのは何年後なんでしょう。
やってられんですよ。

そこで何とか自動化する方法を考えます。

境界線の緯度経度を取得する方法

googleマップのURLは以下のようになっています。

https://www.google.co.jp/maps/place/〒370-3348+群馬県高崎市榛名湖町/@36.4688302,138.8523685,14z/data=!3m1!4b1!4m5!3m4!1s0x601e7cb9d81a68df:0x382d836b5c5a7509!8m2!3d36.4709423!4d138.8768626?hl=ja&authuser=0

URLの構造

https://www.google.co.jp/maps/ googleマップそのもののURL
place/ ランドマークを指定したときのパス
placeの次 検索名
@__,__ 表示している地図の中心の緯度経度
_z 地図の倍率
data以降 なんかよく分からんパラメータ

dataの最後にくっついている座標は地図内の市区町村名が書いてある場所を指しているようです。
でも今回は使いません。


ここで、言葉の定義をしておきます。
これ以降の座標という単語は画像内の座標(1920×1080とかそういう意味での)を指します。
分かりにくいかもしれませんがご容赦ください。


境界線の緯度経度を取得するにはまず、境界線の赤い部分が画像内のどこにあるか特定します。
普段は左上が(0,0)ですが、googleマップ的には中心が(0,0)のようです。

境界線の色が赤であることは確定しているので、地図のスクリーンショットを撮り、てきとうに画像内の特定の色を抽出するようなプログラムを書けば簡単に境界線の座標が分かります。

しかし、特定の一色だけにするとうまく抽出できないので、良い感じ閾値を設定してそれを超えれば抽出する、みたいな感じにするのが良さげです。

また、電車の駅なども赤いのでうまくチューニングする必要があります。

次に、座標から緯度経度に変換できるような式を用意しますが、地球は丸いのでそう簡単には式を作れません。
ここは大人しく先人の知恵を有り難くお借りします。
hosohashi.blog59.fc2.com

以下が座標から緯度経度に変換するための式です。
{ \begin{align}
経度 = \frac{180}{2^{z+7}}X+x_c \end{align}
}

{ \begin{align}
緯度 = \frac{180}{\pi}\sin^{-1}\left(\tanh\left(\frac{\pi}{2^{z+7}}Y+\tanh^{-1}\left(\sin\left(\frac{\pi}{180}y_c\right)\right)\right)\right) \end{align}
}

記号は以下のように定義されています。

{ X } 画像内の経度を求めたい地点のx座標
{ Y } 画像内の緯度を求めたい地点のy座標
{ x_c } 画像の中心の経度
{ y_c } 画像の中心の緯度
{ z } googleマップの倍率


これで境界線の緯度経度を取得する準備が整いました。
あとは一連の流れをプログラムに落とし込んで12万回ぶん回すだけです。

でも、実装はまた今度...