Quickstart: running an OTB application with pyotb

pyotb has been written so that it is more convenient to run an application in Python.

You can pass the parameters of an application as a dictionary :

import pyotb
resampled = pyotb.RigidTransformResample({
    'in': 'my_image.tif', 
    'transform.type.id.scaley': 0.5,
    'interpolator': 'linear', 
    'transform.type.id.scalex': 0.5
})

For now, resampled has not been executed. Indeed, pyotb has a 'lazy' evaluation: applications are executed only when required. Generally, like in this example, executions happen to write output images to disk.

To actually trigger the application execution, write() has to be called:

resampled.write('output.tif')  # this is when the application actually runs

Using Python keyword arguments

One can use the Python keyword arguments notation for passing that parameters:

output = pyotb.SuperImpose(inr='reference_image.tif', inm='image.tif')

Which is equivalent to:

output = pyotb.SuperImpose({'inr': 'reference_image.tif', 'inm': 'image.tif'})

Warning

For this notation, python doesn't accept the parameter in or any parameter that contains a dots (e.g. io.in). For in or other main input parameters of an OTB application, you may simply pass the value as first argument, pyotb will guess the parameter name. For parameters that contains dots, you can either use a dictionary, or replace dots (.) with underscores (_).

Let's take the example of the OrthoRectification application of OTB, with the input image parameter named io.in:

Option #1, keyword-arg-free:

ortho = pyotb.OrthoRectification('my_image.tif')

Option #2, replacing dots with underscores in parameter name:

ortho = pyotb.OrthoRectification(io_in='my_image.tif')

In-memory connections

One nice feature of pyotb is in-memory connection between apps. It relies on the so-called streaming mechanism of OTB, that enables to process huge images with a limited memory footprint.

pyotb allows to pass any application's output to another. This enables to build pipelines composed of several applications.

Let's start from our previous example. Consider the case where one wants to resample the image, then apply optical calibration and binary morphological dilatation. We can write the following code to build a pipeline that will generate the output in an end-to-end fashion, without being limited with the input image size or writing temporary files.

import pyotb

resampled = pyotb.RigidTransformResample({
    'in': 'my_image.tif', 
    'interpolator': 'linear',
    'transform.type.id.scaley': 0.5, 
    'transform.type.id.scalex': 0.5
})

calibrated = pyotb.OpticalCalibration({
    'in': resampled, 
    'level': 'toa'
}) 

dilated = pyotb.BinaryMorphologicalOperation({
    'in': calibrated, 
    'out': 'output.tif', 
    'filter': 'dilate',
    'structype': 'ball', 
    'xradius': 3, 
    'yradius': 3
})

We just have built our first pipeline! At this point, it's all symbolic since no computation has been performed. To trigger our pipeline, one must call the write() method from the pipeline termination:

dilated.write('output.tif')

In the next section, we will detail how write() works.

Writing the result of an app

Any pyotb object can be written to disk using write().

Let's consider the following pyotb application instance:

import pyotb
resampled = pyotb.RigidTransformResample({
    'in': 'my_image.tif', 
    'interpolator': 'linear',
    'transform.type.id.scaley': 0.5,
    'transform.type.id.scalex': 0.5
})

We can then write the output of resampled as following:

resampled.write('output.tif')

Note

For applications that have multiple outputs, passing a dict of filenames can be considered. Let's take the example of MeanShiftSmoothing which has 2 output images:

import pyotb
meanshift = pyotb.MeanShiftSmoothing('my_image.tif')
meanshift.write({'fout': 'output_1.tif', 'foutpos': 'output_2.tif'})

Another possibility for writing results is to set the output parameter when initializing the application:

import pyotb

resampled = pyotb.RigidTransformResample({
    'in': 'my_image.tif', 
    'interpolator': 'linear', 
    'out': 'output.tif',
    'transform.type.id.scaley': 0.5,
    'transform.type.id.scalex': 0.5
})

Pixel type

Setting the pixel type is optional, and can be achieved setting the pixel_type argument:

resampled.write('output.tif', pixel_type='uint16')

The value of pixel_type corresponds to the name of a pixel type from OTB applications (e.g. 'uint8', 'float', etc).

Extended filenames

Extended filenames can be passed as str or dict.

As str:

resampled.write(
    ...
    ext_fname='nodata=65535&box=0:0:256:256'
)

As dict:

resampled.write(
    ...
    ext_fname={'nodata': '65535', 'box': '0:0:256:256'}
)

Info

When ext_fname is provided and the output filenames contain already some extended filename pattern, the ones provided in the filenames take priority over the ones passed in ext_fname. This allows to fine-grained tune extended filenames for each output, with a common extended filenames keys/values basis.