We need a GUI to configure the Python Raster Funciton. These initialization def __init__(self):
, parameter definaition def getParameterInfo(self):
, configuration setting def getConfiguration(self, **scalars):
, and Raster Metadata Updating def updateRasterInfo(self, **kwargs):
should not look as complicated as the following:
def __init__(self):
self.name = "Compound Topographic Index"
self.description = ("Computes the compound topographic index (CTI), also "
"known as the topographic wetness index (TWI). "
"This is calculated from an input slope raster and flow "
"accumulation surface and is meant to be used in "
"a raster function chain.")
def getParameterInfo(self):
return [
{
'name': 'slope',
'dataType': 'raster',
'value': None,
'required': True,
'displayName': "Slope Raster",
'description': "A slope raster (in degrees) derived from a digital elevation model (DEM)."
},
{
'name': 'flow',
'dataType': 'raster',
'value': None,
'required': True,
'displayName': "Flow Accumulation Raster",
'description': "A raster representing flow accumulation."
}
]
def getConfiguration(self, **scalars):
return {
'compositeRasters': False,
'inheritProperties': 1 | 2 | 4 | 8, # inherit all from the raster
'invalidateProperties': 2 | 4 | 8, # reset stats, histogram, key properties
'inputMask': False
}
def updateRasterInfo(self, **kwargs):
# repeat stats for all output raster bands
kwargs['output_info']['bandCount'] = 1
kwargs['output_info']['statistics'] = ({'minimum': 0, 'maximum': 25.0}, )
kwargs['output_info']['histogram'] = () # reset histogram
kwargs['output_info']['pixelType'] = 'f4'
self.dem_cellsize = kwargs['slope_info']['cellSize']
return kwargs
I don't like how we have to define bits in the inheritProperties
and invalidateProperties
. The kwargs
params are mysterious. This is all just overly complicated and unclear.
The def updatePixels(self, tlc, shape, props, **pixelBlocks):
block does the actual pixel processing. The pixelBlocks
are a multidimmensional numpy array of pixel values over a given extent. This syntax is pecluliar and unclear.
If you take a look at this CTI Raster Function, it takes in two input raster datasets: slope
(Slope Raster) and flow
(Flow Direction Raster). Those rasters become:
inBlock_slope = pixelBlocks['slope_pixels']
inBlock_flow = pixelBlocks['flow_pixels']
How do we make it easier? Why can't this function look more like def updatePixels(slope, flow):
?
If you look at some of the more recent raster functions that I have developed, for example, LandsatImageSynthesis.py, in the updatePixels
block, there are print statements and pickle exports.
#fname = '{:%Y_%b_%d_%H_%M_%S}_t.txt'.format(datetime.datetime.now())
#filename = os.path.join(debug_logs_directory, fname)
#file = open(filename,"w")
#file.write("File Open.\n")
#pickle_filename = os.path.join(debug_logs_directory, fname)
#pickle.dump(pix_time, open(pickle_filename[:-4]+'pix_time.p',"wb"))
I do this becuase in order to develop the function, I need to pull out a sample pixelBlock
and develop the python function against it. Not many people understand this workflow and even if they do, they think it's too complicated of a process just to develop some python image processing code. Can we make it easier to develop these functions?
With these comments in mind, is there anyway we can use Jupyter to write a Python Raster Function? Can we get the pixelBlocks
into a Notebook in order to prototype it?