Ottenere il valore in pixel di GDAL raster sotto il punto OGR senza NumPy?


45

Sto lavorando a un modello computazionale dell'abbondanza di impollinatori selvatici in un paesaggio. Il modello stesso è completo e ora sto lottando con una fase di post-elaborazione.

Ho il mio raster di fornitura impollinatore GDAL che assomiglia a questo (i colori più chiari significano una maggiore visita dell'impollinatore in un pixel):

Scala di grigi raster che rappresenta la fornitura di impollinatori su un paesaggio

E ho un file di forma OGR di punti che rappresentano posizioni campione sul paesaggio:

inserisci qui la descrizione dell'immagine

Sto cercando di eseguire alcune analisi sui pixel sotto questi punti, ma per farlo, devo essere in grado di estrarre il valore di un pixel sotto un punto.

È possibile estrarre il valore di un pixel sotto un punto usando solo OGR e GDAL tramite Python? Preferirei evitare di leggere l'intero raster in memoria ReadAsArray(), poiché i miei raster di output sono molto, molto grandi (troppo grandi per adattarsi alla memoria).

Ho notato questo post , che è simile, ma richiede una chiamata da riga di comando.


2
Che dire di ReadAsArray () e della sola lettura nel punto? Quindi leggi solo la singola cella che ti interessa? Dovresti convertire dalle coordinate dei punti nello spazio pixel ed estrarre la cella necessaria.
Jay Laura,

1
Guarda il codice per gdalsrsinfo, ti mostra come usare GDALInvertGeoTransform () e passare dallo spazio geografico allo spazio pixel: trac.osgeo.org/gdal/browser/trunk/gdal/apps/gdalsrsinfo.cpp

Se non ti dispiace usare PostGIS, vedi questo . È estremamente veloce ed è solo 1 riga SQL.
mlt

Lo terrò presente se riscontro questo problema e accedo a un database PostGIS! Non ho fatto questo particolare problema, quindi la soluzione GDAL di seguito ha fatto il trucco. Grazie comunque!
James,

@kyle Non so se le cose sono cambiate ma sembra che GDALInvGeoTransform non sia invertito e questo è un esempio .
mlt

Risposte:


61

È possibile utilizzare il metodo gdal.Dataset o gdal.Band ReadRaster. Consulta le esercitazioni sull'API GDAL e OGR e l'esempio di seguito. ReadRaster non utilizza / richiede intorpidimento, il valore restituito è dato binario non elaborato e deve essere decompresso utilizzando il modulo strutt python standard .

Un esempio:

from osgeo import gdal,ogr
import struct

src_filename = '/tmp/test.tif'
shp_filename = '/tmp/test.shp'

src_ds=gdal.Open(src_filename) 
gt=src_ds.GetGeoTransform()
rb=src_ds.GetRasterBand(1)

ds=ogr.Open(shp_filename)
lyr=ds.GetLayer()
for feat in lyr:
    geom = feat.GetGeometryRef()
    mx,my=geom.GetX(), geom.GetY()  #coord in map units

    #Convert from map to pixel coordinates.
    #Only works for geotransforms with no rotation.
    px = int((mx - gt[0]) / gt[1]) #x pixel
    py = int((my - gt[3]) / gt[5]) #y pixel

    structval=rb.ReadRaster(px,py,1,1,buf_type=gdal.GDT_UInt16) #Assumes 16 bit int aka 'short'
    intval = struct.unpack('h' , structval) #use the 'short' format code (2 bytes) not int (4 bytes)

    print intval[0] #intval is a tuple, length=1 as we only asked for 1 pixel value

In alternativa, poiché il motivo fornito per non utilizzare numpyera evitare di leggere l'intero array durante l'utilizzo ReadAsArray(), di seguito è riportato un esempio che utilizza numpye non legge l'intero raster in.

from osgeo import gdal,ogr
import struct

src_filename = '/tmp/test.tif'
shp_filename = '/tmp/test.shp'

src_ds=gdal.Open(src_filename) 
gt=src_ds.GetGeoTransform()
rb=src_ds.GetRasterBand(1)

ds=ogr.Open(shp_filename)
lyr=ds.GetLayer()
for feat in lyr:
    geom = feat.GetGeometryRef()
    mx,my=geom.GetX(), geom.GetY()  #coord in map units

    #Convert from map to pixel coordinates.
    #Only works for geotransforms with no rotation.
    px = int((mx - gt[0]) / gt[1]) #x pixel
    py = int((my - gt[3]) / gt[5]) #y pixel

    intval=rb.ReadAsArray(px,py,1,1)
    print intval[0] #intval is a numpy array, length=1 as we only asked for 1 pixel value

E come puoi salvare come CSV, tabella o altro oggetto? Un oggetto con la stessa lunghezza di coordinate objetct
gonzalez.ivan90 il


le righe che assegnano px/ pysono errate nel caso in cui mx / my si trovi al di fuori dei limiti di rb, perché int(-0.5) == 0. È necessario floor(...)e quindi è necessario verificare che nessuno dei due sia px/ pysia inferiore a zero (o farlo prima di chiamare int()), perché gli indici negativi funzionano (ottengono l'altro lato dell'array). Mi piacerebbe sapere se esiste un modo più semplice per affrontare questo problema. Inoltre, come si riscrivono quelle righe in modo che gestiscano correttamente le rotazioni?
niente 1
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.