Python kullanarak bir rasterdeki her pikselin XY koordinatlarını ve hücre değerini nasıl alabilirim?


16

Python için gerçekten yeniyim ve ArcGIS 10'da Python kullanarak raster pikselin hücre değerlerini piksel ve koordinatlarını (her pikselin merkezinin XY koordinatını) almak için hızlı bir yöntem olup olmadığını bilmek ister misiniz?

Bunu daha fazla tanımlamak için, ilk pikselin X haritasını, Y haritasını ve hücre değerini almam ve bu üç değeri üç değişkene atamam ve diğer piksellerin geri kalanı için bu adımı tekrarlamam (tüm rasterde döngü) gerekir.


Sanırım sorumu daha fazla açıklamam gerekiyor. Sorun, ben ilk raster bir pikselin XY konumunu almak ve o XY konuma karşılık gelen diğer birkaç raster hücre değerleri almak gerekir. Bu işlem, herhangi bir ara nokta şekil dosyası oluşturmadan ilk rasterin her pikseli arasında döngü yapmalıdır çünkü yaklaşık 8 milyar piksele sahip bir rasterle başa çıkmak zorunda olduğum için gerçekten çok zaman alıcı olacak. Ayrıca, bunu ArcGIS 10'da Python kullanarak yapmam gerekiyor.

@ JamesS: Öneriniz için çok teşekkür ederim. Evet bu bir tarama için işe yarayacaktır, ancak diğer birkaç raster için de hücre değerlerini toplamam gerekiyor. Sorun, ilk raster ilk pikselin X ve Y koordinatını aldıktan sonra, ilk raster X, Y konumu, sonra üçüncü raster ve benzeri karşılık gelen ikinci raster hücre değerini almak gerekir. Bu yüzden, ilk rasterde döngü yaparken, bir pikselin X ve Y konumunu alıp o konuma karşılık gelen diğer rasterlerin hücre değerlerini aynı anda yapmak gerektiğini düşünüyorum ama emin değilim. Bu, ilk raster bir nokta şekil dosyasına dönüştürülerek ve ArcGIS 10'da çoklu değerlerin nokta işlevine Ayıkla gerçekleştirilerek yapılabilir, ancak '

@hmfly: Teşekkürler, Evet bu yöntem (RastertoNumpyarray) dizinin bilinen bir satır ve sütun değeri koordinatını alabilirsiniz çalışır.

@whuber: Herhangi bir hesaplama yapmak istemiyorum, tek yapmam gereken XY koordinatlarını ve hücre değerlerini bir metin dosyasına yazmak ve hepsi bu


Belki de tüm taramada biraz matematik yapmak istersiniz? Raster hesap makineleri piksel piksel çalışır.
BWill

1
lütfen amacınızı daha ayrıntılı olarak açıklayın.
BWill

Normalde, noktalar üzerinde döngü yapmak yerine Harita Cebiri işlemleri kullanılarak verimli ve güvenilir çözümler elde edilir. Uzamsal Analistin harita cebiri uygulamasındaki sınırlamalar, bu yaklaşımı her durumda çalışmaktan alıkoyar, ancak şaşırtıcı derecede çok sayıda durumda bir döngüyü kodlamanız gerekmez. Tam olarak hangi hesaplamayı yapmanız gerekiyor?
whuber

Düzenlemenizi yeniden yapın: tabii ki bu meşru bir amaçtır. Biçim, boru hattının ilerisindeki yazılım ihtiyaçları tarafından dayatılabilir. Ancak 8 milyar (X, Y, değer1, ..., değer3) tuples yazmanın 224 milyar bayt (ikili) ve belki de oldukça büyük bir veri kümesi olan 400 milyar bayt (ASCII'de) gerektireceğini düşünürsek, nihayetinde başarmaya çalıştığınız her şeye alternatif yaklaşımlar bulmaya değer olabilir!
whuber

Yanıtlar:


11

@ Dango'nun fikrini takiben aşağıdaki kodu (aynı ölçüde ve hücre boyutunda küçük rasterlerde) oluşturdum ve test ettim:

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 kodunu temel alarak istediğiniz değerlere erişebilirsiniz:

(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

Ne yazık ki bir 'ama' var - kod sistem belleği tarafından işlenebilen NumPy dizileri için doğru. Sistemim için (8GB), en büyük dizi yaklaşık 9000.9000 idi.

Deneyimlerim daha fazla yardım sağlamama izin vermediğinden, büyük dizilerle uğraşmayla ilgili bazı önerileri düşünebilirsiniz: /programming/1053928/python-numpy-very-large-matrices

arcpy.RasterToNumPyArrayyöntemi, NumPy dizisine ( ArcGIS10 yardım sayfası ) dönüştürülen raster alt kümesinin, büyük veri kümesini alt matrislere dönüştürürken faydalı olabilecek özellikleri belirtmeye olanak tanır .


Marcin'nin kodu süper! teşekkürler, ama raster aynı çözünürlüğü ile raster X, Y yazmıyor Yani x ve y 1 m büyümek, örneğin) 100 metre .... Düzeltmek için bir öneriniz var mı Teşekkürler

7

Piksel değerlerini (satır, sütun) üzerinden almak istiyorsanız, şöyle bir komut dosyası yazabilirsiniz:

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))

Ancak, pikselin koordinatını almak istiyorsanız, NumPyArray size yardımcı olamaz. Raster'i RasterToPoint Tool ile noktaya dönüştürebilir ve daha sonra Shape'ye göre koordinatı alabilirsiniz.


7

ArcGIS 10'da bir metin dosyasına koordinatları ve hücre değerlerini çıkarmanın en basit yöntemi örnek işlevdir , koda gerek yoktur ve özellikle her hücre üzerinde döngü oluşturmaya gerek yoktur. Gelen ArcGIS'de <= 9.3x tarama hesap o kadar kolay olarak eskiden outfile.csv = sample(someraster)olduğu çıktılayacaktır (Z, X, Y biçiminde) Tüm (olmayan boş) hücre değerleri ve koordinat bir metin dosyası. ArcGIS 10'da "in_location_data" argümanı artık zorunlu olduğu için sözdizimini kullanmanız gerekiyor Sample(someraster, someraster, outcsvfile).

Düzenleme: Ayrıca birden rasterları belirtebilirsiniz: Sample([someraster, anotherraster, etc], someraster, outcsvfile). Bu 8 milyar hücre üzerinde çalışsın, hiç fikrim yok ...

Düzenleme: Not, bu ArcGIS 10 test etmedim, ancak <= 9.3 (ve Workstation) yıllarca örnek işlevini kullandık.

Düzenleme: Şimdi ArcGIS 10'da test yaptım ve bir metin dosyasına çıkmayacak. Araç, dosya uzantısını otomatik olarak ".dbf" olarak değiştirir. Ancak ... aşağıdaki python kodu SOMA olarak çalışır ve MOMA harita cebir ifadeleri ArcGIS 10'da hala desteklenmektedir:

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

Çok hoş. Bunu işaret ettiğiniz için teşekkürler - bu aracı daha önce fark etmemiştim. Kesinlikle çok daha temiz ve benim çözüm daha basit!
JamesS

6

Bunu yapmanın bir yolu, Raster_To_Point aracını ve ardından Add_XY_Coordinates aracını kullanmaktır. Nitelik tablosundaki her satırın rasterinizden X_Coord , Y_Coord ve Cell_Value sütunlarını içeren bir pikseli temsil ettiği bir şekil dosyası ile karşılaşırsınız . Daha sonra bir imleç kullanarak bu tablo üzerinde döngü (veya isterseniz Excel gibi bir şeye dışa aktarabilirsiniz).

İşlem yapmak için yalnızca bir tarama cihazınız varsa, muhtemelen komut dosyası oluşturmaya değmez - sadece ArcToolbox'tan araçları kullanın. Bunu birçok raster için yapmanız gerekiyorsa, böyle bir şey deneyebilirsiniz:

[ Not: ArcGIS 10'um yok ve ArcPy'ye aşina değilim, bu yüzden bu çok kaba bir taslak. Test edilmemiştir ve işe yaraması için neredeyse kesinlikle ince ayar yapması gerekecektir.]

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)

Daha sonra bir Arama İmleç kullanarak şekil dosyası öznitelik tabloları veya dbfpy kullanarak (muhtemelen daha basit) döngü yapabilirsiniz . Bu, rasterinizden (şimdi bir şekil dosyası .dbf tablosunda saklanan) verileri python değişkenlerine okumanıza izin verecektir.

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

Belki tarama için bir dünya dosyası oluşturabilir, tarama işlemini bir numpy dizisine dönüştürebilirsiniz. dizi üzerinde döngü yaparsanız hücre değerlerini alırsınız ve x, y'yi dünya dosyasından artımlı olarak güncelleştirirseniz, her hücre değeri için koordinatlara sahip olursunuz. umarım faydalıdır.


JamesS tarafından önerilen Raster to Point aracı yöntemiyle ilgilenmiyorsanız, bunun yol olduğunu söyleyebilirim.
nmpeterson

3

RasCentrX ve rasCentrY işlevlerindeki bir sorun dışında çıkış koordinatlarının farklı bir çözünürlükte görünmesine (Grazia'nın gözlemlediği gibi) neden olması dışında Marcin'in kodu iyi çalıştı. Düzeltmem değişti

coordX = rasXmin + (0.5*rasMeanCellWidth + rasWidth)

için

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

ve

  coordY = rasYmin + (0.5*rasMeanCellHeight + rasHeight)

için

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

ESRI Izgarasını bir CSV dosyasına dönüştürmek için kod kullandım. Bu, inRaster2'ye yapılan referans kaldırılarak, ardından koordinatları ve değerleri çıkarmak için bir csv.writer kullanılarak gerçekleştirildi:

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])

Ayrıca aktarımın gerekli olduğunu bulamadım

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

bunu dönüştürdü

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

2

Çirkin ama son derece etkili:

  1. Söz konusu rasterlerin köşelerinin dışında 4 nokta ile yeni bir nokta özelliği oluşturun. Söz konusu tarama ile aynı koordinat sisteminde emin olun.
  2. 'Xcor' ve 'ycor' çift alanlarını ekleyin
  3. Bu alanların koordinatlarını almak için geometriyi hesaplayın
  4. Mekansal Analist-> Enterpolasyon-> Eğilim -> Doğrusal regresyon
  5. Ortam ayarları: raster ve hücre boyutunu söz konusu rasterle aynı tutturma
  6. 'Xcor' ve 'ycor' için ayrı olarak yürütün
  7. Out, hücre değerleri olarak koordinatlı değerlendiricilerle gelir, komut dosyaları için girdi olarak kullanın.

2

Açık kaynaklı python paketleri kullanarak basit bir çözüm:

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, şekil dosyasını açabildiğiniz, özellikler arasında yineleyebildiğiniz ve (benim gibi) bir dictnesneye ekleyebileceğiniz için kullanışlıdır . Aslında Fiona'nın featurekendisi de bir gibidir dict, bu yüzden özelliklere erişmek kolaydır. Puanlarımın herhangi bir özelliği olsaydı, bu dikte koordinatları, kimliği vb.Ile birlikte görünürlerdi.

Rasterio kullanışlıdır, çünkü rasterde nümerik bir dizi, hafif ve hızlı bir veri türü olarak okunması kolaydır. Ayrıca raster x, y koordinatlarını dizi satırına, col koordinatlarına dönüştürmek için gereken tüm veriler dictde dahil olmak üzere bir raster özelliklerine erişebiliriz affine. @ Perrygeo'nun mükemmel açıklamasına buradan bakın .

Her bir nokta için veri içeren ve ayıklanan bir pt_datatür ile dictsonuçlanır raster_value. İstersek şekil dosyasını da çıkarılan verilerle kolayca yeniden yazabiliriz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.