24
地図画像だけじゃない! Mapion x FOSS4G 株式会社マピオン 松浦慎平 (@PEmugi)

FOSS4G 2012 Osaka

Embed Size (px)

Citation preview

Page 1: FOSS4G 2012 Osaka

地図画像だけじゃない!

Mapion x FOSS4G

株式会社マピオン 

松浦慎平 (@PEmugi)

Page 2: FOSS4G 2012 Osaka

自己紹介

● 2003 年 - 2006年– Arc・・・でGIS、RSデビュー@大学

● 2006 – 2008– GISとかRSから離れ石垣島に通いつめる@大学院

● 2008 – 現在– Mapserverを弄りまくる@マピオン

Page 3: FOSS4G 2012 Osaka

おしながき

今回はほとんどgdal/ogrの話です混み入った処理の話はあまりないです実際に動いているAPIと使うデータの仕組みをできる限りそのままお届けすること目標に

● 標高API

● リバースジオコーダAPI

Page 4: FOSS4G 2012 Osaka

データ作成/APIの目標

● 高いパフォーマンス– タイル画像に次いで回数を呼ばれるAPIなので– APPサーバは4台– APPサーバ1台あたり標高APIが250万回/日、リバースジオコーダAPIが340万回/日呼ばれる

● DBを使わない– ライブラリ + dataで完結すれば環境構築が容易– 色々なところに組み込みやすい– ミドルウェア増やしたくない・・・

Page 5: FOSS4G 2012 Osaka

標高API 概要 1

● 機能– 標高

● 入力地点の標高がわかります● 複数地点、区間での入力も可

– 日の出日の入り、月の出月の入り● 入力地点の日の出日の入り、月の出月の入りの時間、方角がわかります

● 標高を元に計算● 要件

– 1スクロールに1回呼ばれる● PC, スマホ、FP などすべてのデバイスから呼ばれる

(ピーク時で秒間50回ぐらい)

Page 6: FOSS4G 2012 Osaka

標高API 概要 2

● 材料– 基盤地図情報 10m DEM

● 配信– Glassfish v2.1 + varnish

– Java EE6(JAX-RS)をつかってみました(glassfish v2の上でうごいでるけど・・・)

Page 7: FOSS4G 2012 Osaka

用途

Page 8: FOSS4G 2012 Osaka

用途

Page 9: FOSS4G 2012 Osaka

データの持ち方

● GeoTIFF– 等高線、段彩に使うポリゴンの中間生成物– NFS上に配置

● 2次メッシュ単位– 基盤地図情報の10m標高そのまま– パフォーマンス的にも妥当だった

Page 10: FOSS4G 2012 Osaka

データの作り方

基盤地図情報(gml)

基盤地図情報(gml)

基盤地図情報対応GDAL/OGR を使えばプログラミング無しでGeoTIFFになります

http://www.osgeo.jp/foss4g-mext/

基盤地図情報対応GDAL/OGR を使えばプログラミング無しでGeoTIFFになります

http://www.osgeo.jp/foss4g-mext/

Page 11: FOSS4G 2012 Osaka

APIの仕組み

経度緯度2次メッシュ算出geotiffファイル特

ファイル内ピクセル座標算出

ランダムアクセスで

ピクセル値取得

● とってもシンプル設計です● 画像へのアクセスをするためのライブラリが豊富– ImageMagick, libpng, libtiff, libjpeg

– JAI(Java Advanced Imaging)

– PIL(Python Imaging Library)

Page 12: FOSS4G 2012 Osaka

ピクセル座標の算出//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);

Page 13: FOSS4G 2012 Osaka

ピクセル座標の算出 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)がデータの座標系での座標

Page 14: FOSS4G 2012 Osaka

リバースジオコーダAPI概要1

● 機能– 住所情報を返します

● 経度緯度からその地点の住所情報を返します● 要件

– 1スクロールに1回呼ばれる● PC, スマホ、FP などすべてのデバイスから呼ばれる

(ピーク時で秒間50回ぐらい)

– 独自にメンテナンス可能● 市区町村統廃合などに対応したいので

Page 15: FOSS4G 2012 Osaka

リバースジオコーダAPI 概要 2

● 材料– Zenrin住所ポリゴン– 国土数値情報の行政区域データでも応用できるはず

● 配信– Glassfish v2.1 + varnish

– Cubby (地図配信APIの一機能として稼働)

Page 16: FOSS4G 2012 Osaka

用途

Page 17: FOSS4G 2012 Osaka

用途

● 住所付与– 緯度経度のみのPOIデータに対して住所を付与– DBから直接呼んだり、API叩いたり

Page 18: FOSS4G 2012 Osaka

データの持ち方と仕組み

● 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– 頑張ればスマホにだってつめちゃうぞ!!

Page 19: FOSS4G 2012 Osaka

データの作り方

ポリゴンの重なりを除去し1次メッシュ単位でshapeを統合

市区町村合併等の処理

紐付け処理

住所polygon1フィールドには住所コード(shape file)

住所情報1(漢字、読み、コード)

住所polygon2フィールドには住所

コード

住所情報2(漢字、読み、コード)

住所コード変換テーブル

住所polygon3フィールドにはイン

デックス 住所データ

ラスタライズ値はインデックス(最大indexによてデータ型が3パターン)

ラスターデータ(Byte, UInt16,

Int32)

+ C

Page 20: FOSS4G 2012 Osaka

データの作り方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}"

インデックスの数で決める

Page 21: FOSS4G 2012 Osaka

APIの仕組み

● 基本的な仕組みは標高APIと同じ– 1工程多いだけです

● 一部メモリ上にデータをキャッシュ– 住所の漢字、読み、コードのデータは全体で40Mだけなので

経度緯度2次メッシュ算出geotifファイル特

ファイル内ピクセル座標算出

ランダムアクセスで

ピクセル値取得

ピクセル値でデータファイルから住

所取得

Page 22: FOSS4G 2012 Osaka

ラスターデータを使う場合の注意点

● 精度– ラスターの解像度に依存する

● 解像度が高ければ– 精度は向上(元データがラスターの場合元データの解像度が限界)– サイズは肥大化

– 精度が求められるとき● ベクターデータに対して空間検索等すべき

– 地図タイルと一緒に使う場合● 精度はタイル画像と同じでよい

● 飛び地– 住所を扱う場合小さな領域が消えてしまうかもしれない

Page 23: FOSS4G 2012 Osaka

まとめ

● ラスターは画像として見せる以外にもピクセル値を使うことで色々なAPIに利用できる

● パフォーマンスもいい!● ベクター - ラスター間の変換や処理には

gdal/ogrだけでもかなりできる● ラスターをインデックスとして使うときにはベクターが元データの場合空間解像度に気をつける

● FOSS4Gは専門的なGISの処理を身近にしてくれるから使う!

Page 24: FOSS4G 2012 Osaka

ご清聴ありがとうございマピオン