Як отримати растрові кутові координати за допомогою прив'язки Python GDAL?


30

Чи є спосіб отримати кутові координати (у градусах lat / long) з растрового файлу, використовуючи прив'язки Python gdal?

Кілька пошукових запитів в Інтернеті переконали мене, що цього немає, тому я розробив роботу, аналізуючи вихід gdalinfo, це дещо принципово, але я подумав, що це може заощадити час людям, які можуть бути менш комфортними з python. Він також працює лише в тому випадку, якщо gdalinfo містить географічні координати разом із кутовими координатами, що, на мою думку, не завжди так.

Ось мій спосіб вирішення, чи хтось має кращі рішення?

gdalinfo на відповідному растрі призводить до чогось подібного на середині виходу:

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)

Цей код буде працювати з файлами, які виглядають таким чином gdalinfo. Я вірю, що іноді координати будуть в градусах і десятків, а не в градусах, хвилинах і секундах; слід було б банально відкоригувати код для цієї ситуації.

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

І це дає мені:

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

Можливо, пов’язане: gis.stackexchange.com/questions/33330/…
AndreJ

Відповіді:


29

Ось ще один спосіб зробити це без виклику зовнішньої програми.

Для цього потрібно отримати координати чотирьох кутів від геотрансформації та відхилити їх у параметр / lat, використовуючи osr.CoordinateTransformation.

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)

Деякий код з metageta проекту, osr.CoordinateTransformation ідея від цієї відповіді


Дивовижне, спасибі І він працює незалежно від того, чи існують відповідні рядки у виході gdalinfo.
EddyTheB

Я думаю, що це буде краще з tgt_srs = src_srs.CloneGeogCS (). Мої початкові растри - це зображення Марса, тому використання EPSG (4326) не є ідеальним, але CloneGeogCS (), здається, просто змінюється від прогнозованих до географічних координат.
EddyTheB

Напевно. Я оновив відповідь, щоб використовувати CloneGeogCS. Однак я просто намагався продемонструвати використання функцій GetExtent і ReprojectCoords. Ви можете використовувати все, що завгодно, як цільові СР.
користувач2856

Так, дякую, я б ніколи не знаходив їх інакше.
EddyTheB

Що робити, якщо у вас є набір даних, який не має проекції і вказує RPC? Не вдалося імпортувати функцію wkt. Можна обчислити ступінь за допомогою трансформатора, але мені було цікаво, чи існує спосіб із вищевказаним методом?
Томас

41

Це можна зробити в набагато менших рядках коду

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, ulyЦе верхній лівий кут, lrx, lryце нижній правий кут

Бібліотека osr (частина gdal) може використовуватися для перетворення точок у будь-яку систему координат. За одну точку:

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)

Щоб перепроеціровать все растрове зображення буде набагато більш складною справою, але GDAL> = 2.0 пропонує просте рішення для цього теж: gdal.Warp.


Це відповідь Pythonic настільки - рівно-пітонічне рішення для перепроектування було б приголомшливим. Це говорило - я використовую результати в PostGIS, тому я просто передаю неперетворений ступінь і ST_Transform(ST_SetSRID(ST_MakeBox2D([результати] ),28355),4283)його. (Один вислів - величина "T" src.GetGeoTransform()має бути використана з великої літери).
GT.

@GT. Доданий приклад
Джеймс

1

Я зробив це так ... це трохи жорстко закодовано, але якщо нічого не зміниться з gdalinfo, воно буде працювати для проектованих 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
Це досить крихко, оскільки воно покладається як gdalinfoна доступність на шляху користувачів (не завжди це стосується, особливо в Windows), так і на аналіз друкованого виводу, який не має строгого інтерфейсу, тобто покладається на ті "магічні числа" для правильного проміжку. Це непотрібно, коли gdal забезпечує всебічні прив'язки пітона, які можуть зробити це більш чітко і надійно
Джеймс,

1

Якщо ваш растр повернутий, то математика стає дещо складнішою, оскільки вам потрібно врахувати кожен із шести афінних коефіцієнтів перетворення. Подумайте про використання афінної для перетворення обертової афінної трансформації / геотрансформи:

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|

Тепер ви можете генерувати чотири кутні координатні пари:

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

І якщо вам також потрібні межі на основі сітки (xmin, ymin, xmax, ymax):

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

0

Я вірю, що в останніх версіях модуля OSGEO / GDAL для python можна безпосередньо викликати утиліти GDAL з коду без залучення системних викликів. наприклад, замість використання підпроцесу для виклику:

gdalinfo можна зателефонувати gdal.Info (ім'я_файла_файла), щоб мати експозицію метаданих / анотації файлу

або замість використання підпроцесу для виклику: gdalwarp можна викликати gdal.Warp, щоб зробити деформацію на растрі.

Перелік утиліт GDAL, які зараз доступні як внутрішня функція: http://erouault.blogspot.com/2015/10/gdal-and-ogr-utilities-as-library.html

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