ラスター セルの反復子の使用法の概要
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)
ラスター オブジェクトのインデックス構築
ラスター オブジェクトのインデックスを構築すると、ラスター データセットの特定のセルに読み取りおよび書き込みアクセスを行えるようになります。 インデックスの構築は、ラスター セルの反復子の内部でも外部でも使用できます。
シングルバンド ラスターの場合、ラスター オブジェクトには [i, j] という 2 つのインデックスがあり、それぞれ行と列のインデックスです。 クエリーおよび値の割り当てには、最低 2 つのインデックスが必要です。 すべてのインデックスはゼロベースで、0 から始まります。 行インデックスの値の範囲は 0 から n (行数) - 1 までと定義されます。ここで、n (行数) はそのラスター内の行数です。 同様に、列インデックスの値の範囲も、0 から n (列数) - 1 までと定義され、n (列数) はそのラスター内の列数です。
インデックスの作成はラスター データセットの左上隅から始まり、左上隅のセルのインデックスは [0, 0]、右下隅のセルのインデックスは [n (行数) - 1、n (列数) - 1] です。
NoData セルの処理
NoData のセルが、RCI のコンテキストの内部または外部で、インデックス表記を使用してクエリーされると、Python で返される値は NaN です。 たとえば、myRas の行と列のインテックス [2, 2] の値が NoData であることが判明している場合、このセルの値をクエリーすると、NaN が返されます。 これは math.isnan() メソッドを使用すると、このセルに対してブール値 True が返されることで検証されます。
import math
math.isnan(myRas[2,2])
out: True
Python でセルに NaN が割り当てられると、そのラスター セルは、形式や NoDataValues に関係なく NoData になります。 これが、セルを NoData に変換する正しい方法です。 たとえば、myRas の行と列のインデックスが [3, 3] のセルに NaN を割り当てると、そのセルが NoData に変更されます。
myRas[3,3] = math.nan
セルを NoData に変換するときは、そのラスター データセットの noDataValues を直接セルに割り当てるのではなく、上述の方法に従うことをおすすめします。
ラスター セルの反復子による高度な操作
このセクションでは、RCI を使用して実行できる高度な操作について概念的に説明します。 明示的なラスター セルの反復子を作成して複数のラスターにわたって操作を反復的に行う方法と、padding および skipNoData オプションの使用法について説明します。 マルチバンド ラスターのインデックスを作成し、RCI 内で使用する方法を紹介します。 各種のラスター ピクセル タイプの扱い方や、境界外の値の処理方法について説明します。
明示的なラスター セルの反復子
RCI を呼び出すもう 1 つの方法は、明示的な RasterCellIterator クラス オブジェクトを使用することです。 暗黙的な反復子は、単一のラスター データセットでの反復処理に適していますが、明示的なラスター反復子は複数のラスターに対して反復処理を行うよう設計され、この目的のために最適化されています。 複数のラスターを反復処理するとき、計算に使用されるセル値を含む入力ラスターと、計算中にセル値が書き込まれる出力ラスターを使用して、解析を実行できます。
次の例は、明示的な RCI を使用して複数の入力および出力ラスターを反復処理する方法を示しています。 入力ラスター myRas1 および myRas2 は、行数と列数が同じで、セル サイズ、範囲、空間参照などの他のプロパティも持っています。 出力ラスター outRas1 および outRas2 は、最初の入力ラスターの rasterInfo クラス オブジェクトを使用して作成されます。 myRas1 および myRas2 について、各ラスター セルの 3 × 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 のセルを個別に処理する代わりに、完全にスキップする機能があります。 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 (バンド) - 1 までに決定されます。ここで、n (バンド) はバンドの総数です。
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