Pythonを使用してラスターの各ピクセルのXY座標とセル値を取得する方法は?


16

私は本当にPythonが初めてで、ArcGIS 10のPythonを使用して、ピクセルごとのラスターのセル値と座標(各ピクセルの中心のXY座標をマップ)を取得する簡単な方法があるかどうかを知りたいですか?

これをさらに説明するには、最初のピクセルのマップX、マップY、およびセル値を取得し、それらの3つの値を3つの変数に割り当て、他のピクセルの残りに対してこの手順を繰り返す必要があります(ラスター全体をループします)。


私の質問をもっと説明する必要があると思います。問題は、最初のラスタのピクセルのXY位置を取得し、そのXY位置に対応するいくつかの他のラスタのセル値を取得する必要があることです。このプロセスは、中間ポイントシェープファイルを作成せずに、最初のラスターのすべてのピクセルをループ処理する必要があります。80億ピクセル近くのラスターを処理する必要があるため、本当に時間がかかります。また、ArcGIS 10でPythonを使用してこれを行う必要があります。

@JamesS:ご提案ありがとうございます。はい、これは1つのラスターで機能しますが、他のいくつかのラスターのセル値も収集する必要があります。問題は、最初のラスタの最初のピクセルのX座標とY座標を取得した後、最初のラスタのX、Y位置、3番目のラスタなどに対応する2番目のラスタのセル値を取得する必要があることです。だから、最初のラスターをループするとき、ピクセルのXとYの位置を取得し、その位置に対応する他のラスターのセル値を取得することは同時に行われるべきだと思いますが、わかりません。これは、最初のラスターをポイントシェープファイルに変換し、ArcGIS 10でポイント値への複数値の抽出を実行することで実行できますが、

@hmfly:ありがとう、はい、このメソッド(RastertoNumpyarray)は、配列の既知の行と列の値の座標を取得できれば機能します。

@whuber:計算を実行したくないので、テキストファイルにXY座標とセル値を書き込むだけで十分です。


おそらく、ラスター全体に対していくつかの計算を行いたいだけでしょうか?ラスター計算機はピクセルごとに機能します。
Bウィル

1
目的をさらに詳しく説明してください。
Bウィル

通常、効率的で信頼性の高いソリューションは、ポイントをループするのではなく、マップ代数演算を使用することで得られます。Spatial Analystのマップ代数実装の制限により、このアプローチはすべてのケースで機能しませんが、驚くほど多くの状況では、ループをコーディングする必要はありません。正確にどのような計算を実行する必要がありますか?
whuber

編集してください:もちろんそれは正当な目的です。パイプラインのさらに下のソフトウェアのニーズにより、この形式が課される場合があります。しかし、80億(X、Y、value1、...、value3)のタプルを書き込むには、2,240億バイト(バイナリ)からおそらく4,000億バイト(ASCII)が必要であり、どちらもかなり大きなデータセットであると考えると、最終的に達成しようとしているものに対する代替アプローチを見つける価値があるかもしれません!
whuber

回答:


11

@Dangoのアイデアに従って、次のコードを(同じ範囲とセルサイズの小さなラスターで)作成してテストしました。

import arcpy, numpy

inRaster = r"C:\tmp\RastersArray.gdb\InRaster"
inRaster2 = r"C:\tmp\RastersArray.gdb\InRaster2"

##Get properties of the input raster
inRasterDesc = arcpy.Describe(inRaster)

#coordinates of the lower left corner
rasXmin = inRasterDesc.Extent.Xmin
rasYmin = inRasterDesc.Extent.Ymin

# Cell size, raster size
rasMeanCellHeight = inRasterDesc.MeanCellHeight
rasMeanCellWidth = inRasterDesc.MeanCellWidth
rasHeight = inRasterDesc.Height
rasWidth = inRasterDesc.Width

##Calculate coordinates basing on raster properties
#create numpy array of coordinates of cell centroids
def rasCentrX(rasHeight, rasWidth):
    coordX = rasXmin + (0.5*rasMeanCellWidth + rasWidth)
    return coordX
inRasterCoordX = numpy.fromfunction(rasCentrX, (rasHeight,rasWidth)) #numpy array of X coord

def rasCentrY(rasHeight, rasWidth):
    coordY = rasYmin + (0.5*rasMeanCellHeight + rasHeight)
    return coordY
inRasterCoordY = numpy.fromfunction(rasCentrY, (rasHeight,rasWidth)) #numpy array of Y coord

#combine arrays of coordinates (although array for Y is before X, dstack produces [X, Y] pairs)
inRasterCoordinates = numpy.dstack((inRasterCoordY,inRasterCoordX))


##Raster conversion to NumPy Array
#create NumPy array from input rasters 
inRasterArrayTopLeft = arcpy.RasterToNumPyArray(inRaster)
inRasterArrayTopLeft2 = arcpy.RasterToNumPyArray(inRaster2)

#flip array upside down - then lower left corner cells has the same index as cells in coordinates array
inRasterArray = numpy.flipud(inRasterArrayTopLeft)
inRasterArray2 = numpy.flipud(inRasterArrayTopLeft2)


# combine coordinates and value
inRasterFullArray = numpy.dstack((inRasterCoordinates, inRasterArray.T))

#add values from second raster
rasterValuesArray = numpy.dstack((inRasterFullArray, inRasterArray2.T))

@hmflyコードに基づいて、目的の値にアクセスできます。

(height, width, dim )=rasterValuesArray.shape
for row in range(0,height):
    for col in range(0,width):
        #now you have access to single array of values for one cell location

残念ながら1つだけですが、コードはシステムメモリで処理できるNumPy配列に適しています。私のシステム(8GB)では、最大のアレイは約9000,9000でした。

私の経験ではこれ以上のヘルプを提供できませんので、大きな配列での処理に関するいくつかの提案を検討できます:https ://stackoverflow.com/questions/1053928/python-numpy-very-large-matrices

arcpy.RasterToNumPyArrayメソッドを使用すると、NumPy配列に変換されたラスターのサブセットを指定できます(ArcGIS10ヘルプページ)。


Marcinのコードは最高です!感謝しますが、ラスターと同じ解像度でラスターのX、Yを書き込みません。たとえば、xとyは1 mになり、100 mではありません。...修正する提案はありますかありがとう

7

(行、列)を介してピクセル値を取得するだけの場合は、次のようなarcpyスクリプトを作成できます。

import arcpy
raster = arcpy.Raster("yourfilepath")
array = arcpy.RasterToNumPyArray(raster)
(height, width)=array.shape
for row in range(0,height):
    for col in range(0,width):
        print str(row)+","+str(col)+":"+str(array.item(row,col))

しかし、ピクセルの座標を取得したい場合、NumPyArrayは役に立ちません。RasterToPointツールでラスターをポイントに変換し、Shapeフィールドで座標を取得できます。


7

ArcGIS 10で座標とセル値をテキストファイルに出力する最も簡単な方法は、コードが不要で、特に各セルをループする必要がないサンプル関数です。ArcGIS <= 9.3xラスタ電卓それはのように簡単のように使用されるoutfile.csv = sample(someraster)出力のすべてのテキストファイル(Z、X、Y形式で)(非ヌル)セルの値と座標をあろう。ArcGIS 10では、「in_location_data」引数が必須になったように見えるため、構文を使用する必要がありますSample(someraster, someraster, outcsvfile)

編集:複数のラスタを指定することもできます:Sample([someraster, anotherraster, etc], someraster, outcsvfile)。これが80億個のセルで機能するかどうか、私にはまったくわからない...

編集:注、ArcGIS 10ではこれをテストしていませんが、サンプル関数は<= 9.3(およびWorkstation)で何年も使用しています。

編集:現在、ArcGIS 10でテストしましたが、テキストファイルには出力されません。ツールは、ファイル拡張子を「.dbf」に自動的に変更します。ただし、次のPythonコードは、SOMAおよびMOMAマップ代数ステートメントがArcGIS 10で引き続きサポートされるように機能します。

import arcgisscripting
gp=arcgisscripting.create()
gp.multioutputmapalgebra(r'%s=sample(%s)' % (outputcsv,inputraster))

非常に素晴らしい。これを指摘してくれてありがとう-私は以前このツールに気づいていなかった。確かに私のソリューションよりもすっきりとシンプル!
ジェームズ

6

これを行う1つの方法は、使用することですRaster_To_Pointのに続いツールAdd_XY_Coordinatesのツールを。属性テーブルの各行がX_CoordY_Coord、およびCell_Valueの列を持つラスターのピクセルを表すシェープファイルになります。次に、カーソルを使用してこのテーブルをループします(または、必要に応じてExcelなどにエクスポートします)。

処理するラスターが1つしかない場合、スクリプトを作成する価値はないでしょう。ArcToolboxのツールを使用してください。多くのラスタでこれを行う必要がある場合は、次のようなものを試すことができます。

[ 注: ArcGIS 10を持っていないため、ArcPyに精通していないため、これは非常に大まかな概要です。テストされていないので、ほとんど確実に機能させるために調整が必要です。

import arcpy, os
from arcpy import env

# User input
ras_fold = r'path/to/my/data'           # The folder containing the rasters
out_fold = r'path/to/output/shapefiles' # The folder in which to create the shapefiles

# Set the workspace
env.workspace = ras_fold

# Get a list of raster datasets in the raster folder
raster_list = arcpy.ListRasters("*", "All")

# Loop over the rasters
for raster in raster_list:
    # Get the name of the raster dataset without the file extension
    dataset_name = os.path.splitext(raster)[0]

    # Build a path for the output shapefile
    shp_path = os.path.join(out_fold, '%s.shp' % dataset_name)

    # Convert the raster to a point shapefile
    arcpy.RasterToPoint_conversion(raster, shp_path, "VALUE")

    # Add columns to the shapefile containing the X and Y co-ordinates
    arcpy.AddXY_management(shp_path)

その後、Search Cursorを使用して、または(おそらくはより単純な)dbfpyを使用して、シェープファイル属性テーブルをループできます。これにより、ラスター(シェープファイルの.dbfテーブルに格納されている)からPython変数にデータを読み込むことができます。

from dbfpy import dbf

# Path to shapefile .dbf
dbf_path = r'path\to\my\dbf_file.dbf'

# Open the dbf file
db = dbf.Dbf(dbf_path)

# Loop over the records
for rec in db:
    cell_no = rec['POINTID'] # Numbered from top left, running left to right along each row
    cell_x = rec['POINT_X']
    cell_y = rec['POINT_Y']
    cell_val = rec['GRID_CODE']

    # Print values
    print cell_no, cell_x, cell_y, cell_val

3

ラスタのワールドファイルを作成して、ラスタをnumpy配列に変換することもできます。次に、配列をループするとセル値が取得され、ワー​​ルドファイルからx、yを更新すると、各セル値の座標も取得されます。それが役に立つことを願っています。


JamesSによって提案されたRaster to Pointツールメソッドに興味がない場合は、これが進むべき方法だと思います。
nmpeterson

3

Marcinのコードは、rasCentrXおよびrasCentrY関数の問題により、出力座標が異なる解像度で表示されることを除いて、正常に機能しました(Graziaが観察したように)。私の修正は変更することでした

coordX = rasXmin + (0.5*rasMeanCellWidth + rasWidth)

coordX = rasXmin + ((0.5 + rasWidth) * rasMeanCellWidth)

そして

  coordY = rasYmin + (0.5*rasMeanCellHeight + rasHeight)

  coordY = rasYmin + ((0.5 + rasHeight) * rasMeanCellHeight)

このコードを使用して、ESRIグリッドをCSVファイルに変換しました。これは、inRaster2への参照を削除し、csv.writerを使用して座標と値を出力することで実現しました。

out = csv.writer(open(outputCSV,"wb"), delimiter=',', quoting=csv.QUOTE_NONNUMERIC)
out.writerow(['X','Y','Value'])
(height, width, dim )=inRasterFullArray.shape
for row in range(0,height):
    for col in range(0,width):
        out.writerow(inRasterFullArray[row,col])

また、転置が必要だとは思いませんでした

inRasterFullArray = numpy.dstack((inRasterCoordinates, inRasterArray.T))

それを

inRasterFullArray = numpy.dstack((inRasterCoordinates, inRasterArray))

2

glyいが非常に効果的:

  1. 問題のラスターの角の外側に4つのポイントを持つ新しいポイントフィーチャを作成します。問題のラスターと同じ座標系で確認してください。
  2. 「xcor」および「ycor」の二重フィールドを追加
  3. ジオメトリを計算して、これらのフィールドの座標を取得します
  4. 空間Analyst-> Interpolation-> トレンド - > 線形回帰
  5. 環境設定:ラスターとセルサイズを問題のラスターと同じサイズにスナップします
  6. 「xcor」と「ycor」に対して個別に実行
  7. 評価者は、座標をセル値として出力し、スクリプトの入力として使用します。

2

オープンソースのPythonパッケージを使用した簡単なソリューション:

import fiona
import rasterio
from pprint import pprint


def raster_point_coords(raster, points):

    # initialize dict to hold data
    pt_data = {}

    with fiona.open(points, 'r') as src:
        for feature in src:
            # create dict entry for each feature
            pt_data[feature['id']] = feature

    with rasterio.open(raster, 'r') as src:
        # read raster into numpy array
        arr = src.read()
        # rasterio always reads into 3d array, this is 2d, so reshape
        arr = arr.reshape(arr.shape[1], arr.shape[2])
        # get affine, i.e. data needed to work between 'image' and 'raster' coords
        a = src.affine

    for key, val in pt_data.items():
        # get coordinates
        x, y = val['geometry']['coordinates'][0], val['geometry']['coordinates'][1]
        # use affine to convert to row, column
        col, row = ~a * (x, y)
        # remember numpy array is indexed array[row, column] ie. y, x
        val['raster_value'] = arr[int(row), int(col)]

    pprint(pt_data) 

if __name__ == '__main__':
    # my Landsat raster
    ras = '/data01/images/sandbox/LT05_040028_B1.tif'
    # my shapefile with two points which overlap raster area
    pts = '/data01/images/sandbox/points.shp'
    # call function
    raster_point_coords(ras, pts)

Fionaは、シェープファイルを開いて機能を反復処理し、(私が持っているように)dictオブジェクトに追加できるので便利です。実際、フィオナfeature自体dictも同様であるため、プロパティに簡単にアクセスできます。私のポイントに属性がある場合、それらは座標、IDなどとともにこの辞書に表示されます。

Rasterioは、軽量で高速なデータ型であるnumpy配列としてラスターで読みやすいため、便利です。また、をdict含むラスタープロパティにアクセスできますaffine。これは、ラスターx、y座標を配列行、col座標に変換するために必要なすべてのデータです。@perrygeoの優れた説明はこちらをご覧ください

最終的に、各ポイントと抽出されたのデータを持つpt_dataタイプのdictになりraster_valueます。必要に応じて、抽出したデータでシェープファイルを簡単に書き換えることもできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.