GDAL Python Creating Contourlines - python

I'd like to generate contourlines from a SRTM image within Python. It seems to calculate but if I want to add my contourlines nothing shows up and the attribute table is empty as well. Please take a look at my code:
from osgeo import gdal, gdal_array
from osgeo.gdalconst import *
from numpy import *
from osgeo import ogr
#Read in SRTM data
indataset1 = gdal.Open( src_filename_1, GA_ReadOnly)
in1 = indataset1.GetRasterBand(1)
#Generate layer to save Contourlines in
ogr_ds = ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(dst_filename)
contour_shp = ogr_ds.CreateLayer('contour')
field_defn = ogr.FieldDefn("ID", ogr.OFTInteger)
contour_shp.CreateField(field_defn)
field_defn = ogr.FieldDefn("elev", ogr.OFTReal)
contour_shp.CreateField(field_defn)
#Generate Contourlines
gdal.ContourGenerate(in1, 100, 0, [], 0, 0, contour_shp, 0, 1)
ogr_ds.Destroy()
Field ID and field elevation seem to be empty, but the contour_shape file is fairly huge ~100MB.
Any idea what might went wrong?
Update: I got it! I forgot to close the datasource with: ogr_ds.Destroy()

Don't use the Destroy() method, as described in the GDAL/OGR Python Gotchas.
To save and close a dataset, dereference the variable, and optionally delete it.
I typically use this at the end to save/close either a GDAL or OGR dataset:
ogr_ds = None
del ogr_ds

Related

Python3.8: The last output file is not stored properly on disk

I have a global dataset at about 300m resolution in tif. I want to upscale it to 9km resolution (below you see my code). I decided to do upscaling piecewise due to high resolution data and large computing time. So I divided the whole global data into 10 pieces, do upscaling and store each piece separately in a tif file again. NOW my problem pops up: the last piece of global data is NOT saved completely on the disk. Each piece of map should be 2M but piece#10 is 1.7M. And the strange thing is that after running my script twice, that piece#10 will be completed and it will change from 1.7M to 2M. But the current piece10 is again not complete.
import numpy as np
from osgeo import gdal
from osgeo import osr
from osgeo.gdalconst import *
import pandas as pd
#
#%%
#-----converting--------#
df_new = pd.read_excel("input_attribute_table.xlsx",sheet_name='Global_data')
listvar = ['var1']
number = df_new['data_number'][:]
##The size of global array is 129599 x 51704. The pieces should be square
xoff = np.array([0, 25852.00, 51704.00, 77556.00, 103408.00])
yoff = np.array([0, 25852.00])
xcount = 25852
ycount = 25852
o = 1
for q in range(len(yoff)):
for p in range(len(xoff)):
src = gdal.Open('Global_database.tif')
ds_xform = src.GetGeoTransform()
ds_driver = gdal.GetDriverByName('Gtiff')
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
data =src.GetRasterBand(1).ReadAsArray(xoff[p],yoff[q],xcount,ycount).astype(np.float32)
Var = np.zeros(data.shape, dtype=np.float32)
Variable_load = df_new[listvar[0]][:]
for m in range(len(number)):
Var[data==number[m]] = Variable_load[m]
#-------rescaling-----------#
Var[np.where(np.isnan(Var))]=0
ds_driver = gdal.GetDriverByName('Gtiff')
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
sz = Var.itemsize
h,w = Var.shape
bh, bw = 36, 36
shape = (h/bh, w/bw, bh, bw)
shape2 = (int(shape[0]),int(shape[1]),shape[2],shape[3])
strides = sz*np.array([w*bh,bw,w,1])
blocks = np.lib.stride_tricks.as_strided(Var,shape=shape2,strides=strides)
resized_array=ds_driver.Create(str(listvar[0])+'_resized_to_9km_glob_piece'+str(o)+'.tif',shape2[1],shape2[0],1,gdal.GDT_Float32) resized_array.SetGeoTransform((ds_xform[0],ds_xform[1]*bw,ds_xform[2],ds_xform[3],ds_xform[4],ds_xform[5]*bh))
resized_array.SetProjection(srs.ExportToWkt())
band = resized_array.GetRasterBand(1)
zero_array = np.zeros([shape2[0],shape2[1]], dtype=np.float32)
for z in range(len(blocks)):
for k in range(len(blocks)):
zero_array[z][k] = np.mean(blocks[z][k])
band.WriteArray(zero_array)
band.FlushCache()
band = None
del zero_array
del Var
o=o+1
Normally, you should either be sure to call close on a file, or use the with statement. However, it looks like neither of those is supported by gdal.
Instead, you're expected to remove all references to the file. You're already setting band = None, but you also need to set src = None.
This is a bad, non-Pythonic interface, but that's apparently what the Python gdal library does. In addition to being a weird gotcha in its own right, it also interacts poorly with exceptions; any unhandled exceptions may also result in the file not being saved (or being partly saved, or being corrupted).
For the immediate problem, though, adding src = None or del src should do the trick.
PS (from comments): Another option would be to move the body of the for loop into a function; that will automatically delete all the variables without you having to list them all and potentially miss one. It'll still have problems if there's an exception, but at least the normal case should start working...

Unable to write Raster using Gdal in Python. Error:dict' object has no attribute 'shape'

I am trying to create a raster file after filling NO DATA with some value using gdal in Python.
I have a function that gets me the raster array.
def raster2array(rasterfn):
try:
bndNum_Val_Dic={}
raster = gdal.Open(rasterfn)
for bandNum in range(raster.RasterCount):
bandNum += 1
band=raster.GetRasterBand(bandNum)
bandVal=band.ReadAsArray()
bndNum_Val_Dic[bandNum]=bandVal
raster=None
return bndNum_Val_Dic
except Exception as e:
print(e)
Using the array generated from from this function I am trying to write my raster which throws an error at "outband.WriteArray(array)" that dict' object has no attribute 'shape'.
import numpy as np
import gdal
from osgeo import osr
rasterfn ="MAH_20.tif"
newRasterfn ="MAH_FND.tif"
array= raster2array(rasterfn)
newValue = 100
Driver= 'GTiff'
bandNumber=1
raster = gdal.Open(rasterfn)
geotransform = raster.GetGeoTransform()
originX = geotransform[0]
originY = geotransform[3]
pixelWidth = geotransform[1]
pixelHeight = geotransform[5]
cols = raster.RasterXSize
rows = raster.RasterYSize
bandCount=raster.RasterCount
rasterDataType=raster.GetRasterBand(bandNumber).DataType
global Flag
if(Flag):
driver = gdal.GetDriverByName(Driver)
global outRaster
outRaster = driver.Create(newRasterfn, cols, rows, bandCount, rasterDataType)
Flag=False
outband = outRaster.GetRasterBand(bandNumber)
outRaster.SetGeoTransform((originX, pixelWidth, 0, originY, 0, pixelHeight))
outband = outRaster.GetRasterBand(bandNumber)
outband.WriteArray(array)
outRasterSRS = osr.SpatialReference()
outRasterSRS.ImportFromWkt(raster.GetProjectionRef())
outRaster.SetProjection(outRasterSRS.ExportToWkt())
outRaster.GetRasterBand(bandNumber).SetNoDataValue(newValue)
raster=None
if(bandNumber==bandCount):
outRaster=None
outband=None
raster=None
I am using python 3.5 and GDAL 3.0.2. Is there any way to fix this?
Any help will be appreciated
You are trying two write a dictionary while GDAL expects a Numpy array. It's not completely clear which data you are trying to write, but changing your write statement to something as shown below should at least get rid of the error message. But make sure you write the correct band.
outband.WriteArray(array[bandNumber])

gdal WriteArray() crashes python without a stack trace

I'm trying to write an array to a geotiff using gdal. Each row of the array is identical, and I used np.broadcast_to to create the array.
When I try to write it, the I get a windows popup saying "Python has stopped working: A problem cause the program to stop working correctly. Please close the program"
This approximates the steps I'm taking:
import gdal
import numpy as np
driver = gdal.GetDriverByName('GTiff')
outRaster = driver.Create("C:/raster.tif", 1000, 1000, 1, 6)
band = outRaster.GetRasterBand(1)
# Create array
a = np.arange(0,1000, dtype='float32')
a1 = np.broadcast_to(a, (1000,1000))
# try writing
band.WriteArray(a1) # crash
The problem is that the input array created by broadcast_to isn't contiguous on disk. As described in the numpy documentation, more than one element array may point to the same memory address. This causes problems in gdal.
Instead of using broadcast_to, use something that stores each element as its own place in memory.
As an illustrative example, see the following code:
import gdal
import numpy as np
import sys
driver = gdal.GetDriverByName('GTiff')
outRaster = driver.Create("C:/raster.tif", 1000, 1000, 1, 6)
band = outRaster.GetRasterBand(1)
# Create 1000 x 1000 array two different ways
a = np.arange(0,1000, dtype='float32')
a1 = a[np.newaxis, :]
a1 = a1.repeat(1000, axis=0)
a2 = np.broadcast_to(a, (1000,1000))
# examine size of objects
sys.getsizeof(a1) # 4000112
sys.getsizeof(a2) # 112
# try writing
band.WriteArray(a1) # writes fine
band.WriteArray(a2) # crash

How to save custom vertex properties with openmesh in Python?

I am working with openmesh installed in Python 3.6 via pip. I need to add custom properties to vertices of a mesh in order to store some data at each vertex. My code goes as follows :
import openmesh as OM
import numpy as np
mesh = OM.TriMesh()
#Some vertices
vh0 = mesh.add_vertex(np.array([0,0,0]));
vh1 = mesh.add_vertex(np.array([1,0,0]));
vh2 = mesh.add_vertex(np.array([1,1,0]));
vh3 = mesh.add_vertex(np.array([0,1,0]));
#Some data
data = np.arange(mesh.n_vertices)
#Add custom property
for vh in mesh.vertices():
mesh.set_vertex_property('prop1', vh, data[vh.idx()])
#Check properties have been added correctly
print(mesh.vertex_property('prop1'))
OM.write_mesh('mesh.om',mesh)
print returns [0, 1, 2, 3]. So far, so good. But when I read again the mesh, the custom property has disappeared :
mesh1 = OM.TriMesh()
mesh1 = OM.read_trimesh('mesh.om')
print(mesh1.vertex_property('prop1'))
returns [None, None, None, None]
I have two guesses :
1 - The property was not saved in the first place
2 - The reader does not know there is a custom property when it reads the file mesh.om
Does anybody know how to save and read properly a mesh with custom vertex properties with openmesh in Python? Or is it even possible (has anybody done it before?)?
Is it that there is something wrong with my code?
Thanks for your help,
Charles.
The OM writer currently does not support custom properties. If you are working with numeric properties, it is probably easiest to convert the data to a NumPy array and save it separately.
Say your mesh and properties are set up like this:
import openmesh as om
import numpy as np
# create example mesh
mesh1 = om.TriMesh()
v00 = mesh1.add_vertex([0,0,0])
v01 = mesh1.add_vertex([0,1,0])
v10 = mesh1.add_vertex([1,0,0])
v11 = mesh1.add_vertex([1,1,0])
mesh1.add_face(v00, v01, v11)
mesh1.add_face(v00, v11, v01)
# set property data
mesh1.set_vertex_property('color', v00, [1,0,0])
mesh1.set_vertex_property('color', v01, [0,1,0])
mesh1.set_vertex_property('color', v10, [0,0,1])
mesh1.set_vertex_property('color', v11, [1,1,1])
You can extract the property data as a numpy array using one of the *_property_array methods and save it alongside the mesh using NumPy's save function.
om.write_mesh('mesh.om', mesh1)
color_array1 = mesh1.vertex_property_array('color')
np.save('color.npy', color_array1)
Loading is similar:
mesh2 = om.read_trimesh('mesh.om')
color_array2 = np.load('color.npy')
mesh2.set_vertex_property_array('color', color_array2)
# verify property data is equal
for vh1, vh2 in zip(mesh1.vertices(), mesh2.vertices()):
color1 = mesh1.vertex_property('color', vh1)
color2 = mesh2.vertex_property('color', vh2)
assert np.allclose(color1, color2)
When you store data, you should set set_persistent function true like below.
(sorry for using c++, I don't know about python)
OpenMesh::VPropHandleT<float> vprop_float;
mesh.add_property(vprop_float, "vprop_float");
mesh.property(vprop_float).set_persistent(true);
OpenMesh::IO::write_mesh(mesh, "tmesh.om");
and then, you have to request this custom property in your mesh before loading it with the obj reader. Order is important.
TriMesh readmesh;
OpenMesh::VPropHandleT<float> vprop_float;
readmesh.add_property(vprop_float, "vprop_float");
OpenMesh::IO::read_mesh(readmesh, "tmesh.om");'
I refered below.
https://www.openmesh.org/media/Documentations/OpenMesh-4.0-Documentation/a00062.html
https://www.openmesh.org/media/Documentations/OpenMesh-4.0-Documentation/a00060.html

How do I import tif using gdal?

How do I import tif using gdal?
I'm trying to get my tif file in a usable format in Python, so I can analyze the data. However, every time I import it, I just get an empty list. Here's my code:
xValues = [447520.0, 432524.0, 451503.0]
yValues = [4631976.0, 4608827.0, 4648114.0]
gdal.AllRegister()
dataset = gdal.Open('final_snow.tif', GA_ReadOnly)
if dataset is None:
print 'Could not open image'
sys.exit(1)
data = np.array([gdal.Open(name, gdalconst.GA_ReadOnly).ReadAsArray() for name, descr in dataset.GetSubDatasets()])
print 'this is data ', data`
It always prints an empty list, but it doesn't throw an error. I checked out other questions, such as [this] (Create shapefile from tif file using GDAL) What might be the problem?
For osgeo.gdal, it should look like this:
from osgeo import gdal
gdal.UseExceptions() # not required, but a good idea
dataset = gdal.Open('final_snow.tif', gdal.GA_ReadOnly)
data = dataset.ReadAsArray()
Where data is either a 2D array for 1-banded rasters, or a 3D array for multiband.
An alternative with rasterio looks like:
import rasterio
with rasterio.open('final_snow.tif', 'r') as r:
data = r.read()
Where data is always a 3D array, with the first dimension as band index.

Categories