รับระดับความสูงที่ lat / long จากแรสเตอร์ด้วย python หรือไม่


10

ฉันสงสัยว่าใครมีประสบการณ์ในการรับข้อมูลระดับความสูงจากแรสเตอร์โดยไม่ต้องใช้ ArcGISแต่ควรรับข้อมูลเป็นงูหลามlistหรือdict?

ฉันได้รับข้อมูล XY ของฉันเป็นรายการสิ่งอันดับ:

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

ฉันต้องการวนรอบรายการหรือส่งผ่านไปยังฟังก์ชันหรือคลาสวิธีเพื่อให้ได้ระดับความสูงที่สอดคล้องกันสำหรับคู่ xy

ฉันทำการค้นคว้าบางอย่างเกี่ยวกับหัวข้อและgdal API ฟังดูมีแนวโน้ม ใครสามารถแนะนำฉันเกี่ยวกับสิ่งต่าง ๆ ข้อผิดพลาดโค้ดตัวอย่างได้หรือไม่?


GDAL ไม่ใช่ตัวเลือกเนื่องจากฉันไม่สามารถแก้ไขตัวแปรพา ธ ของระบบในเครื่องที่ฉันกำลังทำงานอยู่!

ไม่มีใครรู้เกี่ยวกับวิธีการที่แตกต่างกันอย่างไร


2
น่าเสียดายที่คุณต้องทำให้ GDAL ทำงานบนระบบของคุณเพื่อทำทุกอย่างด้วยแรสเตอร์ใน Python ด้วย "ไม่สามารถแก้ไขตัวแปรพา ธ ของระบบบนเครื่อง" คุณหมายถึงคำแนะนำเหล่านี้หรือไม่ ฉันพบว่าวิธีการติดตั้งนี้แย่มากและฉันไม่ได้ใช้หรือไม่แนะนำ หากคุณกำลังใช้ Windows ติดตั้ง GDAL / หลามวิธีที่ง่าย
Mike T

ใช่ฉันเป็นจริง ฉันไม่ได้ทำงานตอนนี้ แต่ฉันจะตรวจสอบลิงก์ที่คุณโพสต์ ดูมีแนวโน้ม! ขอบคุณที่กลับมาที่คำถามของฉัน!
LarsVegas

ฉันใช้โปรแกรมติดตั้งโดย Christoph Gohlke (ลิงก์ด้านบน) บนคอมพิวเตอร์ที่ใช้งานจำนวนมากและมันง่ายมาก คุณจะต้องตรวจสอบให้แน่ใจว่าคุณตรงกับเวอร์ชันของ Python และ Windows 32- หรือ 64- บิต ในขณะที่คุณอยู่ที่นี่คุณควรได้รับ NumPy จากที่เดียวกันเนื่องจาก GDAL นั้นเป็นที่ต้องการดังที่แสดงในคำตอบด้านล่าง
Mike T

คำตอบ:


15

นี่เป็นวิธีการเขียนโปรแกรมที่ใช้ GDAL มากกว่าคำตอบของ @ Aragon ฉันไม่ได้ทำการทดสอบ แต่ส่วนใหญ่เป็นรหัสหม้อไอน้ำที่เคยทำงานให้ฉันในอดีต มันขึ้นอยู่กับการเชื่อมโยงของ 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()เป็นบิตที่สำคัญตราบใดที่คุณสามารถสร้างอาร์เรย์ numpy (หรือหนึ่ง Python ปกติ แต่โดยทั่วไปพวกเขาไม่ได้มีประสิทธิภาพสำหรับสิ่งนี้เรียงลำดับ) และได้รับกล่องขอบเขตทางภูมิศาสตร์ของอาร์เรย์
MerseyViking

1
+1 สำหรับความคิดเห็น (และรหัส) เกี่ยวกับการย้อนกลับพารามิเตอร์ไปยังอาร์เรย์ numpy ฉันค้นหาข้อผิดพลาดในรหัสของฉันทุกที่และการสลับนี้แก้ไขได้!
aldo

1
ถ้าอย่างนั้นฉันขอแนะนำเมทริกซ์ของคุณ ( gtในตัวอย่าง) ว่าผิด เมทริกเลียนแบบตามที่ใช้ใน CGAL (ดู: gdal.org/gdal_datamodel.html ) โดยทั่วไปจะไม่สามารถย้อนกลับได้ ดังนั้นที่เรามีg = p.Aเราสามารถทำp = g.A^-1Numpy.linalg เป็นบิตเฮฟวี่เวทสำหรับวัตถุประสงค์ของเรา - เราสามารถลดทุกอย่างเป็นสองสมการง่ายๆ
MerseyViking

1
ฉันได้แก้ไขโค้ดอีกครั้งเพื่อใช้พีชคณิตแบบง่าย ๆ แทนที่จะเป็น linalg แบบนัมพี หากคณิตศาสตร์ผิดให้แก้ไขหน้า Wikipedia
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


มันน่าเสียดายที่รหัสดูเหมือนว่าจะไม่ได้รับอนุญาตให้เปิดแหล่งที่มา
Ben Crowell

ตอนนี้มันมี :-)
Stefan

-1

รหัสหลามที่ให้มาจะดึงข้อมูลค่าของเซลล์แรสเตอร์ตาม 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.