Posted at

目指せGISマスター #1 OpenStreetMapから道路NWを抽出する

More than 3 years have passed since last update.


スマホのGPSの精度にはまだまだ不満がある

スマホでも手軽にGPSロギングができるようになった昨今ですが、

やはりというか、誤差は結構あります。

以下はMyTracks(もう使えない?)による車両走行軌跡。

mytracks.png

人が見ればどこを走ったかは分かりますが、なんとか綺麗な軌跡にできないもんか・・・

とは言え、Gセンサとか操舵とかのデータは取れていないですし、あってもそこから補正するのは素人には難しそうなので

マップマッチング的なことで何とかしたいなぁと思ったわけです。

では、地図データはどこから手に入れたらよいでしょう・・・?


作っておいてよかったOSM

上図でも使っているOpenStreetMap。

自前で地図サーバが欲しいということで構築しておいたのですが(構築方法はいずれ投稿するかも)、

タイルサーバとしては頻繁に使っていたものの、データ自体は見ておりませんでした。

ところが、なんという宝の山!これを今まで使わなかったなんて。。。

道路ネットワークもあれば、(多く無いですが)POI情報もあれば、建物のポリゴンもある。

精度うんぬんの問題はあるでしょうが、何十mもずれることはない(と信じている。少なくともスマホのGPSよりましなはず。)ので、

宝を掘り起こしていきたいと思います。


OpenStreetMapから道路NWを抽出することができるか?チャレンジしてみた。

そもそもOSMのデータにアクセスしようと思ったのは

Overpass APIというものがあると教えてもらったのがきっかけです。

http://wiki.openstreetmap.org/wiki/JA:Overpass_API

確かに独自形式だがのクエリを投げると道路NWなどが表示される!

ということは自前で構築済みのOSMサーバからも同じようにデータがとれるはず!

と考えました。

構築時にPostgresql、PostGISを入れた記憶があったので、

地図サーバのPostgresqlにアクセス。

あるある!それっぽいテーブルが!

テーブルのスキーマを見るとOverpassAPIにあったようにhighwayなどの属性がある。

これはいける。と確信。

スキーマは以下などが参考になります。。

http://wiki.openstreetmap.org/wiki/JA:Osm2pgsql/schema

→道路NWを取るならplanet_osm_line テーブルから取るようです。

 今回はこのテーブルですね。

また車が走行する道路のみが欲しいのでhighwayの属性にどのようなものがあるかは確認が必要です。

以下が参考になります。

http://wiki.openstreetmap.org/wiki/Key:highway

footwayなど、歩道もデータには含まれています。


実際に取ってみた

スキーマを見るとwayカラムが実際に位置情報を持っているようですが、

型が"geometry(~~)"となっており、単純に取得しても人間には読めません。

理解するにはgeometry型をPostGISで変換する必要があります。

ST_Astext(ST_Transform(way,4326))

→4326はProjectionのコード。これもいろいろ種類があるようですが、世界測地系は4326で良さそう。

上記を踏まえて例として甲州街道という文言がnameカラムに含まれるデータをSQLで抽出します。

select osm_id,name,highway,z_order,ST_Astext(ST_Transform(way,4326)),way_area from planet_osm_line where name like '%甲州街道%';

少し時間がかかりますが、

141147784 | 甲州街道 | trunk | 8 | LINESTRING(138.089114228403 36.0716119850332,138.088936900966 36.0716665145095,・・・

というようにデータが取れました。パチパチパチパチw

でも、nameは入っていないデータの方が多いので取得条件には工夫が必要。。。


まとめてごっそり取りたい。

緯度経度の四角を指定して、そこに含まれるデータだけ取りたい。

最終的にはPOLYGONで指定した範囲で取りたい。

手間がかかりそうな気がしましたが、

考えてみればOverpass APIだとbboxで見えている範囲で取っているのでできるはずなのです。

調べてみたところ、当然ですができます。

指定したPOLYGONの中に”wayの最初のpointが含まれる"という条件が以下で実現できます。

これをwhere句に入れればOKです。

ST_Within( ST_StartPoint( ST_Transform(way,4326)) , ST_GeomFromText ( 'POLYGON(( 位置1,位置2,位置3, ... ,位置1))' ,4326) )

POLYGONの位置は「lon1 lat1,lon2 lat2・・・」というようにスペース区切りで緯度経度のペアを生成し、

カンマ区切りで位置を数珠つなぎにします。最後に位置1も記述し、輪になるようにする必要があります。

これを使うと都道府県などのPOLYGONデータを持っているのであれば、”都道府県別に取得”ということもできるはずです。


PostGISはいろいろな機能がある

使いこなすにはまだまだほど遠いですが、便利な機能が結構ありますね。

特にPOLYGONの面積を出せるのは便利です。今後も使いそうです。

area.png

POLYGONで指定した面積がおよそ500平方kmであることが算出できます。

PostGISの関数を使いたいだけなので select ~で計算だけさせれば良いです。


とりあえず道路NWデータの抽出は出来る

今回はOSMのデータベースから道路NWの抽出を行いました。

しかし、マップマッチングと言っている以上、この抽出データとGPSデータをマッチングさせる必要があります。

どうやろう・・・

片っ端から距離計算するという手もあるが、さすがに時間がかかりすぎるだろうなぁ・・・

つ R-Tree

ということで次回はR-Treeを使って"高速に"GPSとOSMの道路NWをマッチングさせていきます。

俺たちの戦いははじまったばかりだ