This chapter presents the different steps to write your own application. It also contains a description of the
framework surrounding the applications.
The first logical step is to define the role of your application:
- What is the function of your application ? Try to draw a box diagram to describe the design
of your application. Note that you don’t have to worry about opening and saving image (or
vector data) files, this is handled by the framework.
- What variables (or data objects) must be exposed outside the application ? Try to make a list
of the inputs, outputs and parameters of your application.
Then you should have a good vision of your application pipeline. Depending on the different filters used,
the application can be streamed and threaded. The threading capabilities can be different between the
filters so there is no overall threading parameter (by default, each filter has its own threading
settings).
It is a different story for streaming. Since the image writers are handled within the framework and outside
the reach of the developer, the default behaviour is to use streaming. If one of the filters doesn’t support
streaming, it will enlarge the requested output region to the largest possible region and the entire
image will be processed at once. As a result, the developer doesn’t have to handle streaming nor
threading. However, there is a way to choose the number of streaming divisions (see section
31.2.4).
Every application derive from the class otb::Wrapper::Application . An application can’t be
templated. It must contain the standard class typedefs and a call to the OTB_APPLICATION_EXPORT
macro.
You need also to define standard macros itk::NewMacro and itk::TypeMacro .
It is also mandatory to implement three methods in a new application:
- DoInit()
- DoUpdateParameters()
- DoExecute()
This method is called once, when the application is instanciated. It should contain the following
actions:
- Set the name and the description of the application
- Fill the documentation and give an example
- Declare all the parameters
This method is called after every modification of a parameter value. With the command line
launcher, it is called each time a parameter is loaded. With the Qt launcher, it is called each time
a parameter field is modified. It can be used to maintain consistency et relationship between
parameters (e.g. in ExtractROI: when changing the input image, maybe the ROI size has to be
updated).
This method contains the real action of the application. This is where the pipeline must be set up. The
application framework provides different methods to get a value or an object associated to a
parameter:
- GetParameterInt(key) : get the integer value of a parameter
- GetParameterFloat(key) : get the float value of a parameter
- GetParameterString(key) : get the string value of a parameter
- GetParameterImage(key) : get a pointer to an image object, read from the file name given
in input
- …
where key refers to parameter key, defined using AddParameter() method in DoInit() method.
Similar methods exist for binding a data object to an output parameter:
- SetParameterOutputImage(key,data) : link the image object to the given output
parameter
- SetParameterComplexOutputImage(key,data) : link the complex image object to the
given output parameter
- SetParameterOutputVectorData(key,data) : link the vector data object to the given
output parameter
If possible, no filter update should be called inside this function. The update will be automatically called
afterwards : for every image or vector data output, a writer is created and updated.
In the new application framework, every input, output or parameter derive from otb::Wrapper::Parameter .
The application engine supplies the following types of parameters:
- ParameterType_Empty : parameter without value (can be used to represent a flag)
- ParameterType_Int : parameter storing an integer.
- ParameterType_Radius : parameter storing a radius.
- ParameterType_Float : parameter storing a float.
- ParameterType_String : parameter storing character string.
- ParameterType_StringList : parameter storing a list of character string.
- ParameterType_InputFilename : parameter storing an input file name.
- ParameterType_InputFilenameList : parameter storing a list of input file names.
- ParameterType_Directory : parameter storing a folder name.
- ParameterType_Group : parameter storing children parameters.
- ParameterType_Choice : parameter storing a list of choices (doesn’t support multi-choice).
It also allows to create specific sub-parameters for each available choice.
- ParameterType_ListView : parameter storing a list of choices (support multi-choice).
- ParameterType_InputImage : parameter storing an input image.
- ParameterType_InputImageList : parameter storing a list of input image.
- ParameterType_ComplexInputImage : parameter storing a complex input image.
- ParameterType_InputVectorData : parameter storing input vector data.
- ParameterType_InputVectorDataList : parameter storing a list of input vector data.
- ParameterType_InputProcessXML : parameter storing an input XML file name.
- ParameterType_OutputFilename : parameter storing an output file name.
- ParameterType_OutputImage : parameter storing an output image.
- ParameterType_ComplexOutputImage : parameter storing a complex output image.
- ParameterType_OutputVectorData : parameter storing an output vector data.
- ParameterType_OutputProcessXML : parameter storing an output XML file name.
- ParameterType_RAM : parameter storing the maximum amount of RAM to be used.
Each created parameter has a unique key and several boolean flags to represent its state. These flags can be
used to set a parameter optional or test if the user has modified the parameter value. The parameters are
created in the DoInit() method, then the framework will set their value (either by parsing the command
line or reading the graphical user interface). The DoExecute() method is called when all mandatory
parameters have been given a value, which can be obtained with ”Get” methods defined in
otb::Wrapper::Application . Parameters are set mandatory (or not) using MandatoryOn(key) method
(MandatoryOff(key)).
Some functions are specific to numeric parameters, such as SetMinimumParameterIntValue(key,value) or
SetMaximumParameterFloatValue(key,value). By default, numeric parameters are treated as inputs. If
your application outputs a number, you can use a numeric parameter and change its role by calling
SetParameterRole(key,Role_Output).
The input types InputImage, InputImageList, ComplexInputImage, InputVectorData and
InputVectorDataList store the name of the files to load, but they also encapsulate the readers needed to
produce the input data.
The output types OutputImage, ComplexOutputImage and OutputVectorData store the name of the files
to write, but they also encapsulate the corresponding writers.
In order to compile your application you must call the macro OTB_CREATE_APPLICATION in the
CMakelists.txt file. This macro generates the lib otbapp_XXX.so, in (OTB_BINARY_DIR), where XXX
refers to the class name. Don’t forget to enable application building (see. ?? section).
their are different ways to launch applicatons :
-
CommandLine :
- The command line option is
invoked using otbApplicationLauncherCommandLine executable followed by the classname,
the application dir and the application parameters.
-
QT :
- Application can be encapsuled in Qt framework using otbApplicationLauncherQt executable
followed by the classname and the application dir.
-
Python :
- A Python wrapper is also available.
It is possible to write application tests. They are quite similar to filters tests. The macro
OTB_TEST_APPLICATION makes it easy to define a new test.
The source code for this example can be found in the file
Examples/Application/ApplicationExample.cxx.
This example illustrates the creation of an application. A new application is a class, which
derives from otb::Wrapper::Application class. We start by including the needed header
files.
#include "otbWrapperApplication.h" #include "otbWrapperApplicationFactory.h"
Application class is defined in Wrapper namespace.
ExampleApplication class is derived from Application class.
class ApplicationExample : public Application
Class declaration is followed by ITK public types for the class, the superclass and smart pointers.
typedef ApplicationExample Self; typedef Application Superclass; typedef itk::SmartPointer<Self> Pointer; typedef itk::SmartPointer<const Self> ConstPointer;
Following macros are necessary to respect ITK object factory mechanisms. Please report to 29.5 for
additional information.
itkNewMacro(Self) ; itkTypeMacro(ExampleApplication, otb::Application) ;
otb::Application relies on three main private methods: DoInit(), DoUpdate(), and DoExecute().
Section 31.2 gives a description a these methods. DoInit() method contains class information and
description, parameter set up, and example values. Application name and description are set using following
methods :
-
SetName()
- Name of the application.
-
SetDescription()
- Set the short description of the class.
-
SetDocName()
- Set long name of the application (that can be displayed …).
-
SetDocLongDescription()
- This methods is used to describe the class.
-
SetDocLimitations()
- Set known limitations (threading, invalid pixel type …) or bugs.
-
SetDocAuthors()
- Set the application Authors. Author List. Format : ”John Doe, Winnie the
Pooh” …
-
SetDocSeeAlso()
- If the application is related to one another, it can be mentioned.
SetName("Example"); SetDescription("This application opens an image and save it. " "Pay attention, it includes Latex snippets in order to generate " "software guide documentation"); SetDocName("Example"); SetDocLongDescription("The purpose of this application is " "to present parameters types," " and Application class framework. " "It is used to generate Software guide documentation" " for Application chapter example."); SetDocLimitations("None"); SetDocAuthors("OTB-Team"); SetDocSeeAlso(" ");
AddDocTag() method categorize the application using relevant tags. Code/ApplicationEngine/otbWrapperTags.h
contains some predefined tags defined in Tags namespace.
AddDocTag(Tags::Analysis); AddDocTag("Test");
Application parameters declaration is done using AddParameter() method. AddParameter() requires
Parameter type, its name and description. otb::Wrapper::Application class contains methods to set
parameters characteristics.
AddParameter(ParameterType_InputImage, "in", "Input Image"); AddParameter(ParameterType_OutputImage, "out", "Output Image"); AddParameter(ParameterType_Empty, "boolean", "Boolean"); MandatoryOff("boolean"); AddParameter(ParameterType_Int, "int", "Integer"); MandatoryOff("int"); SetDefaultParameterInt("int", 1); SetMinimumParameterIntValue("int", 0); SetMaximumParameterIntValue("int", 10); AddParameter(ParameterType_Float, "float", "Float"); MandatoryOff("float"); SetDefaultParameterFloat("float", 0.2); SetMinimumParameterFloatValue("float", -1.0); SetMaximumParameterFloatValue("float", 15.0); AddParameter(ParameterType_String, "string", "String"); MandatoryOff("string"); AddParameter(ParameterType_InputFilename, "filename", "File name"); MandatoryOff("filename"); AddParameter(ParameterType_Directory, "directory", "Directory name"); MandatoryOff("directory"); AddParameter(ParameterType_Choice, "choice", "Choice"); AddChoice("choice.choice1", "Choice 1"); AddChoice("choice.choice2", "Choice 2"); AddChoice("choice.choice3", "Choice 3"); AddParameter(ParameterType_Float, "choice.choice1.floatchoice1" , "Float of choice1"); SetDefaultParameterFloat("choice.choice1.floatchoice1", 0.125); AddParameter(ParameterType_Float, "choice.choice3.floatchoice3" , "Float of choice3"); SetDefaultParameterFloat("choice.choice3.floatchoice3", 5.0); AddParameter(ParameterType_Group, "ingroup", "Input Group"); MandatoryOff("ingroup"); AddParameter(ParameterType_Int, "ingroup.integer", "Integer of Group"); MandatoryOff("ingroup.integer"); AddParameter(ParameterType_Group, "ingroup.images", "Input Images Group"); AddParameter(ParameterType_InputImage, "ingroup.images.inputimage" , "Input Image"); MandatoryOff("ingroup.images.inputimage"); AddParameter(ParameterType_Group, "outgroup", "Output Group"); MandatoryOff("outgroup"); AddParameter(ParameterType_OutputImage, "outgroup.outputimage" , "Output Image"); MandatoryOff("outgroup.outputimage"); AddParameter(ParameterType_InputImageList, "il", "Input image list"); MandatoryOff("il"); AddParameter(ParameterType_ListView, "cl", "Output Image channels"); AddChoice("cl.choice1", "cl.choice1"); AddChoice("cl.choice2", "cl.choice2"); MandatoryOff("cl"); AddParameter(ParameterType_RAM, "ram", "Available RAM"); SetDefaultParameterInt("ram", 256); MandatoryOff("ram"); AddParameter(ParameterType_ComplexInputImage, "cin", "Input Complex Image"); AddParameter(ParameterType_ComplexOutputImage, "cout", "Output Complex Image"); MandatoryOff("cin"); MandatoryOff("cout");
An example commandline is automatically generated. Method SetDocExampleParameterValue() is used
to set parameters. Dataset should be located in OTB-Data/Examples directory.
SetDocExampleParameterValue("boolean", "true"); SetDocExampleParameterValue("in", "QB_Suburb.png"); SetDocExampleParameterValue("out", "Application_Example.png");
DoUpdateParameters() is called as soon as a parameter value change. Section 31.2.2 gives a complete
description of this method.
void DoUpdateParameters() ITK_OVERRIDE { }
DoExecute() contains the application core. Section 31.2.3 gives a complete description of this method.
void DoExecute() ITK_OVERRIDE { FloatVectorImageType::Pointer inImage = GetParameterImage("in"); int paramInt = GetParameterInt("int"); otbAppLogDEBUG( << paramInt <<std::endl ); int paramFloat = GetParameterFloat("float"); otbAppLogINFO( << paramFloat ); SetParameterOutputImage("out", inImage); }
Finally OTB_APPLICATION_EXPORT is called.
OTB_APPLICATION_EXPORT(otb::Wrapper::ApplicationExample)