Upload
shimpei-matsuura
View
907
Download
2
Embed Size (px)
Citation preview
地図画像だけじゃない!
Mapion x FOSS4G
株式会社マピオン
松浦慎平 (@PEmugi)
自己紹介
● 2003 年 - 2006年– Arc・・・でGIS、RSデビュー@大学
● 2006 – 2008– GISとかRSから離れ石垣島に通いつめる@大学院
● 2008 – 現在– Mapserverを弄りまくる@マピオン
おしながき
今回はほとんどgdal/ogrの話です混み入った処理の話はあまりないです実際に動いているAPIと使うデータの仕組みをできる限りそのままお届けすること目標に
● 標高API
● リバースジオコーダAPI
データ作成/APIの目標
● 高いパフォーマンス– タイル画像に次いで回数を呼ばれるAPIなので– APPサーバは4台– APPサーバ1台あたり標高APIが250万回/日、リバースジオコーダAPIが340万回/日呼ばれる
● DBを使わない– ライブラリ + dataで完結すれば環境構築が容易– 色々なところに組み込みやすい– ミドルウェア増やしたくない・・・
標高API 概要 1
● 機能– 標高
● 入力地点の標高がわかります● 複数地点、区間での入力も可
– 日の出日の入り、月の出月の入り● 入力地点の日の出日の入り、月の出月の入りの時間、方角がわかります
● 標高を元に計算● 要件
– 1スクロールに1回呼ばれる● PC, スマホ、FP などすべてのデバイスから呼ばれる
(ピーク時で秒間50回ぐらい)
標高API 概要 2
● 材料– 基盤地図情報 10m DEM
● 配信– Glassfish v2.1 + varnish
– Java EE6(JAX-RS)をつかってみました(glassfish v2の上でうごいでるけど・・・)
用途
用途
データの持ち方
● GeoTIFF– 等高線、段彩に使うポリゴンの中間生成物– NFS上に配置
● 2次メッシュ単位– 基盤地図情報の10m標高そのまま– パフォーマンス的にも妥当だった
データの作り方
基盤地図情報(gml)
基盤地図情報(gml)
基盤地図情報対応GDAL/OGR を使えばプログラミング無しでGeoTIFFになります
http://www.osgeo.jp/foss4g-mext/
基盤地図情報対応GDAL/OGR を使えばプログラミング無しでGeoTIFFになります
http://www.osgeo.jp/foss4g-mext/
APIの仕組み
経度緯度2次メッシュ算出geotiffファイル特
定
ファイル内ピクセル座標算出
ランダムアクセスで
ピクセル値取得
● とってもシンプル設計です● 画像へのアクセスをするためのライブラリが豊富– ImageMagick, libpng, libtiff, libjpeg
– JAI(Java Advanced Imaging)
– PIL(Python Imaging Library)
ピクセル座標の算出//2次メッシュコードを求めるdouble y1 = lat * 60 / 40;double y2 = lat * 60 % 40 / 5;double x1 = Math.floor(lon - 100);double x2 = (lon - Math.floor(lon)) * 60 / 7.5;int code1 = (int) y1 * 100 + (int) x1;int code2 = (int) y2 * 10 + (int) x2;int level2 = code1 * 100 + code2
//2次メッシュの左上緯度経度を求めるint code1 = code / 100;int code2 = code - code1 * 100;double yMesh1 = (double) (code1 / 100) / 3.0 * 2.0;double xMesh1 = (code1 - code1 / 100 * 100) + 100;int code2y = code2 / 10;int code2x = code2 - code2y * 10;double yMesh2 = code2y * (2.0 / 3.0 / 8.0);double xMesh2 = code2x * (1.0 / 8.0);double minx = xMesh1 + xMesh2;double miny = yMesh1 + yMesh2;double maxx = minx + (1.0 / 8.0);double maxy = miny + (2.0 / 3.0 / 8.0);
//ピクセル座標を求めるdouble uppx = 1.0 / 8.0 / 1125;double uppy = 2.0 / 3.0 / 8.0 / 750;int xIndex = (int) ((lon – minx) / uppx);int yIndex = (int) ((maxy – lat) / uppy);
ピクセル座標の算出 GeoTIFFのヘッダ使うパターン
(javaだけしか試してないのでjavaだけ)int TIEPOINT_TAG = 33922;int PIXEL_SCALE_TAG = 33550;int WIDTH_TAG = 256;int HEIGHT_TAG = 257;
FileSeekableStream s = new FileSeekableStream(file);TIFFDirectory d = new TIFFDirectory(s, 0); //1directoryの画像の場合TIFFField widthField = d.getField(WIDTH_TAG);TIFFField heightField = d.getField(HEIGHT_TAG);TIFFField pixelScaleField = d.getField(PIXEL_SCALE_TAG);TIFFField tiePointField = d.getField(TIEPOINT_TAG);
long width = widthField.getAsLong(0);long height = heightField.getAsLong(0);double[] pixelScale = pixelScaleField.getAsDoubles();tiepoints = tiePointField.getAsDoubles();s.close();
double uppx = pixelScale[0];double uppy = pixelScale[1];
double minx = tiepoints[3] - uppx * tiepoints[0];double maxy = tiepoints[4] + uppy * tiepoints[1];double maxx = minx + uppx * width;double miny = maxy - uppy * height;
int xIndex = (int) ((lon – minx) / uppx);int yIndex = (int) ((maxy – lat) / uppy);
・GeoTIFFの仕様http://www.remotesensing.org/geotiff/spec/geotiff1.html
・tiffの仕様http://partners.adobe.com/public/developer/tiff/index.html
com.sun.media.jai.codecパッケージで簡単に画像情報にアクセスできます。
・TIEPOINT(...,I,J,K, X,Y,Z...)(I,J)がピクセル座標(X,Y)がデータの座標系での座標
リバースジオコーダAPI概要1
● 機能– 住所情報を返します
● 経度緯度からその地点の住所情報を返します● 要件
– 1スクロールに1回呼ばれる● PC, スマホ、FP などすべてのデバイスから呼ばれる
(ピーク時で秒間50回ぐらい)
– 独自にメンテナンス可能● 市区町村統廃合などに対応したいので
リバースジオコーダAPI 概要 2
● 材料– Zenrin住所ポリゴン– 国土数値情報の行政区域データでも応用できるはず
● 配信– Glassfish v2.1 + varnish
– Cubby (地図配信APIの一機能として稼働)
用途
用途
● 住所付与– 緯度経度のみのPOIデータに対して住所を付与– DBから直接呼んだり、API叩いたり
データの持ち方と仕組み
● GeoTIFF● 1次メッシュ
– 色々試した結果一番効率がよかったので
-------index section-------1: 県index,市区町村index,大字index,字丁目index2: 県index,市区町村index,大字index,字丁目index…2800: 県index,市区町村index,大字index,字丁目index------- 県 section-------北海道青森県------- 市区町村 section-------旭川市江別市札幌市1条通り...------- 大字 section-------東南里塚緑ケ丘平和...------- 小字丁目 section-------1丁目2丁目3丁目4丁目...
1
ピクセル値がデータファイルのインデックスになってるラスタ(1次メッシュ) 対になるラスタに含まれる住所データ(バイ
ナリ)
4
1
3
56
78
2
● 日本全国街区番号まで入れて1.2GB– 頑張ればスマホにだってつめちゃうぞ!!
データの作り方
ポリゴンの重なりを除去し1次メッシュ単位でshapeを統合
市区町村合併等の処理
紐付け処理
住所polygon1フィールドには住所コード(shape file)
住所情報1(漢字、読み、コード)
住所polygon2フィールドには住所
コード
住所情報2(漢字、読み、コード)
住所コード変換テーブル
住所polygon3フィールドにはイン
デックス 住所データ
ラスタライズ値はインデックス(最大indexによてデータ型が3パターン)
ラスターデータ(Byte, UInt16,
Int32)
+ C
データの作り方2
● ポリゴンの重なり除去– OGR_L_SetSpatialFilterで対象ポリゴンと重なっているポリゴンを検索!
– OGR_G_Differenceで対象ポリゴンと重なっているポリゴンの重なって無い部分だけ抽出!
● ラスタライズ– gdal_rasterize -a_nodata 0 -ot {Byte,UInt16,UInt32} -co
"COMPRESS=LZW" -te {region} -tr {upp} {upp} -a idx -of GTiff -l {layername} {input} {output}"
インデックスの数で決める
APIの仕組み
● 基本的な仕組みは標高APIと同じ– 1工程多いだけです
● 一部メモリ上にデータをキャッシュ– 住所の漢字、読み、コードのデータは全体で40Mだけなので
経度緯度2次メッシュ算出geotifファイル特
定
ファイル内ピクセル座標算出
ランダムアクセスで
ピクセル値取得
ピクセル値でデータファイルから住
所取得
ラスターデータを使う場合の注意点
● 精度– ラスターの解像度に依存する
● 解像度が高ければ– 精度は向上(元データがラスターの場合元データの解像度が限界)– サイズは肥大化
– 精度が求められるとき● ベクターデータに対して空間検索等すべき
– 地図タイルと一緒に使う場合● 精度はタイル画像と同じでよい
● 飛び地– 住所を扱う場合小さな領域が消えてしまうかもしれない
まとめ
● ラスターは画像として見せる以外にもピクセル値を使うことで色々なAPIに利用できる
● パフォーマンスもいい!● ベクター - ラスター間の変換や処理には
gdal/ogrだけでもかなりできる● ラスターをインデックスとして使うときにはベクターが元データの場合空間解像度に気をつける
● FOSS4Gは専門的なGISの処理を身近にしてくれるから使う!
ご清聴ありがとうございマピオン