一些在线搜索使我确信没有,所以我开发了一个通过解析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]
#1 楼
这是另一种无需调用外部程序的方法。这是从地理变换中获取四个角的坐标,然后使用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.CoordinateTransformation的一些代码
评论
太好了,谢谢。无论gdalinfo输出中是否存在适当的行,它都可以工作。
– EddyTheB
13年4月16日在18:01
我认为使用tgt_srs = src_srs.CloneGeogCS()会更好。我最初的栅格是火星的图像,因此使用EPSG(4326)并不理想,但是CloneGeogCS()似乎只是从投影坐标更改为地理坐标。
– EddyTheB
13年4月19日在0:49
当然。我已经更新了使用CloneGeogCS的答案。但是,我只是试图演示GetExtent和ReprojectCoords函数的用法。您可以使用任何您想要的目标srs。
–user2856
13年4月19日在1:17
是的,谢谢,否则我将再也找不到这些。
– EddyTheB
13年4月19日在2:28
如果您有一个没有投影并指定RPC的数据集怎么办?从wkt函数导入失败。可以使用变压器来计算范围,但是我想知道上面的方法是否有办法?
–托马斯
18-10-23在21:12
#2 楼
这可以用更少的代码行完成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)。 (一个小问题-src.GetGeoTransform()中的'T'应该大写)。
– GT。
17-2-22在0:59
@GT。添加了一个例子
–詹姆斯
17年2月22日在7:37
#3 楼
使用rasterio非常简单,我是这样完成的:ds_raster = rasterio.open(raster_path)
bounds = ds_raster.bounds
left= bounds.left
bottom = bounds.bottom
right = bounds.right
top = bounds.top
#4 楼
我已经这样做了...它有点硬编码,但是如果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]
评论
这是相当脆弱的,因为它依赖于既可以在用户路径上使用gdalinfo(并非总是如此,尤其是在Windows上)并且解析没有严格接口的打印输出-即依靠那些“魔术数字”来获得正确的间距。当gdal提供全面的python绑定(可以更明确,更可靠的方式执行此操作)时,这是不必要的
–詹姆斯
17-2-22在7:44
#5 楼
如果旋转了栅格,则数学会变得更加复杂,因为您需要考虑六个仿射变换系数中的每一个。考虑使用仿射变换旋转仿射变换/地理变换: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)
评论
您能否就这个仿射变换问题分享您的看法? gis.stackexchange.com/questions/361003/…
–BằngRikimaru
20年5月8日在8:41
#6 楼
我相信在适用于python的OSGEO / GDAL模块的最新版本中,可以直接从代码中调用GDAL实用程序,而无需进行系统调用。例如,可以使用gdal.Info(the_name_of_the_file)来暴露文件元数据/注释
或而不是使用子过程来调用:
gdalwarp可以校准gdal.Warp在栅格上进行变形。
当前可作为内部函数使用的GDAL实用程序列表:
http://erouault.blogspot.com/2015/10/gdal-and-ogr-utilities-as-library.html
评论
可能相关:gis.stackexchange.com/questions/33330/…