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.