This page explain how to access OTB C++ application via Python API inside a SNAP Operator Plugin.
Read how to write a processor in python for a tutorial. - How to write a processor in Python. This tutorial explain all the snap related stuff in creating an java maven project to write a SNAP processor
This example demonstrates computing ndvi for a source product opened in SNAP through OTB. Note that RadiometricIndices application in OTB is not exclusively for computing NDVI. see its documentation here[link].
The python-operator-plugin ask for red and nir bands that will be used to compute NDVI. The parameter options are handled by ndvi_op-in.xml
In order to write a Python plugin for SNAP you need the following tools.
Maven >= v3.0 Maven is the build tool used to build and package the final plugin file.
The recommended basic project structure looks like as shown in the following code block. We will look at the content and the meaning of each of those files later.
| pom.xml (the project definition file for maven)
| manifest.mf (settings for the plugin)
| my_python_op-info.xml (metadata about the operator)
| my_python_op.py (the actual operator implementation)
| layer.xml (integration into SNAP Desktop)
org.esa.snap.python.gpf.PyOperatorSpi (make the operator known to SNAP Engine)
An operator implemented in Python needs to have three methods. An initialize, a compute and a dispose method. Please have a look at the following skeleton on an operator.
def init(self): pass
def initialize(self, context):
# You either implement this or the computeTileStack method
def computeTile(self, context, band, tile):
# You either implement this or the computeTile method
def computeTileStack(self, context, target_tiles, target_rectangle):
def dispose(self, context):
initialize method takes input from user through UI and create source and target product. We also create band instance which are later used inside computeTileStack method. This method is called only once at start of processing.
Data input to OTB application from SNAP is done using python numpy arrays. Inside computeTileStack method, one can have access to underlying pixels which fall only under the target_rectangle. We pick the pixel data using Tile.getSamplesFloat() and stack into an N-dimensional numpy array. The call for making numpy.ndarray or numpy.array is decided by the input image type (VectorImage, Image, ImageList) of OTB application.
Below is the snippet which create N-dimensional numpy array using two bands for the input to RadiometricIndices application.
Note: Tile.setSamples() requires a N-dimensional numpy array even though the function set samples for one single band. This is a limitation in snap python bindings.
Our otb application returns an N-D array from GetVectorImageAsNumpyArray() but number of bands is 1 because we compute only one index NDVI.
suppose we compute two indices NDVI and WVI, then the "ndvi" will have two bands each representing one index. In that case, we have to workaround to overcome the snap python issue before calling Tile.setSamples()
See below code snippet which create a temporary nd array and fill the first slice from ndvi
you must install swig, python-devel and python-numpy package
chmod +x OTB-5.4.0-xdk-Linux64.run
git clone https://firstname.lastname@example.org/git/otb.git
mkdir OTB.build && cd OTB.build
cmake -DOTB_WRAP_PYTHON=TRUE -DOTB_USE_MUPARSER=TRUE ../OTB
make && make install (default install is /usr/local)
Clone snap-examples from github fork
You can checkout the sources and import the project.