2017-04-07

メッシュデータのラスター化 - 土地利用細分メッシュ [更新]

「メッシュデータのラスター化 - 土地利用細分メッシュ」(2015-07-18, 以下[初版]と言います) で、国土数値情報「土地利用細分メッシュ」データをラスターに変換するワークスペース例を紹介しました。

[初版]のワークスペースは、Shapefile形式のデータから読み込んだ1/10細分メッシュ区画の矩形2Dポリゴン (1次メッシュ1区画あたり64万個) について、それらが属性として持っている土地利用種別コードに対応する画素値をZ座標とする3Dポリゴンに変換し、さらに、それらに基づいて NumericRasterizer によってラスターを作成するものでした。

現時点のFME最新バージョン - FME 2017 でも[初版]のワークスペース (FME 2015 で作成) は実行できますが、FME 2017 で Python FME Objects API にラスター処理関係の機能が追加されたことから、数十行程度の小さな Python スクリプトによって、XML形式の土地利用細分メッシュデータから抽出した土地利用種別コードのリスト (1次メッシュ1区画あたり800列 x 800行 = 64万コード, スペース/改行区切り文字列) に基づいてラスターを作成することも可能になりました。

土地利用細分メッシュXMLからラスターへの変換は、いくつかのトランスフォーマーの組み合わせでもできることですが、Python スクリプトを使うことによって格段に性能が良くなります。以下、FME 2017 の新機能を利用したアップグレード版として紹介します。

[2017-06-15] 2017-06-02 から、国土数値情報ダウンロードサイトで「土地利用細分メッシュ(ラスタ版)」データ (平成26年度 GeoTIFF形式, JGD2000) がダウンロードできるようになりました。「土地利用細分メッシュ (ラスター) データセットの作成」(2017-06-10) もご参照ください。

FME 2017.0.0.2 build 17280

FMEワークスペース例











[XML] リーダー: 国土数値情報「土地利用細分メッシュ」XMLデータを読み込む
AttributeManager: 一部の属性名の変更、不要な属性の削除

[CSV2] リーダー: 土地利用種別コードと画素値の対応表を読み込む
ListBuilder: 土地利用種別コードと画素値の全てのペアをひとつのリスト属性に格納する

FeatuerMerger リスト属性を土地利用細分メッシュフィーチャーに結合する
PythonCaller: Python スクリプトにより、ラスター (8ビット符号なし整数1バンド) に変換する
AttributeFileReader: パレットの定義 (画素値 - RGBの対応) を記述したテキストを読み込む
RasterPaletteAdder: パレットをラスターに設定する
[PNGRASTER] ライター: PNG形式のファイルに出力する


国土数値情報「土地利用細分メッシュ」(平成26年) 1次メッシュ区画 5339, 5340 の変換結果
FME Data Inspector による表示 (背景は地理院地図の淡色地図)
FME 2017.0 では、Data Inspector のビューの背景 (Background Map) として、地理院地図 (Japan GSI Maps) も表示できるようになりました。
















[XML] リーダーでは、土地利用細分メッシュXMLの ksj:Dataset/ksj:LanduseSubdivisionMesh 要素をフィーチャータイプとして読み込むことにしました。ワークスペースにリーダーを追加するときに、次のようにパラメーターを設定します。

  • Configuration Type: Feature Paths
  • Elements to Match: Dataset/LanduseSubdivisionMesh
  • Flatten Options: [Options...] > Enable Flattening チェックボックスをチェック

[XML] リーダーパラメーター設定画面



























平坦化 (Flatten) オプションを有効にすると、ksj:LanduseSubdivisionMesh 要素に属する全てのXMLノード (要素、属性) が平坦化され、フィーチャー属性として読み込まれます。個々のXML要素の値を格納するフィーチャー属性の名前は、LanduseSubdivisionMesh より下位の XPath (XMLドキュメントツリーにおける上位から下位の順でノード名を / 区切りで連結した文字列) から名前空間接頭辞を除き、ドット区切りに置き換えたものになります。

例えば、XPath (ドキュメントルートからのフルパス)
ksj:Dataset/ksj:LanduseSubdivisionMesh/ksj:coverage/gml:boundedBy/gml:Envelope/gml:lowerCorner
で指定されるXML要素の内容 (値) を格納するフィーチャー属性名は、
coverage.boundedBy.Envelope.lowerCorner
になります。「XMLの読込 - 断片化と平坦化」もご参照ください。

AttributeManager では、以後の処理に必要な属性だけ残す (他を削除する) とともに、属性名を変更して簡素にしました。これは、必須のことではありません。

土地利用細分メッシュラスター作成用の属性
変更前の属性名変更後内容
coverage.boundedBy.Envelope.lowerCornerlowerCorner1次メッシュ区画南西隅の座標 (緯度 経度)
coverage.boundedBy.Envelope.upperCornerupperCorner1次メッシュ区画北東隅の座標 (緯度 経度)
coverage.rangeSet.DataBlock.tupleListtupleList土地利用種別コードのリスト (800列 x 800行)
meshcodemeshcode1次メッシュコード

[CSV2] リーダーで、土地利用細分メッシュデータ (平成21, 26年) で使用されている土地利用種別コード (文字列) とラスター画素値 (整数) の対応表を読み込みました。対応表の内容は[初版]で使用したものと同じです。

注: FME 2017 では CSV リーダー/ライターもアップグレードしました。新バージョンの CSV リーダー/ライター用のフォーマット識別子は CSV2 です。

土地利用種別コード-画素値.csv
コード,土地利用種別,画素値
0100,田,1
0200,その他の農用地,2
0500,森林,3
0600,荒地,4
0700,建物用地,5
0901,道路,6
0902,鉄道,7
1000,その他の用地,8
1100,河川地及び湖沼,9
1400,海浜,10
1500,海水域,11
1600,ゴルフ場,12
0000,解析範囲外,0


次の ListBuilder によって、土地利用種別コードと画素値の全てのペアをひとつのリスト属性に格納したうえで、FeatureMerger によって、そのリスト属性を LanduseSubdivisionMesh フィーチャーに結合しました。このリスト属性を参照することにより、XMLから読み込まれた土地利用種別コードをラスター画素値に置き換えることができます。

PythonCaller は、ワークスペースの実行時、フィーチャーを受け取るたびに Python スクリプトを実行して入力フィーチャーに何らかの変更 (ジオメトリや属性の追加、削除、変更等) を施してから出力します。また、必要に応じて、新たなフィーチャーを生成したり、入力フィーチャーを削除したりするようなスクリプトを設定することもできます。

PythonCaller パラメーター設定画面





















実行すべきスクリプト (クラスまたは関数) を Python Script パラメーターに、そのクラス名/関数名を Class or Function to Process Features パラメーターに設定します。スクリプトで Python FME Objects API を利用する場合は、fmeobjects モジュールをインポートします。

詳細については次のページを参照してください。

このワークスペース例の PythonCaller に設定したスクリプト (全文) は、次のとおりです。

import fmeobjects

class MyUInt8BandTilePopulator(fmeobjects.FMEBandTilePopulator):
    def __init__(self, dataArray):
        self.dataArray = dataArray
        
    def clone(self):
        return MyUInt8BandTilePopulator(self.dataArray)
    
    def getTile(self, startRow, startCol, tile):
        numRows, numCols = tile.getNumRows(), tile.getNumCols()
        endRow, endCol = startRow + numRows, startCol + numCols
        data = [self.dataArray[r][startCol:endCol] for r in range(startRow, endRow)]
        newTile = fmeobjects.FMEUInt8Tile(numRows, numCols)
        newTile.setData(data)
        return newTile
        
class KsjLanduseSubdivisionMeshRasterizer(object):
    def __init__(self):
        # Nodata値設定用タイル
        self.nodata = fmeobjects.FMEUInt8Tile(1, 1)
        self.nodata.setData([[0]])
        
    def input(self,feature):
        # 土地利用種別コードから画素値への変換用辞書
        codes = feature.getAttribute('_list{}.コード')
        values = feature.getAttribute('_list{}.画素値')
        codeToValue = {c:int(v) for c, v in zip(codes, values)}
        
        # 土地利用種別コードリストを取得し, 画素値データ配列に変換
        tupleList = feature.getAttribute('tupleList')
        data = [codeToValue.get(c, 0) for c in tupleList.split()]
        dataArray = [data[i:i+800] for i in range(0, 640000, 800)]
        
        # 範囲の最小/最大座標
        lower = feature.getAttribute('lowerCorner').split()
        upper = feature.getAttribute('upperCorner').split()
        xmin, ymin = float(lower[1]), float(lower[0])
        xmax, ymax = float(upper[1]), float(upper[0])

        # ラスターオブジェクト作成 (解像度は 800x800 pixels 固定)
        rasterProperties = fmeobjects.FMERasterProperties(800, 800,
            (xmax-xmin)/800, (ymax-ymin)/800,
            0.5, 0.5, xmin, ymax, 0.0, 0.0)
        raster = fmeobjects.FMERaster(rasterProperties)
        
        # バンドオブジェクト作成, ラスターに追加
        bandTilePopulator = MyUInt8BandTilePopulator(dataArray)
        bandProperties = fmeobjects.FMEBandProperties('Landuse',
            fmeobjects.FME_INTERPRETATION_UINT8,
            fmeobjects.FME_TILE_TYPE_FIXED, 800, 800)            
        band = fmeobjects.FMEBand(bandTilePopulator,
            rasterProperties, bandProperties, self.nodata)
        raster.appendBand(band)

        # フィーチャーにラスターを設定して出力        
        feature.setGeometry(raster)
        self.pyoutput(feature)


このスクリプトで作成されるラスターは、8ビット符号なし整数1バンドの数値ラスターですが、次のようなパレットを設定することにより、カラー表示が可能になります。AttributeFileReader と RasterPaletteAdder によるパレットの設定方法は[初版]と同じです。

土地利用ラスターパレット.txt
RGB24
0 0,0,0
1 85,170,0
2 255,255,0
3 0,100,0
4 170,85,0
5 255,170,0
6 170,170,170
7 170,0,170
8 170,170,0
9 0,170,255
10 255,170,127
11 0,0,255
12 170,255,127

[PNGRASTER] ライターフィーチャータイプでは、meshcode 属性の値をフィーチャータイプ名 (Raster File Name) に設定することにより、出力先ファイル名 = 1次メッシュコード (4桁数字) としました。[PNGRASTER] ライターは、デフォルトで自動的にワールドファイルも作成します。


多くの場合、標準のトランスフォーマーの組み合わせによって要件を満たしたワークスペースを作成できるので、FMEを利用するうえで Python プログラミングは必須ではありません。

しかし、一部のプロセスをスクリプトに置き換えれば格段に性能が良くなることはあり、また、標準のトランスフォーマーだけではワークフローが極めて大規模、複雑になることもあります。そのような場合に、実行時の性能が良く、かつ、簡潔なワークスペースとするためにスクリプトを組み込むのは効果的です。

土地利用細分メッシュXMLからラスターへの変換は、土地利用種別コードのリストに基づいてラスターを作成するプロセスをスクリプトに置き換えることによって、格段に性能が良くなりました。

多くのソフトウェアで、ユーザーによるカスタマイズやプラグインの開発を行うためのプログラム言語として Python が採用されており、そのようなソフトウェアのユーザーは、これまでに培ってきた Python スキルを FME ワークスペース開発に生かすことができます。また逆に、FME ユーザーはワークスペース開発で培ったスキルを他のソフトウェアを活用するために生かせます。どこから始めるにしても、Python を学んで損することはないと思います。まだ Python を使ったことがない方は是非、チャレンジしてください。

0 件のコメント:

コメントを投稿