วิธีรับพิกัดมุมแรสเตอร์โดยใช้การรวม Python GDAL?


30

มีวิธีการรับพิกัดมุม (เป็นองศา lat / ยาว) จากไฟล์แรสเตอร์โดยใช้การผูก Python ของ gdal หรือไม่?

การค้นหาออนไลน์ไม่กี่ทำให้ฉันมั่นใจว่าไม่มีดังนั้นฉันได้พัฒนาแก้ไขโดยการแยกวิเคราะห์ผลลัพธ์ 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]

อาจเกี่ยวข้อง: 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 คุณสามารถใช้อะไรก็ได้ที่คุณต้องการเป็นเป้าหมาย srs
2856

ใช่ขอบคุณฉันไม่เคยพบที่อื่น
EddyTheB

ถ้าคุณมีชุดข้อมูลที่ไม่มีการฉายภาพและระบุ RPCs การนำเข้าจากฟังก์ชั่น 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)

เพื่อ reproject ภาพแรสเตอร์ทั้งหมดจะเป็นเรื่องไกลความซับซ้อนมากขึ้น แต่ 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มีอยู่ในเส้นทางของผู้ใช้ (ไม่ใช่ทุกกรณีโดยเฉพาะอย่างยิ่งใน windows) และแยกวิเคราะห์ผลงานพิมพ์ที่ไม่มีส่วนติดต่อที่เข้มงวด - นั่นคือการพึ่งพาอาศัยของพวกเวทมนตร์หมายเลขสำหรับระยะห่างที่ถูกต้อง มันไม่จำเป็นเมื่อ gdal จัดให้มีการผูก python ที่ครอบคลุมซึ่งสามารถทำได้ในลักษณะที่ชัดเจนและมีประสิทธิภาพมากขึ้น
James

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 (the_name_of_the_file) เพื่อให้ได้สัมผัสของเมตาดาต้าไฟล์ / บันทึกย่อ

หรือแทนที่จะใช้หน่วยประมวลผลย่อยเพื่อเรียก: gdalwarp หนึ่งสามารถ cal 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.