Obtenez des coordonnées et des valeurs de pixels correspondantes à partir de GeoTiff en utilisant python gdal et enregistrez-les en tant que tableau numpy


10

Comment puis-je obtenir les coordonnées projetées ainsi que les valeurs réelles des pixels à ces coordonnées à partir d'un fichier GeoTiff, puis les enregistrer dans un tableau numpy? J'ai le fichier arsenci020l.tif, et ses coordonnées sont en mètres. Voici la sortie abrégée de gdalinfo que j'ai exécutée dessus.

~$ 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)
...

Il y avait une question similaire ici concernant l'obtention de coordonnées lat / long à partir de tiff (obtenir la latitude et la longitude à partir d'un fichier GeoTIFF) et la réponse a montré comment obtenir uniquement les coordonnées des pixels x et y en haut à gauche. J'ai besoin d'obtenir TOUTES les coordonnées des pixels projetés ainsi que d'obtenir les valeurs des pixels et de les enregistrer dans un tableau numpy. Comment puis-je le faire?


Vous voulez 10366 × 7273 = plus de 75 millions de points?
Mike T

@MikeT Je pense que oui, je ne connais pas vraiment de meilleure solution pour aborder le problème que j'essaie de résoudre: je dois trouver la coordonnée de pixels la plus proche de cet ensemble de données à chaque centroïde du bloc américain, puis attribuer le valeur de pixel correspondant à ce bloc.En recherchant autour, j'ai réalisé que la requête cKDTree va m'aider avec la recherche du voisin le plus proche.La fonction Python pour l'algorithme demande un "arbre" pour interroger en tant que tableau numpy.Afin de faire un "arbre" parmi toutes les coordonnées de pixels de cet ensemble de données, je dois les stocker d'une manière ou d'une autre.Si vous avez une meilleure solution, faites-le moi savoir!
irakhman

Réponses:


7

ajouterait comme commentaire, mais un peu long - au cas où vous voudriez utiliser gdal / ogr dans python - quelque chose comme ça pourrait fonctionner (piraté ensemble à partir d'un autre code que j'avais - non testé!) Cela suppose également que plutôt que de trouver le plus proche pixel raster à un polygone centroïde, vous interrogez simplement le raster au xy du centroïde. je n'ai aucune idée de ce que le compromis de vitesse pourrait être ...

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

Cela devrait vous permettre de continuer. Les valeurs raster sont lues à l'aide de rasterio et les coordonnées du centre des pixels sont converties en abscisses / ordonnées en utilisant affine , qui sont ensuite converties en latitude / longitude en utilisant pyproj . La plupart des tableaux ont la même forme que le raster en entrée.

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
Lorsque j'utilise ceci, j'obtiens le message "AttributeError: l'objet 'DatasetReader' n'a pas d'attribut 'affine'" pour la ligne "T0 = r.affine"
mitchus

@mitchus Apparemment, ce affinen'est qu'un alias pour transform, et l'alias a été supprimé de la version la plus récente de rasterio. J'ai édité la réponse, mais il semble qu'elle doive être évaluée par des pairs puisque je suis nouveau ici. :)
Autumnsault

1
Il semble également que les index soient incorrects A.shape, ce qui n'a que deux dimensions.
Autumnsault
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.