Ottieni coordinate e corrispondenti valori di pixel da GeoTiff usando python gdal e salvali come matrice numpy


10

Come posso ottenere coordinate proiettate così come i valori dei pixel effettivi su tali coordinate da un file GeoTiff e salvarli in un array numpy? Ho un file arsenci020l.tif e le sue coordinate sono in metri. Di seguito è riportato l'output abbreviato di gdalinfo che ho eseguito su di esso.

~$ gdalinfo arsenci020l.tif 
Driver: GTiff/GeoTIFF
Files: arsenci020l.tif
       arsenci020l.tfw
Size is 10366, 7273
Coordinate System is:
PROJCS["Lambert Azimuthal Equal Area projection with arbitrary plane grid; projection center 100.0 degrees W, 45.0 degrees N",
    GEOGCS["WGS 84",
        DATUM["WGS_1984",
            SPHEROID["WGS 84",6378137,298.257223563,
                AUTHORITY["EPSG","7030"]],
            AUTHORITY["EPSG","6326"]],
        PRIMEM["Greenwich",0],
        UNIT["degree",0.0174532925199433],
        AUTHORITY["EPSG","4326"]],
    PROJECTION["Lambert_Azimuthal_Equal_Area"],
    PARAMETER["latitude_of_center",45],
    PARAMETER["longitude_of_center",-100],
    PARAMETER["false_easting",0],
    PARAMETER["false_northing",0],
    UNIT["metre",1,
        AUTHORITY["EPSG","9001"]]]
Origin = (-6086629.000000000000000,4488761.000000000000000)
Pixel Size = (1000.000000000000000,-1000.000000000000000)
...

C'è stata una domanda simile qui su come ottenere coordinate lat / long da tiff (Ottieni latitudine e longitudine da un file GeoTIFF) e la risposta ha mostrato come ottenere solo le coordinate pixel x e y in alto a sinistra. Devo ottenere TUTTE le coordinate pixel proiettate, nonché ottenere i valori dei pixel e salvarli in una matrice numpy. Come posso farlo?


Vuoi 10366 × 7273 = oltre 75 milioni di punti?
Mike T,

@MikeT Penso di sì, non conosco davvero una soluzione migliore su come affrontare il problema che sto cercando di risolvere: devo trovare la coordinata pixel più vicina da questo set di dati a ciascun centroide del blocco USA e quindi assegnare il corrispondente valore di pixel a quel blocco. Dalla ricerca ho capito che la query cKDTree mi aiuterà con la ricerca del vicino più vicino. La funzione Pitone per l'algoritmo richiede un "albero" da interrogare come matrice numpy. Al fine di creare un "albero" tra tutte le coordinate pixel di questo set di dati, devo memorizzarle tutte in qualche modo. Se hai una soluzione migliore, per favore fatemelo sapere!
irakhman,

Risposte:


7

aggiungerei come commento, ma un po 'di tempo - nel caso in cui volessi usare gdal / ogr in Python - qualcosa del genere potrebbe funzionare (hackerato insieme da qualche altro codice che avevo - non testato!) Questo presuppone anche che piuttosto che trovare il più vicino pixel raster su un centroide poligonale, basta interrogare il raster alla xy del centroide. non ho idea di quale potrebbe essere il compromesso di velocità ...

from osgeo import gdal,ogr

fc='PathtoYourVector'
rast='pathToYourRaster'

def GetCentroidValue(fc,rast):
    #open vector layer
    drv=ogr.GetDriverByName('ESRI Shapefile') #assuming shapefile?
    ds=drv.Open(fc,True) #open for editing
    lyr=ds.GetLayer(0)

    #open raster layer
    src_ds=gdal.Open(rast) 
    gt=src_ds.GetGeoTransform()
    rb=src_ds.GetRasterBand(1)
    gdal.UseExceptions() #so it doesn't print to screen everytime point is outside grid

    for feat in lyr:
        geom=feat.GetGeometryRef()
        mx=geom.Centroid().GetX()
        my=geom.Centroid().GetY()

        px = int((mx - gt[0]) / gt[1]) #x pixel
        py = int((my - gt[3]) / gt[5]) #y pixel
        try: #in case raster isnt full extent
            structval=rb.ReadRaster(px,py,1,1,buf_type=gdal.GDT_Float32) #Assumes 32 bit int- 'float'
            intval = struct.unpack('f' , structval) #assume float
            val=intval[0]
        except:
            val=-9999 #or some value to indicate a fail

       feat.SetField('YOURFIELD',val)
       lyr.SetFeature(feat)

    src_ds=None
    ds=None

GetCentroidValue(fc,rast)

14

Questo dovrebbe farti andare. I valori raster vengono letti usando rasterio e le coordinate del centro del pixel vengono convertite in Eastings / Northings usando affine , che vengono quindi convertite in Latitude / Longitude usando pyproj . La maggior parte degli array ha la stessa forma dell'input raster.

import rasterio
import numpy as np
from affine import Affine
from pyproj import Proj, transform

fname = '/path/to/your/raster.tif'

# Read raster
with rasterio.open(fname) as r:
    T0 = r.transform  # upper-left pixel corner affine transform
    p1 = Proj(r.crs)
    A = r.read()  # pixel values

# All rows and columns
cols, rows = np.meshgrid(np.arange(A.shape[2]), np.arange(A.shape[1]))

# Get affine transform for pixel centres
T1 = T0 * Affine.translation(0.5, 0.5)
# Function to convert pixel row/column index (from 0) to easting/northing at centre
rc2en = lambda r, c: (c, r) * T1

# All eastings and northings (there is probably a faster way to do this)
eastings, northings = np.vectorize(rc2en, otypes=[np.float, np.float])(rows, cols)

# Project all longitudes, latitudes
p2 = Proj(proj='latlong',datum='WGS84')
longs, lats = transform(p1, p2, eastings, northings)

1
Quando lo utilizzo, ricevo il messaggio "AttributeError: l'oggetto 'DatasetReader' non ha alcun attributo 'affine'" per la riga "T0 = r.affine"
mitchus

@mitchus Apparentemente affineè solo un alias per transform, e l'alias è stato rimosso dalla versione più recente di rasterio. Ho modificato la risposta ma sembra che debba essere rivisto da pari poiché sono nuovo qui. :)
Autumnsault,

1
Sembra anche che gli indici siano sbagliati A.shape, che ha solo due dimensioni.
Autumnsault,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.