RCI (Raster Cell Iterator) を使用して、カスタム ラスター解析を実行できます。RCI を使用すると、個々のラスター セル位置に移動し、反復制御を提供して、ラスター セルの値を検索および変更できます (すべて Python 環境で)。
ラスター セルの反復子を使用した基本的な操作
このセクションでは、RCI を使用して実行できる基本的な操作を概念的に理解します。暗黙的な RCI の作成方法、値の検索方法とラスター セルへの割り当て方法、メタデータで空のラスターを作成する方法、ラスター オブジェクトのインデックス構築方法、および NoData の処理方法について学習します。各セクションには、Python ウィンドウから RCI を使用する方法を示すコード例が含まれています。このドキュメントを上から順に読んで、これらのコード例を理解することをお勧めします。
暗黙的なラスター セルの反復子
RCI は、ラスター オブジェクトに対して暗黙的に実行し、ラスターのロウとカラムのインデックスを反復処理できます。下記のコード例では、既存のラスター データセット "myras" から myRas というラスター オブジェクトを作成します。暗黙的なラスターの反復子は、ループでラスター全体にわたってロウとカラムのインデックス ペアを列挙するラスター オブジェクトに対して定義されます。反復子内で、ロウ インデックス i、カラム インデックス j、およびセル値 myRas[i,j] がセル位置ごとに出力されます。これは、インデックス表記を使用して所定のセル位置のセル値を検索する例です。
from arcpy.sa import *
myRas = Raster("myras")
for i,j in myRas:
print(i, j, myRas[i,j])
セルへの値の割り当て
RCI を使用して、ラスター セルに値を割り当てることで、ラスター データセットを変更できます。デフォルトでは、既存のラスター データセットから作成されたラスター オブジェクトは、readOnly に設定された True プロパティを持ちます。ラスター データセットを変更するには、まず readOnly プロパティを False に設定する必要があります。ラスター セルの変更後、ラスター オブジェクトに対して save() メソッドを呼び出し、その変更を永続化する必要があります。readOnly プロパティおよびラスター保存の詳細については、Raster オブジェクトのヘルプ トピックをご参照ください。
myRas.readOnly = False
for i,j in myRas:
if myRas[i,j] == 0:
myRas[i,j] = 128
myRas.save()
空のラスターの作成
getRasterInfo() メソッドを使用すると、空のラスター オブジェクトを簡単に作成し、既存のラスター オブジェクトからメタデータをコピーできます。既存のラスター オブジェクトに対して getRasterInfo() メソッドが呼び出されます。これにより、このラスターの rasterInfo() オブジェクトが返されます。その後、rasterInfo() オブジェクトが Raster() クラスに入力パラメーターとして渡され、空のラスターをインスタンス化します。空のラスター オブジェクトは、作成元のラスター オブジェクトと同じメタデータを持ちますが、すべてのラスター セルに NoData が含まれます。ラスター メタデータは、bandCount、セル サイズ、extent、spatialReference、pixelType、noDataValues などのプロパティで構成されます。getRasterInfo() メソッドを使用してラスター オブジェクトを作成する場合、readOnly プロパティはデフォルトで False に設定されるため、この空のラスター オブジェクトに値を割り当てることができます。
outRas = Raster(myRas.getRasterInfo())
空の rasterInfo クラス オブジェクトを作成し、rasterInfo() オブジェクトに対して FromJSONString() メソッドを使用して、ラスター メタデータを設定することもできます。その後、以下に示すように、このオブジェクトを使用して空のラスターを作成できます。
ri = arcpy.RasterInfo()
ri_as_jsonstring = '{"bandCount":1,' \
'"extent":{"xmin":0,"ymin":0,"xmax":10,"ymax":10,"spatialReference":{"wkid":26912}},' \
'"pixelSizeX":1,' \
'"pixelSizeY":1,' \
'"pixelType":"F32"}'
ri.fromJSONString(ri_as_jsonstring)
outRas = Raster(ri)
ラスター オブジェクトのインデックス構築
ラスター オブジェクトのインデックスを構築すると、ラスター データセット内の特定のセルへの読み取り/書き込みアクセスが可能になります。インデックス構築は、ラスター セルの反復子の内部でも外部でも使用できます。
シングルバンド ラスターの場合、ラスター オブジェクトは 2 つのインデックス [i, j] を持ちます。これらは、それぞれロウとカラムのインデックスです。値の検索および割り当てには、少なくとも 2 つのインデックスが必要です。すべてのインデックスはゼロベースで、ゼロから開始されます。ロウ インデックスは 0 ~ n(rows) - 1 で定義された値の範囲を持ちます。ここで、n(rows) はそのラスターのロウ数です。同様に、カラム インデックスは 0 ~ n(cols) - 1 で定義された値の範囲を持ちます。ここで、n(cols) はそのラスターのカラム数です。
インデックス構築は、ラスター データセットの左上隅から開始されます。左上隅のセルはインデックス [0, 0] を持ち、右下隅のセルはインデックス [n(rows) - 1, n(cols) - 1] を持ちます。
NoData セルの処理
RCI のコンテキストの内部でも外部でも、インデックス表記を使用して NoData のセルが検索される場合、Python で返される値は NaN です。たとえば、myRas がロウとカラムのインデックス [2, 2] に NoData 値を持つことがわかっている場合、このセル値を検索すると NaN が返されます。これは、math.isnan() メソッドを使用して確認できます。このメソッドは、このセルについてブール値 True を返します。
import math
math.isnan(myRas[2,2])
out: True
Python でセルに NaN が割り当てられると、ラスター セルは、そのラスター データセットの形式にも NoDataValues にも関係なく、NoData になります。これは、セルを NoData にする正しい方法です。たとえば、ロウとカラムのインデックス [3, 3] で myRas に NaN を割り当てると、そのセルが NoData に変更されます。
myRas[3,3] = math.nan
そのラスター データセットの noDataValues を直接セルに割り当てることでセルを NoData にすることはお勧めできませんが、その代わりに上記の方法に従ってください。
ラスター セルの反復子を使用した高度な操作
このセクションでは、RCI を使用して実行できる高度な操作を概念的に理解します。明示的なラスター セルの反復子を作成して複数のラスターを反復処理する方法、および padding オプションと skipNoData オプションを使用する方法について学習します。また、マルチバンド ラスターのインデックス、および RCI 内でのそのインデックスの使用について学びます。さらに、さまざまなラスター ピクセル タイプの処理方法と、範囲外の値を扱う方法についても学習します。
明示的なラスター セルの反復子
RCI を実行するもう 1 つの方法は、明示的な RasterCellIterator クラス オブジェクトを使用することです。暗黙的な反復子は 1 つのラスター データセットの反復処理に適していますが、明示的なラスターの反復子は複数のラスターを反復処理するために設計されており、この目的に向けて最適化されています。複数のラスターを反復処理する場合は、セル値が計算に使用される入力ラスターと、計算中にセル値の書き込み先となる出力ラスターを使用して、解析を実行できます。
次の例は、明示的な RCI を使用して、複数の入力ラスターと出力ラスターを反復処理する方法を示しています。入力ラスター myRas1 および myRas2 は、同じ数のロウとカラムを持ち、他のプロパティ (セル サイズ、範囲、空間参照など) も同じです。出力ラスター outRas1 および outRas2 は、最初の入力ラスターの rasterInfo クラス オブジェクトを使用して作成されます。各ラスター セルで、myRas1 と myRas2 について 3 セル X 3 セルの近傍の平均値を計算するためにフォーカル演算が実行されます。このセル位置で、outRas1 には最小の平均値としてのセル値が割り当てられ、outRas2 には最大の平均値としてのセル値が割り当てられます。
myRas1 = Raster("myras1")
myRas2 = Raster("myras2")
outRas1 = Raster(myRas1.getRasterInfo())
outRas2 = Raster(myRas1.getRasterInfo())
with RasterCellIterator({'rasters':[myRas1, myRas2, outRas1, outRas2]}) as rci:
for i,j in rci:
meanMyRas1 = (myRas1[i-1,j-1] + myRas1[i-1, j] + myRas1[i-1, j+1] + \
myRas1[i,j-1] + myRas1[i, j] + myRas1[i, j+1] + \
myRas1[i+1,j-1] + myRas1[i+1, j] + myRas1[i+1, j+1]) / 9
meanMyRas2 = (myRas2[i-1,j-1] + myRas2[i-1, j] + myRas2[i-1, j+1] + \
myRas2[i,j-1] + myRas2[i, j] + myRas2[i, j+1] + \
myRas2[i+1,j-1] + myRas2[i+1, j] + myRas2[i+1, j+1]) / 9
outRas1[i,j] = min(meanMyRas1, meanMyRas2)
outRas2[i,j] = max(meanMyRas1, meanMyRas2)
outRas1.save()
outRas2.save()
反復子で複数のラスターが使用される場合、リストの最初のラスターが反復子のラスター解析環境を定義します。リスト内のその他すべてのラスターは、空間参照、セル サイズ、および範囲が最初のラスターと一致すると想定されています。このリスト内の 2 つ目以降のラスターのこれらのプロパティが最初のラスターと一致しない場合は、最初のラスターの解析環境がそれらのラスターに割り当てられます。最初のラスターの rasterInfo() オブジェクトを使用してすべての出力ラスターを作成することをお勧めします。これにより、それらのラスターが最初のラスターの空間参照、セル サイズ、および範囲を継承します。
さらに、環境設定を適用する場合は、ApplyEnvironment 関数を使用してこのリスト内の最初のラスターに環境設定を適用してから、反復子でそのラスターを使用する必要があります。下の例はこれを示しています。
myRas1 = Raster("myras1")
myRas2 = Raster("myras2")
#Apply environment settings to myRas1
myRas1_env = arcpy.sa.ApplyEnvironment(myRas1)
outRas1_env = Raster(myRas1_env.getRasterInfo())
with RasterCellIterator({'rasters':[myRas1_env, myRas2, outRas1_env]}) as rci:
for i,j in rci:
meanMyRas1 = (myRas1_env[i-1,j-1] + myRas1_env[i-1, j] + myRas1_env[i-1, j+1] + \
myRas1_env[i,j-1] + myRas1_env[i, j] + myRas1_env[i, j+1] + \
myRas1_env[i+1,j-1] + myRas1_env[i+1, j] + myRas1_env[i+1, j+1]) / 9
meanMyRas2 = (myRas2[i-1,j-1] + myRas2[i-1, j] + myRas2[i-1, j+1] + \
myRas2[i,j-1] + myRas2[i, j] + myRas2[i, j+1] + \
myRas2[i+1,j-1] + myRas2[i+1, j] + myRas2[i+1, j+1]) / 9
outRas1_env[i,j] = min(meanMyRas1, meanMyRas2)
outRas1_env.save()
埋め込みオプション
明示的な反復子には、埋め込みを提供するオプションが用意されています。埋め込みは、出力をまったく変更しませんが、セル位置を反復処理するときに近傍セル値にアクセスする場合にパフォーマンスを向上させます。たとえば、近傍解析操作に、反復処理下のセル位置から最大 2 ロウ セルまたは 2 カラム セル離れたセル値にアクセスするカーネルがある場合は、埋め込み 2 を指定します。
with RasterCellIterator({'rasters':[myRas1, outRas1], 'padding': 2}) as rci_padded:
for i,j in rci_padded:
outRas1[i,j] = (myRas1[i-2,j-2] + myRas1[i-2, j] + myRas1[i-2, j+2] + \
myRas1[i,j-2] + myRas1[i, j] + myRas1[i, j+2] + \
myRas1[i+2,j-2] + myRas1[i+2, j] + myRas1[i+2, j+2]) / 9
outRas1.save()
NoData オプションのスキップ
明示的な反復子には、NoData セルをセル単位で処理する代わりに、NoData セルをすべてスキップする機能があります。skipNoData キーを使用し、反復子がスキップするラスター セルを決定するラスターのリストを指定します。指定したセルについて、このリスト内のいずれかのラスターに NoData 値が含まれる場合、そのセルはスキップされます。これらのラスターの NoData セルの状態は反復の中で変化する可能性があるため、スキップの適用の有無は、反復子が巡回する各セルのラスターの状態によって決まります。このオプションの主なメリットとは、多くの NoData セルを巡回する必要がなくなるため、疎なラスター データセットに対して反復する際のパフォーマンスが向上することです。
次の例では、疎なラスター streamRas では河川を表すセルにのみ値が含まれ、他の場所には NoData が含まれます。流向ラスター flowDirRas には、ラスター範囲内のすべての場所に値が含まれますが、NoData セルはありません。RCI を使用して河川セルに沿った流向ラスター値を抽出する際、反復子が値を含む河川セルのみ巡回するよう skipNoData キーを使用し、巡回するセルの総数を最小限に抑えることができます。
streamRas = Raster("streams")
flowDirRas = Raster("flowdir")
outRas = Raster(flowDirRas.getRasterInfo())
with RasterCellIterator({'rasters':[streamRas, flowDirRas, outRas],'skipNoData':[flowDirRas, streamRas]}) as rci_skip:
for i,j in rci_skip:
outRas[i,j] = flowDirRas[i,j]
outRas.save()
マルチバンド ラスターのインデックス
マルチバンド ラスターの場合は、2 つまたは 3 つのインデックスを提供できます。これらのインデックスの動作の違いについて、以下で説明します。
2 つのインデックスが提供される場合、これらはロウとカラムのインデックスとして解釈され、指定された [row, column] インデックスについて各バンドから値のタプルが返されます。たとえば、3 つのバンドを持つマルチバンド ラスター "mbras" は、2 つのインデックス (例: [2,2]) で検索できます。これらはロウとカラムのインデックスとして解釈され、3 つの各バンドからの値はタプルとして返されます。
multibandRas = Raster("mbras")
multibandRas[2,2]
out: (4,5,6)
3 つのインデックスが指定される場合、これらは [band, row, column] インデックスとして解釈され、そのバンド、ロウ、カラムのセル位置についてセル値が返されます。バンド インデックスはゼロベースで、マルチバンド ラスターのその値範囲は 0 ~ n(bands) - 1 で決定されます。ここで、n(bands) はバンドの総数です。
multibandRas[0,2,2]
out: 4
範囲外の値の処理
すべてのラスターは、ピクセル タイプと、対応するビット深度を持ちます。ビット深度と、各セルに格納できる値の範囲の完全なリストについては、「ラスター データセット ピクセルのビット深度の容量」をご参照ください。ビット深度の許容可能な値の範囲を超えた値がラスター セルに割り当てられると、範囲外の状況が発生します。そのような状況では、セルに NoData が割り当てられます。たとえば、ラスター オブジェクト myRas1 のピクセル タイプが 'U8' であるとします。これは、8 ビットの符号なし整数です。このラスターは、0 ~ 255 の範囲の整数値を格納できます。myRas1 で 260 という値がセルに割り当てられると、そのセルに NoData が割り当てられます。このセルの値を検索すると、この割り当てに従って NaN が返されます。
myRas1 = Raster("myras1")
myRas1Info = myRas1.getRasterInfo()
pixelType_MyRas1 = myRas1Info.getPixelType()
print(pixelType_MyRas1)
out: 'U8'
myRas1[3,3] = 260
math.isnan(myRas1[3,3])
out: True