Отримання висоти на лат / довгому від растру за допомогою python?


10

Мені було цікаво, чи має хтось досвід отримання даних про висоту з растру без використання ArcGIS , а скоріше отримати інформацію як пітон listабо dict?

Я отримую свої дані XY у списку кортежів:

xy34 =[perp_obj[j].CalcPnts(float(i.dist), orientation) for j in range (len(perp_obj))]

Я хотів би проглянути список або передати його функції або класу-методу, щоб отримати відповідне підвищення для пар xy.

Я провів кілька досліджень на цю тему, і API gdal звучить багатообіцяюче. Хтось може порадити мені, як іти про речі, підводні камені, зразок коду?


GDAL - це не варіант, оскільки я не можу редагувати змінну системного шляху на машині, над якою працюю!

Хтось знає про інший підхід?


2
на жаль, вам дійсно потрібно запустити GDAL у вашій системі, щоб зробити що-небудь з растром на Python. Якщо ви "не можете редагувати змінну системного шляху на машині", ви посилаєтесь на ці вказівки ? Я вважаю цей спосіб установки дуже поганим, і я не використовую його і не рекомендую. Якщо ви використовуєте Windows, встановіть GDAL / Python простим способом .
Майк Т

Так, я справді був. Я зараз не на роботі, але перевірю посилання, яке ви опублікували. Виглядає перспективно! Дякуємо, що повернулися до мого питання!
LarsVegas

Я використовував інсталятор Christoph Gohlke (зв'язаний вище) на багатьох робочих комп'ютерах, і це дуже просто. Вам потрібно лише забезпечити відповідність версії Python та 32- або 64-розрядної Windows. Поки ви перебуваєте на цьому, ви також повинні отримати NumPy з того самого місця, оскільки це потрібно GDAL, як показано у відповідях нижче.
Майк Т

Відповіді:


15

Ось більш програмний спосіб використання GDAL, ніж відповідь @ Арагона. Я цього не перевіряв, але в основному це був код котла, який працював на мене раніше. Він покладається на Numpy та GDAL прив'язки, але це саме про це.

import osgeo.gdal as gdal
import osgeo.osr as osr
import numpy as np
from numpy import ma

def maFromGDAL(filename):
    dataset = gdal.Open(filename, gdal.GA_ReadOnly)

    if dataset is None:
        raise Exception()

    # Get the georeferencing metadata.
    # We don't need to know the CRS unless we want to specify coordinates
    # in a different CRS.
    #projection = dataset.GetProjection()
    geotransform = dataset.GetGeoTransform()

    # We need to know the geographic bounds and resolution of our dataset.
    if geotransform is None:
        dataset = None
        raise Exception()

    # Get the first band.
    band = dataset.GetRasterBand(1)
    # We need to nodata value for our MaskedArray later.
    nodata = band.GetNoDataValue()
    # Load the entire dataset into one numpy array.
    image = band.ReadAsArray(0, 0, band.XSize, band.YSize)
    # Close the dataset.
    dataset = None

    # Create a numpy MaskedArray from our regular numpy array.
    # If we want to be really clever, we could subclass MaskedArray to hold
    # our georeference metadata as well.
    # see here: http://docs.scipy.org/doc/numpy/user/basics.subclassing.html
    # For details.
    masked_image = ma.masked_values(image, nodata, copy=False)
    masked_image.fill_value = nodata

    return masked_image, geotransform

def pixelToMap(gt, pos):
    return (gt[0] + pos[0] * gt[1] + pos[1] * gt[2],
            gt[3] + pos[0] * gt[4] + pos[1] * gt[5])

# Reverses the operation of pixelToMap(), according to:
# https://en.wikipedia.org/wiki/World_file because GDAL's Affine GeoTransform
# uses the same values in the same order as an ESRI world file.
# See: http://www.gdal.org/gdal_datamodel.html
def mapToPixel(gt, pos):
    s = gt[0] * gt[4] - gt[3] * gt[1]
    x = (gt[4] * pos[0] - gt[1] * pos[1] + gt[1] * gt[5] - gt[4] * gt[2]) / s
    y = (-gt[3] * pos[0] + gt[0] * pos[1] + gt[3] * gt[2] - gt[0] * gt[5]) / s
    return (x, y)

def valueAtMapPos(image, gt, pos):
    pp = mapToPixel(gt, pos)
    x = int(pp[0])
    y = int(pp[1])

    if x < 0 or y < 0 or x >= image.shape[1] or y >= image.shape[0]:
        raise Exception()

    # Note how we reference the y column first. This is the way numpy arrays
    # work by default. But GDAL assumes x first.
    return image[y, x]

try:
    image, geotransform = maFromGDAL('myimage.tif')
    val = valueAtMapPos(image, geotransform, (434323.0, 2984745.0))
    print val
except:
    print('Something went wrong.')

1
дивіться правки до мого питання ... дякую за публікацію все одно! Я це схвалив.
LarsVegas

1
Ах чорт! Ну принаймні це тут для нащадків. TBH, математика в mapToPixel()і pixelToMap()є важливим бітом, якщо ви можете створити масивний масив (або звичайний Python, але вони, як правило, не настільки ефективні для подібних речей), і отримати географічне обмежувальне поле масиву.
MerseyViking

1
+1 для коментаря (та коду) про повернення параметрів до масивного масиву. Я всюди шукав помилку в своєму коді, і цей своп виправив це!
альдо

1
Тоді я припускаю, що ваша матриця ( gtу прикладі) неправильна. Афінна матриця, що використовується в CGAL (див.: Gdal.org/gdal_datamodel.html ), як правило, незворотна (інакше у вас з'являються деякі фанкові значення масштабування). Тож, де ми маємо, g = p.Aми також можемо зробити p = g.A^-1Numpy.linalg трохи важким для наших цілей - ми можемо звести все до двох простих рівнянь.
MerseyViking

1
Я змінив код, щоб використовувати просту алгебру, а не нумерований бік. Якщо математика неправильна, виправте сторінку Вікіпедії.
MerseyViking

3

Ознайомтесь з моєю відповіддю тут ... і прочитайте тут інформацію для отримання інформації. Наступна інформація була взята з Geotips:

За допомогою gdallocationinfo ми можемо запитати висоту в точці:

$ gdallocationinfo gmted/all075.vrt -geoloc 87360 19679

Вихід з вищевказаної команди має вигляд:

Report:
   Location: (87360P,19679L)
Band 1:
   Value: 1418

Це означає, що величина висоти при наданій геолокації становить 1418.


Щойно з’ясував, що я не можу використовувати GDAL, оскільки я не в змозі редагувати свою системну змінну на машині, над якою працюю. Дякую за вклад, хоча.
LarsVegas

0

Дивіться, наприклад, цей код, який базується на GDAL (і Python, нумеру не потрібно): https://github.com/geometalab/retrieve-height-service


Прикро, що, схоже, код не має ліцензії на відкритий код.
Бен Кроуелл

Тепер він має :-).
Стефан

-1

Наведений код python витягує дані про значення растрової комірки на основі заданих x, y-координат. Це дещо змінена версія прикладу цього чудового джерела . Він заснований GDALі numpyне є частиною стандартного розподілу пітона. Завдяки @Mike Toews за те, що він вказав на неофіційні бінарні файли Windows для розширення Python, щоб встановити та використовувати швидко та просто.

import os, sys, time, gdal
from gdalconst import *


# coordinates to get pixel values for
xValues = [122588.008]
yValues = [484475.146]

# set directory
os.chdir(r'D:\\temp\\AHN2_060')

# register all of the drivers
gdal.AllRegister()
# open the image
ds = gdal.Open('i25gn1_131.img', GA_ReadOnly)

if ds is None:
    print 'Could not open image'
    sys.exit(1)

# get image size
rows = ds.RasterYSize
cols = ds.RasterXSize
bands = ds.RasterCount

# get georeference info
transform = ds.GetGeoTransform()
xOrigin = transform[0]
yOrigin = transform[3]
pixelWidth = transform[1]
pixelHeight = transform[5]

# loop through the coordinates
for xValue,yValue in zip(xValues,yValues):
    # get x,y
    x = xValue
    y = yValue

    # compute pixel offset
    xOffset = int((x - xOrigin) / pixelWidth)
    yOffset = int((y - yOrigin) / pixelHeight)
    # create a string to print out
    s = "%s %s %s %s " % (x, y, xOffset, yOffset)

    # loop through the bands
    for i in xrange(1,bands):
        band = ds.GetRasterBand(i) # 1-based index
        # read data and add the value to the string
        data = band.ReadAsArray(xOffset, yOffset, 1, 1)
        value = data[0,0]
        s = "%s%s " % (s, value) 
    # print out the data string
    print s
    # figure out how long the script took to run

Здається, це лише менш загальна, менш гнучка версія того, що MerseyViking пропонував вище?
WileyB
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.