Python GDAL 바인딩을 사용하여 래스터 코너 좌표를 얻는 방법은 무엇입니까?


30

gdal의 Python 바인딩을 사용하여 래스터 파일에서 모서리 좌표 (위도 / 경도)를 얻는 방법이 있습니까?

온라인에서 몇 번의 검색 결과에 따르면 gdalinfo 출력을 구문 분석하여 해결 방법을 개발했지만 다소 기본적이지만 파이썬에 익숙하지 않은 사람들에게는 시간을 절약 할 수 있다고 생각했습니다. 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]

답변:


29

외부 프로그램을 호출하지 않고 다른 방법으로 수행 할 수 있습니다.

이 작업은 지오 변환에서 4 개의 모서리 좌표를 가져오고 osr.CoordinateTransformation을 사용하여 lon / lat으로 다시 투영합니다.

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. 이 답변의 좌표 변환 아이디어


정말 고마워 그리고 gdalinfo 출력에 적절한 줄이 있는지 여부에 관계없이 작동합니다.
— EddyTheB

나는 이것이 tgt_srs = src_srs.CloneGeogCS ()로 더 좋을 것이라고 생각합니다. 초기 래스터는 화성의 이미지이므로 EPSG (4326)를 사용하는 것이 이상적이지는 않지만 CloneGeogCS ()는 투영 된 좌표에서 지리적 좌표로 변경되는 것으로 보입니다.
— EddyTheB

확실 해요 CloneGeogCS를 사용하도록 답변을 업데이트했습니다. 그러나 GetExtent 및 ReprojectCoords 함수의 사용법을 보여 주려고했습니다. 원하는 대상을 대상 SRS로 사용할 수 있습니다.
— user2856

네, 고마워요. 다른 사람들을 찾지 못했습니다.
— 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 솔루션이 굉장히 훌륭하다는 Pythonic 답변입니다. 즉, PostGIS에서 결과를 사용하므로 변환되지 않은 범위와 ST_Transform(ST_SetSRID(ST_MakeBox2D(결과를 전달 ),28355),4283)합니다. (한 번의 퀴즈- 'T'는 src.GetGeoTransform()대문자 여야합니다.)
— GT.

@GT. 예를 추가했습니다
— James

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사용자의 경로 (항상 경우, 특히 창에서는 아님)에서 사용할 수 있고 엄격한 인터페이스가없는 인쇄 된 출력을 구문 분석하기 때문에 (예 : 정확한 간격을 위해 '매직 숫자'에 의존하기 때문에) 이는 매우 취약 합니다. gdal이보다 명확하고 강력한 방식으로이를 수행 할 수있는 포괄적 인 파이썬 바인딩을 제공 할 때는 불필요합니다.
— James

1

래스터가 회전하면 6 가지 아핀 변환 계수 각각을 고려해야하기 때문에 수학이 조금 더 복잡해집니다. 회전 된 아핀 변환 / 지오 변환을 변환하기 위해 affine 을 사용하는 것을 고려하십시오 .

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 모듈은 시스템 호출없이 코드에서 GDAL 유틸리티를 직접 호출 할 수 있다고 생각합니다. 예를 들어 하위 프로세스를 사용하여 호출하는 대신 :

gdalinfo 하나는 gdal.Info (the_name_of_the_file)를 호출하여 파일 메타 데이터 / 주석을 노출시킬 수 있습니다.

또는 하위 프로세스를 사용하여 호출하는 대신 : gdalwarp 하나는 gdal.Warp를 호출하여 래스터에 뒤틀림을 수행 할 수 있습니다.

현재 내부 기능으로 사용 가능한 GDAL 유틸리티 목록 : http://erouault.blogspot.com/2015/10/gdal-and-ogr-utilities-as-library.html

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.