Làm thế nào để có được tọa độ góc raster bằng các ràng buộc Python GDAL?


30

Có cách nào để lấy tọa độ góc (tính bằng độ lat / dài) từ tệp raster bằng các ràng buộc Python của gdal không?

Một vài tìm kiếm trực tuyến đã thuyết phục tôi rằng không có, vì vậy tôi đã phát triển một công việc xung quanh bằng cách phân tích đầu ra gdalinfo, nó hơi cơ bản nhưng tôi nghĩ nó có thể tiết kiệm thời gian cho những người có thể không thoải mái với python. Nó cũng chỉ hoạt động nếu gdalinfo chứa tọa độ địa lý cùng với tọa độ góc, điều mà tôi không tin là luôn luôn như vậy.

Đây là cách giải quyết của tôi, có ai có giải pháp nào tốt hơn không?

gdalinfo trên một raster thích hợp dẫn đến kết quả như thế này giữa chừng thông qua đầu ra:

Corner Coordinates:
Upper Left  (  -18449.521, -256913.934) (137d 7'21.93"E,  4d20'3.46"S)
Lower Left  (  -18449.521, -345509.683) (137d 7'19.32"E,  5d49'44.25"S)
Upper Right (   18407.241, -256913.934) (137d44'46.82"E,  4d20'3.46"S)
Lower Right (   18407.241, -345509.683) (137d44'49.42"E,  5d49'44.25"S)
Center      (     -21.140, -301211.809) (137d26'4.37"E,  5d 4'53.85"S)

Mã này sẽ hoạt động trên các tệp mà gdalinfo trông giống như vậy. Tôi tin rằng đôi khi tọa độ sẽ được tính theo độ và số thập phân, thay vì độ, phút và giây; nó nên là tầm thường để điều chỉnh mã cho tình huống đó.

import numpy as np
import subprocess

def GetCornerCoordinates(FileName):
    GdalInfo = subprocess.check_output('gdalinfo {}'.format(FileName), shell=True)
    GdalInfo = GdalInfo.split('/n') # Creates a line by line list.
    CornerLats, CornerLons = np.zeros(5), np.zeros(5)
    GotUL, GotUR, GotLL, GotLR, GotC = False, False, False, False, False
    for line in GdalInfo:
        if line[:10] == 'Upper Left':
            CornerLats[0], CornerLons[0] = GetLatLon(line)
            GotUL = True
        if line[:10] == 'Lower Left':
            CornerLats[1], CornerLons[1] = GetLatLon(line)
            GotLL = True
        if line[:11] == 'Upper Right':
            CornerLats[2], CornerLons[2] = GetLatLon(line)
            GotUR = True
        if line[:11] == 'Lower Right':
            CornerLats[3], CornerLons[3] = GetLatLon(line)
            GotLR = True
        if line[:6] == 'Center':
            CornerLats[4], CornerLons[4] = GetLatLon(line)
            GotC = True
        if GotUL and GotUR and GotLL and GotLR and GotC:
            break
    return CornerLats, CornerLons 

def GetLatLon(line):
    coords = line.split(') (')[1]
    coords = coords[:-1]
    LonStr, LatStr = coords.split(',')
    # Longitude
    LonStr = LonStr.split('d')    # Get the degrees, and the rest
    LonD = int(LonStr[0])
    LonStr = LonStr[1].split('\'')# Get the arc-m, and the rest
    LonM = int(LonStr[0])
    LonStr = LonStr[1].split('"') # Get the arc-s, and the rest
    LonS = float(LonStr[0])
    Lon = LonD + LonM/60. + LonS/3600.
    if LonStr[1] in ['W', 'w']:
        Lon = -1*Lon
    # Same for Latitude
    LatStr = LatStr.split('d')
    LatD = int(LatStr[0])
    LatStr = LatStr[1].split('\'')
    LatM = int(LatStr[0])
    LatStr = LatStr[1].split('"')
    LatS = float(LatStr[0])
    Lat = LatD + LatM/60. + LatS/3600.
    if LatStr[1] in ['S', 's']:
        Lat = -1*Lat
    return Lat, Lon

FileName = Image.cub
# Mine's an ISIS3 cube file.
CornerLats, CornerLons = GetCornerCoordinates(FileName)
# UpperLeft, LowerLeft, UpperRight, LowerRight, Centre
print CornerLats
print CornerLons

Và điều đó mang lại cho tôi:

[-4.33429444 -5.82895833 -4.33429444 -5.82895833 -5.081625  ] 
[ 137.12275833  137.12203333  137.74633889  137.74706111  137.43454722]

Câu trả lời:


29

Đây là một cách khác để làm điều đó mà không cần gọi một chương trình bên ngoài.

Những gì nó làm là lấy tọa độ của bốn góc từ geotransform và chuyển hướng chúng thành lon / lat bằng osr.CoordineTransifying.

from osgeo import gdal,ogr,osr

def GetExtent(gt,cols,rows):
    ''' Return list of corner coordinates from a geotransform

        @type gt:   C{tuple/list}
        @param gt: geotransform
        @type cols:   C{int}
        @param cols: number of columns in the dataset
        @type rows:   C{int}
        @param rows: number of rows in the dataset
        @rtype:    C{[float,...,float]}
        @return:   coordinates of each corner
    '''
    ext=[]
    xarr=[0,cols]
    yarr=[0,rows]

    for px in xarr:
        for py in yarr:
            x=gt[0]+(px*gt[1])+(py*gt[2])
            y=gt[3]+(px*gt[4])+(py*gt[5])
            ext.append([x,y])
            print x,y
        yarr.reverse()
    return ext

def ReprojectCoords(coords,src_srs,tgt_srs):
    ''' Reproject a list of x,y coordinates.

        @type geom:     C{tuple/list}
        @param geom:    List of [[x,y],...[x,y]] coordinates
        @type src_srs:  C{osr.SpatialReference}
        @param src_srs: OSR SpatialReference object
        @type tgt_srs:  C{osr.SpatialReference}
        @param tgt_srs: OSR SpatialReference object
        @rtype:         C{tuple/list}
        @return:        List of transformed [[x,y],...[x,y]] coordinates
    '''
    trans_coords=[]
    transform = osr.CoordinateTransformation( src_srs, tgt_srs)
    for x,y in coords:
        x,y,z = transform.TransformPoint(x,y)
        trans_coords.append([x,y])
    return trans_coords

raster=r'somerasterfile.tif'
ds=gdal.Open(raster)

gt=ds.GetGeoTransform()
cols = ds.RasterXSize
rows = ds.RasterYSize
ext=GetExtent(gt,cols,rows)

src_srs=osr.SpatialReference()
src_srs.ImportFromWkt(ds.GetProjection())
#tgt_srs=osr.SpatialReference()
#tgt_srs.ImportFromEPSG(4326)
tgt_srs = src_srs.CloneGeogCS()

geo_ext=ReprojectCoords(ext,src_srs,tgt_srs)

Một số mã từ metageta dự án, osr.CoordinateTransformation ý tưởng từ câu trả lời này


Thật sự cảm ơn. Và nó hoạt động bất kể các dòng thích hợp có tồn tại trong đầu ra gdalinfo hay không.
EddyTheB

Tôi nghĩ rằng điều này sẽ tốt hơn với tgt_srs = src_srs.CloneGeogCS (). Trình quét ban đầu của tôi là hình ảnh của Sao Hỏa, vì vậy sử dụng EPSG (4326) không lý tưởng, nhưng CloneGeogCS () dường như chỉ thay đổi từ dự kiến ​​sang tọa độ địa lý.
EddyTheB

Chắc chắn. Tôi đã cập nhật câu trả lời để sử dụng CloneGeogCS. Tuy nhiên, tôi chỉ cố gắng chứng minh việc sử dụng các hàm GetExtent và ReprojectCoords. Bạn có thể sử dụng bất cứ thứ gì bạn muốn làm srs mục tiêu.
dùng2856

Vâng, cảm ơn bạn, tôi chưa bao giờ tìm thấy những thứ khác.
EddyTheB

Điều gì xảy ra nếu bạn có một tập dữ liệu không có phép chiếu và chỉ định RPC? Việc nhập từ chức năng wkt không thành công. Có thể tính toán mức độ sử dụng máy biến áp nhưng tôi đã tự hỏi liệu có cách nào với phương pháp trên không?
Thomas

41

Điều này có thể được thực hiện trong các dòng mã ít hơn nhiều

src = gdal.Open(path goes here)
ulx, xres, xskew, uly, yskew, yres  = src.GetGeoTransform()
lrx = ulx + (src.RasterXSize * xres)
lry = uly + (src.RasterYSize * yres)

ulx, ulylà góc trên bên trái lrx, lrylà góc dưới bên phải

Thư viện osr (một phần của gdal) có thể được sử dụng để biến đổi các điểm thành bất kỳ hệ tọa độ nào. Đối với một điểm duy nhất:

from osgeo import ogr
from osgeo import osr

# Setup the source projection - you can also import from epsg, proj4...
source = osr.SpatialReference()
source.ImportFromWkt(src.GetProjection())

# The target projection
target = osr.SpatialReference()
target.ImportFromEPSG(4326)

# Create the transform - this can be used repeatedly
transform = osr.CoordinateTransformation(source, target)

# Transform the point. You can also create an ogr geometry and use the more generic `point.Transform()`
transform.TransformPoint(ulx, uly)

Để chỉnh sửa lại toàn bộ hình ảnh raster sẽ là một vấn đề phức tạp hơn nhiều, nhưng GDAL> = 2.0 cũng cung cấp một giải pháp dễ dàng cho việc này : gdal.Warp.


Đây là câu trả lời của Pythonic về mức độ - một giải pháp Pythonic tương đương cho sự từ chối sẽ rất tuyệt vời, Điều đó nói rằng - Tôi sử dụng kết quả trong PostGIS, vì vậy tôi chỉ vượt qua mức độ không biến đổi và ST_Transform(ST_SetSRID(ST_MakeBox2D([kết quả] ),28355),4283). (Một ngụy biện - chữ 'T' src.GetGeoTransform()nên được viết hoa).
GT.

@GT. Đã thêm một ví dụ
James

1

Tôi đã thực hiện theo cách này ... nó hơi khó mã hóa nhưng nếu không có gì thay đổi với gdalinfo, nó sẽ hoạt động cho các hình ảnh chiếu UTM!

imagefile= /pathto/image
p= subprocess.Popen(["gdalinfo", "%s"%imagefile], stdout=subprocess.PIPE)
out,err= p.communicate()
ul= out[out.find("Upper Left")+15:out.find("Upper Left")+38]
lr= out[out.find("Lower Right")+15:out.find("Lower Right")+38]

2
Điều này khá mong manh vì nó phụ thuộc vào cả hai gdalinfokhả dụng trên đường dẫn của người dùng (không phải luôn luôn như vậy, đặc biệt là trên các cửa sổ) và phân tích một đầu ra được in không có giao diện nghiêm ngặt - tức là dựa vào các 'số ma thuật' đó để có khoảng cách chính xác. Không cần thiết khi gdal cung cấp các ràng buộc trăn toàn diện có thể thực hiện việc này một cách rõ ràng và mạnh mẽ hơn
James

1

Nếu raster của bạn được quay, thì toán học sẽ phức tạp hơn một chút, vì bạn cần xem xét từng hệ số biến đổi affine trong sáu hệ số. Xem xét sử dụng affine để chuyển đổi biến đổi affine / geotransform xoay:

from affine import Affine

# E.g., from a GDAL DataSet object:
# gt = ds.GetGeoTransform()
# ncol = ds.RasterXSize
# nrow = ds.RasterYSize

# or to work with a minimal example
gt = (100.0, 17.320508075688775, 5.0, 200.0, 10.0, -8.660254037844387)
ncol = 10
nrow = 15

transform = Affine.from_gdal(*gt)
print(transform)
# | 17.32, 5.00, 100.00|
# | 10.00,-8.66, 200.00|
# | 0.00, 0.00, 1.00|

Bây giờ bạn có thể tạo bốn cặp tọa độ góc:

c0x, c0y = transform.c, transform.f  # upper left
c1x, c1y = transform * (0, nrow)     # lower left
c2x, c2y = transform * (ncol, nrow)  # lower right
c3x, c3y = transform * (ncol, 0)     # upper right

Và nếu bạn cũng cần các giới hạn dựa trên lưới (xmin, ymin, xmax, ymax):

xs = (c0x, c1x, c2x, c3x)
ys = (c0y, c1y, c2y, c3y)
bounds = min(xs), min(ys), max(xs), max(ys)

0

Tôi tin vào các phiên bản gần đây hơn của mô-đun OSGEO / GDAL cho python, người ta có thể gọi trực tiếp các tiện ích GDAL từ mã mà không liên quan đến các cuộc gọi hệ thống. ví dụ thay vì sử dụng quy trình con để gọi:

gdalinfo người ta có thể gọi gdal.Info (the_name_of_the_file) để hiển thị siêu dữ liệu / chú thích của tệp

hoặc thay vì sử dụng quy trình con để gọi: gdalwarp người ta có thể cal gdal.Warp để thực hiện cong vênh trên một raster.

Danh sách các tiện ích GDAL hiện có sẵn dưới dạng hàm nội bộ: http://erouault.blogspot.com/2015/10/gdal-and-ogr-utilities-as-l Library.html

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.