Lấy độ cao ở lat / long từ raster bằng python?


10

Tôi đã tự hỏi nếu có ai có một số kinh nghiệm trong việc lấy dữ liệu độ cao từ raster mà không sử dụng ArcGIS , mà là lấy thông tin như một con trăn listhay dict?

Tôi nhận dữ liệu XY của mình dưới dạng danh sách các bộ dữ liệu:

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

Tôi muốn lặp qua danh sách hoặc chuyển nó đến một hàm hoặc phương thức lớp để có được độ cao tương ứng cho các cặp xy.

Tôi đã thực hiện một số nghiên cứu về chủ đề này và API gdal nghe có vẻ đầy hứa hẹn. Bất cứ ai có thể tư vấn cho tôi làm thế nào để đi về mọi thứ, cạm bẫy, mã mẫu?


GDAL không phải là một tùy chọn vì tôi không thể chỉnh sửa biến đường dẫn hệ thống trên máy tôi đang làm việc!

Có ai biết về một cách tiếp cận khác nhau?


2
thật không may, bạn thực sự cần phải chạy GDAL trên hệ thống của mình để làm bất cứ điều gì với raster trong Python. Với "không thể chỉnh sửa biến đường dẫn hệ thống trên máy", bạn có đang tham khảo các hướng dẫn này không? Tôi thấy phương pháp cài đặt này rất kém và tôi không sử dụng nó cũng như không khuyên dùng. Nếu bạn đang sử dụng Windows, hãy cài đặt GDAL / Python theo cách đơn giản .
Mike T

Vâng, tôi đã thực sự. Tôi không làm việc ngay bây giờ nhưng tôi sẽ kiểm tra liên kết bạn đã đăng. Trông đầy hứa hẹn! Cảm ơn vì đã trở lại câu hỏi của tôi!
LarsVegas

Tôi đã sử dụng trình cài đặt của Christoph Gohlke (được liên kết ở trên) trên nhiều máy tính làm việc và nó thực sự đơn giản. Bạn chỉ cần đảm bảo rằng bạn phù hợp với phiên bản Python và Windows 32 hoặc 64 bit. Trong khi bạn đang ở đó, bạn cũng nên lấy NumPy từ cùng một nơi, vì điều đó là cần thiết bởi GDAL, như thể hiện trong các câu trả lời dưới đây.
Mike T

Câu trả lời:


15

Đây là một cách sử dụng GDAL có lập trình hơn câu trả lời của @ Aragon. Tôi đã không kiểm tra nó, nhưng nó chủ yếu là mã nồi hơi đã hoạt động cho tôi trong quá khứ. Nó dựa vào các ràng buộc của Numpy và GDAL, nhưng đó là về nó.

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
xem chỉnh sửa câu hỏi của tôi ... cảm ơn vì đã đăng! Tôi ủng hộ nó.
LarsVegas

1
Ôi chết tiệt! Ít nhất nó ở đây cho hậu thế. TBH, toán học trong mapToPixel()pixelToMap()là bit quan trọng, miễn là bạn có thể tạo ra một mảng gọn gàng (hoặc một Python thông thường, nhưng chúng thường không hiệu quả đối với loại điều này) và có được hộp giới hạn địa lý của mảng.
MerseyViking

1
+1 cho nhận xét (và mã) về việc đảo ngược các tham số sang mảng numpy. Tôi đã tìm kiếm khắp nơi để tìm lỗi trong mã của mình và trao đổi này đã sửa nó!
aldo 19/2/2015

1
Sau đó, tôi đề nghị ma trận của bạn ( gttrong ví dụ) là sai. Một ma trận affine như được sử dụng trong CGAL (xem: gdal.org/gdal_datamodel.html ) thường không thể đảo ngược (nếu không, bạn có một số giá trị tỷ lệ thú vị đang diễn ra). Vì vậy, nơi chúng tôi có, g = p.Achúng tôi cũng có thể làm p = g.A^-1Numpy.linalg là một chút nặng nề cho mục đích của chúng tôi - chúng tôi có thể giảm mọi thứ xuống hai phương trình đơn giản.
MerseyViking

1
Tôi đã chỉnh sửa lại mã để sử dụng đại số đơn giản thay vì linalg lumpg. Nếu toán sai, hãy sửa trang Wikipedia.
MerseyViking

3

Kiểm tra câu trả lời của tôi ở đây ... và đọc ở đây để biết một số thông tin. Thông tin sau được lấy từ Geotips:

Với gdallocationinfo , chúng ta có thể truy vấn độ cao tại một điểm:

$ gdallocationinfo gmted/all075.vrt -geoloc 87360 19679

Đầu ra của lệnh trên có dạng:

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

Điều này có nghĩa là giá trị độ cao tại vị trí địa lý được cung cấp là 1418.


Chỉ cần phát hiện ra tôi không thể sử dụng GDAL vì tôi không thể chỉnh sửa biến hệ thống của mình trên máy tôi đang làm việc. Cảm ơn cho đầu vào mặc dù.
LarsVegas

0

Xem ví dụ: mã này dựa trên GDAL (và Python, không cần numpy): https://github.com/geometalab/retrieve-height-service


Thật không may là mã dường như không được cấp phép nguồn mở.
Ben Crowell

Bây giờ nó có :-).
Stefan

-1

Mã python được cung cấp trích xuất dữ liệu giá trị của một ô raster dựa trên các chuỗi x, y đã cho. Đây là một phiên bản hơi thay đổi của một ví dụ từ nguồn tuyệt vời này . Nó dựa trên GDALnumpykhông phải là một phần của phân phối python tiêu chuẩn. Cảm ơn @Mike Toews đã chỉ ra các Binaries Windows không chính thức cho Gói mở rộng Python để giúp cài đặt và sử dụng nhanh chóng và dễ dàng.

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

Có vẻ như đây chỉ là một phiên bản ít chung chung, kém linh hoạt hơn những gì MerseyViking cung cấp ở trên?
WileyB
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.