Uzyskujesz wartość piksela rastra GDAL poniżej punktu OGR bez NumPy?

45

Pracuję nad obliczeniowym modelem liczebności dzikich zapylaczy w krajobrazie. Sam model jest kompletny, a teraz mam problem z etapem przetwarzania końcowego.

Mam raster zapylacza GDAL, który wygląda mniej więcej tak (jaśniejsze kolory oznaczają większą wizytę zapylacza na piksel):

Skala szarości reprezentująca zapylanie zapylacza w krajobrazie

I mam plik kształtu OGR punktów reprezentujących przykładowe lokalizacje w krajobrazie:

wprowadź opis zdjęcia tutaj

Próbuję przeprowadzić analizę pikseli pod tymi punktami, ale aby to zrobić, muszę być w stanie wyodrębnić wartość piksela poniżej punktu.

Czy jest możliwe wyodrębnienie wartości piksela pod punktem przy użyciu tylko OGR i GDAL przez Python? Wolałbym unikać wczytywania całego rastra do pamięci ReadAsArray(), ponieważ moje wyjściowe rastry są bardzo, bardzo duże (zbyt duże, aby zmieściły się w pamięci).

Zauważyłem ten post , który jest podobny, ale wymaga wywołania z wiersza poleceń.

James
źródło
2
Co z ReadAsArray () i tylko czytaniem w punkcie? Więc czytaj tylko jedną komórkę, którą jesteś zainteresowany? Trzeba będzie przekonwertować z współrzędnych punktowych na przestrzeń pikseli i wyodrębnić niezbędną komórkę.
Jay Laura,
1
Spójrz na kod gdalsrsinfo, pokazuje on, jak korzystać z GDALInvertGeoTransform () i przełączać się między przestrzenią geograficzną a przestrzenią pikseli: trac.osgeo.org/gdal/browser/trunk/gdal/apps/gdalsrsinfo.cpp
Jeśli nie masz nic przeciwko korzystaniu z PostGIS, zobacz to . Jest niezwykle szybki i ma tylko 1 linię SQL.
mlt
Będę o tym pamiętać, jeśli napotkam ten problem i będę mieć dostęp do bazy danych PostGIS! Nie zrobiłem tego konkretnego problemu, więc załatwiłem poniższe rozwiązanie GDAL. W każdym razie dzięki!
James
@kyle Nie wiem, czy coś się zmieniło, ale wygląda na to, że GDALInvGeoTransform nie jest odwrócony i to jest przykład .
mlt

Odpowiedzi:

61

Możesz użyć metody gdal.Dataset lub gdal.Band ReadRaster. Zobacz samouczki interfejsu API GDAL i OGR oraz poniższy przykład. ReadRaster nie używa / wymaga numpy, zwracaną wartością są surowe dane binarne i należy je rozpakować przy użyciu standardowego modułu strukturalnego Pythona .

Przykład:

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

Alternatywnie, ponieważ powodem, dla którego podałeś, że nie używasz, numpybyło uniknięcie odczytu całej tablicy podczas używania ReadAsArray(), poniżej znajduje się przykład, który używa numpyi nie czyta całego rastra.

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
użytkownik2856
źródło
Jak zapisać jako plik CSV, tabelę lub inny obiekt? Obiekt o tej samej długości współrzędnych objetct
gonzalez.ivan90
Oto pytanie, Luke. Dzięki! gis.stackexchange.com/questions/269603/…
gonzalez.ivan90
linie, które przypisują px/ pysą niepoprawne w przypadku, gdy mx / my leży poza granicami rb, ponieważ int(-0.5) == 0. Musisz floor(...), a następnie musisz sprawdzić, czy żaden z px/ nie pyjest mniejszy od zera (lub zrób to przed wywołaniem int()), ponieważ indeksy ujemne działają (uzyskują drugą stronę tablicy). Chciałbym wiedzieć, czy istnieje lepszy sposób na rozwiązanie tego problemu. A także, jak przepisać te wiersze, aby poprawnie radziły sobie z obrotami?
naught101