Chr*_*ris 7 python numpy terrain gdal
我想用python,gdal和numpy创建一些高程/高度栅格栅格.我被困在numpy(可能是python和gdal.)
在numpy中,我一直在尝试以下方面:
>>> a= numpy.linspace(4,1,4, endpoint=True)
>>> b= numpy.vstack(a)
>>> c=numpy.repeat(b,4,axis=1)
>>> c
array([[ 4., 4., 4., 4.],
[ 3., 3., 3., 3.],
[ 2., 2., 2., 2.],
[ 1., 1., 1., 1.]]) #This is the elevation data I want
Run Code Online (Sandbox Code Playgroud)
来自gdalconst import的osgeo import gdal*
>>> format = "Terragen"
>>> driver = gdal.GetDriverByName(format)
>>> dst_ds = driver.Create('test.ter', 4,4,1,gdal.GDT_Float32, ['MINUSERPIXELVALUE = 1', 'MAXUSERPIXELVALUE= 4'])
>>> raster = numpy.zeros((4,4), dtype=numpy.float32) #this is where I'm messing up
>>> dst_ds.GetRasterBand(1).WriteArray(raster) # gives the null elevation data I asked for in (raster)
0
>>> dst_ds = None
Run Code Online (Sandbox Code Playgroud)
我想我错过了一些简单的东西,期待你的建议.
谢谢,
克里斯
(后来继续)
我向Ray Gardener和Frank Warmerdam道歉.
Terragen格式说明:
用于写入:SCAL =网格距离(米)hv_px = hv_m/SCAL span_px = span_m/SCAL偏移=参见TerragenDataset :: write_header()scale =参见TerragenDataset :: write_header()physical hv =(hv_px - offset)*65536.0/scale
我们告诉来电者:
Elevations are Int16 when reading,
and Float32 when writing. We need logical
elevations when writing so that we can
encode them with as much precision as possible
when going down to physical 16-bit ints.
Implementing band::SetScale/SetOffset won't work because
it requires callers to know format write details.
So we've added two Create() options that let the
caller tell us the span's logical extent, and with
those two values we can convert to physical pixels.
ds::SetGeoTransform() lets us establish the
size of ground pixels.
ds::SetProjection() lets us establish what
units ground measures are in (also needed
to calc the size of ground pixels).
band::SetUnitType() tells us what units
the given Float32 elevations are in.
Run Code Online (Sandbox Code Playgroud)
这告诉我,在我上面的WriteArray(somearray)之前,我必须设置GeoTransform和SetProjection以及SetUnitType以便工作(可能)
从GDAL API教程:Python导入osr import numpy
dst_ds.SetGeoTransform( [ 444720, 30, 0, 3751320, 0, -30 ] )
srs = osr.SpatialReference()
srs.SetUTM( 11, 1 )
srs.SetWellKnownGeogCS( 'NAD27' )
dst_ds.SetProjection( srs.ExportToWkt() )
raster = numpy.zeros( (512, 512), dtype=numpy.uint8 ) #we've seen this before
dst_ds.GetRasterBand(1).WriteArray( raster )
# Once we're done, close properly the dataset
dst_ds = None
Run Code Online (Sandbox Code Playgroud)
我为创建一个过长的帖子和坦白而道歉.如果我做对了,那么将所有笔记放在一个地方(长篇文章)会很好.
忏悔:
我之前拍了一张照片(jpeg),将其转换为geotiff,并将其作为图块导入到PostGIS数据库中.我现在正在尝试创建高程栅格,以覆盖图片.这可能看起来很愚蠢,但有一位艺术家我想表达,同时也不会冒犯那些努力创造和改进这些伟大工具的人.
这位艺术家是比利时人,所以米是有序的.她在纽约州曼哈顿下城工作,UTM 18.现在有些合理的SetGeoTransform.上面提到的图片是w = 3649/h = 2736,我将不得不考虑一下.
另一个尝试:
>>> format = "Terragen"
>>> driver = gdal.GetDriverByName(format)
>>> dst_ds = driver.Create('test_3.ter', 4,4,1, gdal.GDT_Float32, ['MINUSERPIXELVALUE=1','MAXUSERPIXELVALUE-4'])
>>> type(dst_ds)
<class 'osgeo.gdal.Dataset'>
>>> import osr
>>> dst_ds.SetGeoTransform([582495, 1, 0.5, 4512717, 0.5, -1]) #x-res 0.5, y_res 0.5 a guess
0
>>> type(dst_ds)
<class 'osgeo.gdal.Dataset'>
>>> srs = osr.SpatialReference()
>>> srs.SetUTM(18,1)
0
>>> srs.SetWellKnownGeogCS('WGS84')
0
>>> dst_ds.SetProjection(srs.ExportToWkt())
0
>>> raster = c.astype(numpy.float32)
>>> dst_ds.GetRasterBand(1).WriteArray(raster)
0
>>> dst_ds = None
>>> from osgeo import gdalinfo
>>> gdalinfo.main(['foo', 'test_3.ter'])
Driver: Terragen/Terragen heightfield
Files: test_3.ter
Size is 4, 4
Coordinate System is:
LOCAL_CS["Terragen world space",
UNIT["m",1]]
Origin = (0.000000000000000,0.000000000000000)
Pixel Size = (1.000000000000000,1.000000000000000)
Metadata:
AREA_OR_POINT=Point
Corner Coordinates:
Upper Left ( 0.0000000, 0.0000000)
Lower Left ( 0.0000000, 4.0000000)
Upper Right ( 4.0000000, 0.0000000)
Lower Right ( 4.0000000, 4.0000000)
Center ( 2.0000000, 2.0000000)
Band 1 Block=4x1 Type=Int16, ColorInterp=Undefined
Unit Type: m
Offset: 2, Scale:7.62939453125e-05
0
Run Code Online (Sandbox Code Playgroud)
显然越来越近但不清楚SetUTM(18,1)是否被拾起.这是哈德逊河中的4x4还是Local_CS(坐标系)?什么是沉默的失败?
更多阅读
// Terragen files aren't really georeferenced, but
// we should get the projection's linear units so
// that we can scale elevations correctly.
// Increase the heightscale until the physical span
// fits within a 16-bit range. The smaller the logical span,
// the more necessary this becomes.
Run Code Online (Sandbox Code Playgroud)
4x4米是一个非常小的逻辑跨度.
所以,也许这就好了.SetGeoTransform获得单位,设置比例,你有Terragen世界空间.
最后的想法:我不编程,但在某种程度上我可以遵循.也就是说,我有点想知道我的小Terragen世界空间中的数据是什么样的(以下是感谢http://www.gis.usu.edu/~chrisg/python/2009/第4周):
>>> fn = 'test_3.ter'
>>> ds = gdal.Open(fn, GA_ReadOnly)
>>> band = ds.GetRasterBand(1)
>>> data = band.ReadAsArray(0,0,1,1)
>>> data
array([[26214]], dtype=int16)
>>> data = band.ReadAsArray(0,0,4,4)
>>> data
array([[ 26214, 26214, 26214, 26214],
[ 13107, 13107, 13107, 13107],
[ 0, 0, 0, 0],
[-13107, -13107, -13107, -13107]], dtype=int16)
>>>
Run Code Online (Sandbox Code Playgroud)
所以这很令人满意.我想象上面使用的numpy c和这个结果之间的差异是在这个非常小的逻辑范围内应用Float16的行为.
并转到'hf2':
>>> src_ds = gdal.Open('test_3.ter')
>>> dst_ds = driver.CreateCopy('test_6.hf2', src_ds, 0)
>>> dst_ds.SetGeoTransform([582495,1,0.5,4512717,0.5,-1])
0
>>> srs = osr.SpatialReference()
>>> srs.SetUTM(18,1)
0
>>> srs.SetWellKnownGeogCS('WGS84')
0
>>> dst_ds.SetProjection( srs.ExportToWkt())
0
>>> dst_ds = None
>>> src_ds = None
>>> gdalinfo.main(['foo','test_6.hf2'])
Driver: HF2/HF2/HFZ heightfield raster
Files: test_6.hf2
test_6.hf2.aux.xml
Size is 4, 4
Coordinate System is:
PROJCS["UTM Zone 18, Northern Hemisphere",
GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84",6378137,298.257223563,
AUTHORITY["EPSG","7030"]],
TOWGS84[0,0,0,0,0,0,0],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.0174532925199433,
AUTHORITY["EPSG","9108"]],
AUTHORITY["EPSG","4326"]],
PROJECTION["Transverse_Mercator"],
PARAMETER["latitude_of_origin",0],
PARAMETER["central_meridian",-75],
PARAMETER["scale_factor",0.9996],
PARAMETER["false_easting",500000],
PARAMETER["false_northing",0],
UNIT["Meter",1]]
Origin = (0.000000000000000,0.000000000000000)
Pixel Size = (1.000000000000000,1.000000000000000)
Metadata:
VERTICAL_PRECISION=1.000000
Corner Coordinates:
Upper Left ( 0.0000000, 0.0000000) ( 79d29'19.48"W, 0d 0' 0.01"N)
Lower Left ( 0.0000000, 4.0000000) ( 79d29'19.48"W, 0d 0' 0.13"N)
Upper Right ( 4.0000000, 0.0000000) ( 79d29'19.35"W, 0d 0' 0.01"N)
Lower Right ( 4.0000000, 4.0000000) ( 79d29'19.35"W, 0d 0' 0.13"N)
Center ( 2.0000000, 2.0000000) ( 79d29'19.41"W, 0d 0' 0.06"N)
Band 1 Block=256x1 Type=Float32, ColorInterp=Undefined
Unit Type: m
0
>>>
Run Code Online (Sandbox Code Playgroud)
几乎完全令人欣慰,虽然看起来我在秘鲁的La Concordia.因此,我必须弄清楚如何说 - 像纽约北部更像北方.SetUTM是否采用了第三个元素,表明北方或南方"有多远".似乎我昨天遇到了一个UTM图表,它有一个字母标签区域,比如赤道上的C和纽约地区的T或S.
其实,我认为SetGeoTransform基本上建立左上角北向和东,这是影响的是"有多远北/南" SetUTM的一部分.关闭gdal-dev.
后来还是:
帕丁顿熊去了秘鲁,因为他有一张票.我到了那里因为我说那就是我想去的地方.Terragen就像它一样工作,给了我像素空间.随后对srs的调用对hf2(SetUTM)起作用,但东部和北部是在Terragen下建立的,所以UTM 18已经设定,但是在赤道的边界框中.够好了.
gdal_translate让我去了纽约.我在Windows中这么一个命令行.结果;
C:\Program Files\GDAL>gdalinfo c:/python27/test_9.hf2
Driver: HF2/HF2/HFZ heightfield raster
Files: c:/python27/test_9.hf2
Size is 4, 4
Coordinate System is:
PROJCS["UTM Zone 18, Northern Hemisphere",
GEOGCS["NAD83",
DATUM["North_American_Datum_1983",
SPHEROID["GRS 1980",6378137,298.257222101,
AUTHORITY["EPSG","7019"]],
TOWGS84[0,0,0,0,0,0,0],
AUTHORITY["EPSG","6269"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.0174532925199433,
AUTHORITY["EPSG","9122"]],
AUTHORITY["EPSG","4269"]],
PROJECTION["Transverse_Mercator"],
PARAMETER["latitude_of_origin",0],
PARAMETER["central_meridian",-75],
PARAMETER["scale_factor",0.9996],
PARAMETER["false_easting",500000],
PARAMETER["false_northing",0],
UNIT["Meter",1]]
Origin = (583862.000000000000000,4510893.000000000000000)
Pixel Size = (-1.000000000000000,-1.000000000000000)
Metadata:
VERTICAL_PRECISION=0.010000
Corner Coordinates:
Upper Left ( 583862.000, 4510893.000) ( 74d 0'24.04"W, 40d44'40.97"N)
Lower Left ( 583862.000, 4510889.000) ( 74d 0'24.04"W, 40d44'40.84"N)
Upper Right ( 583858.000, 4510893.000) ( 74d 0'24.21"W, 40d44'40.97"N)
Lower Right ( 583858.000, 4510889.000) ( 74d 0'24.21"W, 40d44'40.84"N)
Center ( 583860.000, 4510891.000) ( 74d 0'24.13"W, 40d44'40.91"N)
Band 1 Block=256x1 Type=Float32, ColorInterp=Undefined
Unit Type: m
C:\Program Files\GDAL>
Run Code Online (Sandbox Code Playgroud)
所以,我们回到了纽约.可能有更好的方法来解决所有这些问题.我必须有一个接受Create的目标,因为我正在从numpy中假设/即兴创建数据集.我需要查看允许创建的其他格式.GeoTiff的高度是可能的(我想.)
感谢所有评论,建议以及对适当阅读的温和推动.在python中制作地图很有趣!
克里斯
你离我不太远.您唯一的问题是GDAL创建选项的语法问题.更换:
['MINUSERPIXELVALUE = 1','MAXUSERPIXELVALUE= 4']
Run Code Online (Sandbox Code Playgroud)
有没有空格之前或键/值对后:
['MINUSERPIXELVALUE=1', 'MAXUSERPIXELVALUE=4']
Run Code Online (Sandbox Code Playgroud)
检查type(dst_ds)
它应该是,<class 'osgeo.gdal.Dataset'>
而不是<type 'NoneType'>
像上面那样的无声失败.
更新默认情况下,不显示警告或异常.您可以通过启用它们gdal.UseExceptions()
来查看下面的内容,例如:
>>> from osgeo import gdal
>>> gdal.UseExceptions()
>>> driver = gdal.GetDriverByName('Terragen')
>>> dst_ds = driver.Create('test.ter', 4,4,1,gdal.GDT_Float32, ['MINUSERPIXELVALUE = 1', 'MAXUSERPIXELVALUE= 4'])
Warning 6: Driver Terragen does not support MINUSERPIXELVALUE creation option
>>> dst_ds = driver.Create('test.ter', 4,4,1,gdal.GDT_Float32, ['MINUSERPIXELVALUE=1', 'MAXUSERPIXELVALUE=4'])
>>> type(dst_ds)
<class 'osgeo.gdal.Dataset'>
Run Code Online (Sandbox Code Playgroud)