diff --git a/Documentation/Cookbook/Art/C++/CompositeExamplePipeline.png b/Documentation/Cookbook/Art/C++/CompositeExamplePipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..8e27d3901b4f22a5ccb183abe15e8fb0fda962a8 Binary files /dev/null and b/Documentation/Cookbook/Art/C++/CompositeExamplePipeline.png differ diff --git a/Documentation/Cookbook/Art/C++/CompositeFilterStages.png b/Documentation/Cookbook/Art/C++/CompositeFilterStages.png new file mode 100644 index 0000000000000000000000000000000000000000..776c86e88647dbac299ffddbbba9973e74eb7e30 Binary files /dev/null and b/Documentation/Cookbook/Art/C++/CompositeFilterStages.png differ diff --git a/Documentation/Cookbook/Art/C++/DataPipeline.png b/Documentation/Cookbook/Art/C++/DataPipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..904402e6373b688cb31486632d38147039251b0a Binary files /dev/null and b/Documentation/Cookbook/Art/C++/DataPipeline.png differ diff --git a/Documentation/Cookbook/Art/C++/DataPipelineOneConnection.png b/Documentation/Cookbook/Art/C++/DataPipelineOneConnection.png new file mode 100644 index 0000000000000000000000000000000000000000..7c919ad3fad0664a75560bee9268948507cd3d1a Binary files /dev/null and b/Documentation/Cookbook/Art/C++/DataPipelineOneConnection.png differ diff --git a/Documentation/Cookbook/Art/C++/DataPipelineUpdate.png b/Documentation/Cookbook/Art/C++/DataPipelineUpdate.png new file mode 100644 index 0000000000000000000000000000000000000000..5031190104951ff6670448d73689bfcdda51189e Binary files /dev/null and b/Documentation/Cookbook/Art/C++/DataPipelineUpdate.png differ diff --git a/Documentation/Cookbook/Art/C++/IteratorFigure1.png b/Documentation/Cookbook/Art/C++/IteratorFigure1.png new file mode 100644 index 0000000000000000000000000000000000000000..15467337fdb04ec4bbeb333cf5bba5f405151100 Binary files /dev/null and b/Documentation/Cookbook/Art/C++/IteratorFigure1.png differ diff --git a/Documentation/Cookbook/Art/C++/NeighborhoodIteratorFig1.png b/Documentation/Cookbook/Art/C++/NeighborhoodIteratorFig1.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e5bd58dfd2207b06a2ab90fea2c69c94bfb6f5 Binary files /dev/null and b/Documentation/Cookbook/Art/C++/NeighborhoodIteratorFig1.png differ diff --git a/Documentation/Cookbook/Art/C++/NeighborhoodIteratorFig2.png b/Documentation/Cookbook/Art/C++/NeighborhoodIteratorFig2.png new file mode 100644 index 0000000000000000000000000000000000000000..7aaa43dc3bae0efcf42364cbee3a5ea48f78bc4d Binary files /dev/null and b/Documentation/Cookbook/Art/C++/NeighborhoodIteratorFig2.png differ diff --git a/Documentation/Cookbook/Scripts/migrate_sg_tex.py b/Documentation/Cookbook/Scripts/migrate_sg_tex.py new file mode 100644 index 0000000000000000000000000000000000000000..a4faa2d1aca5836ac2fd5afea499e4f7eedce2dc --- /dev/null +++ b/Documentation/Cookbook/Scripts/migrate_sg_tex.py @@ -0,0 +1,62 @@ +import argparse +import re +import os +import os.path +from os.path import join +import subprocess + +def sed(content, regex, repl): + return re.sub(regex, repl, content, flags = re.MULTILINE | re.DOTALL) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(usage="migrate sg tex file") + parser.add_argument("filename", help="") + parser.add_argument("output_dir", help="") + args = parser.parse_args() + + input = args.filename + output = join(args.output_dir, os.path.basename(args.filename).replace(".tex", ".rst")) + + content = open(input).read() + + content = sed(content, + r"\\doxygen\{otb\}\{(.*?)\}", + r":doxygen:`\1`") + + content = sed(content, + r"\\doxygen\{itk\}\{(.*?)\}", + r":doxygen-itk:`\1`") + + content = sed(content, + r"\\code\{(.*?)\}", + r"\\texttt{\1}") + + content = sed(content, + r"cmakecode", + r"verbatim") + + content = sed(content, + r"cppcode", + r"verbatim") + + content = sed(content, + r"\\input\{(.*?)\}", + r"See example :ref:`\1`") + + content = sed(content, + r"\\input (\w+)\n", + r"See example \1\n") + + content = sed(content, + r"\\begin\{figure\}", + r"\\begin{verbatim}\\begin{figure}") + + content = sed(content, + r"\\end\{figure\}", + r"\\end{figure}\\end{verbatim}") + + open(output, "w").write(content) + + subprocess.check_call("pandoc -f latex -t rst -o {} {}".format(output, output), shell=True) + subprocess.check_call(['sed', '-i', "s ‘ ` g", output]) + print(output) diff --git a/Documentation/Cookbook/Scripts/otbGenerateExamplesRstDoc.py b/Documentation/Cookbook/Scripts/otbGenerateExamplesRstDoc.py index 934c0e7ba3b25d9eb891f5d91d5e17a1178955d4..025f836a857e2b0017b8142265bdcc9d1c78d693 100644 --- a/Documentation/Cookbook/Scripts/otbGenerateExamplesRstDoc.py +++ b/Documentation/Cookbook/Scripts/otbGenerateExamplesRstDoc.py @@ -95,9 +95,10 @@ def render_example(filename, otb_root): rst_description = "" # Render the template + name = os.path.basename(filename) template_example = open("templates/example.rst").read() output_rst = template_example.format( - label="example-" + root, + label=name, heading=rst_section(name, "="), description=rst_description, usage=example_usage, @@ -108,7 +109,7 @@ def render_example(filename, otb_root): return output_rst -if __name__ == "__main__": +def main(): parser = argparse.ArgumentParser(usage="Export examples to rst") parser.add_argument("rst_dir", help="Directory where rst files are generated") parser.add_argument("otb_root", help="OTB repository root") @@ -130,3 +131,6 @@ if __name__ == "__main__": os.makedirs(join(args.rst_dir, "C++", "Examples", tag), exist_ok=True) with open(join(args.rst_dir, "C++", "Examples", tag, root + ".rst"), "w") as output_file: output_file.write(render_example(filename, args.otb_root)) + +if __name__ == "__main__": + main() diff --git a/Documentation/Cookbook/Scripts/otbGenerateWrappersRstDoc.py b/Documentation/Cookbook/Scripts/otbGenerateWrappersRstDoc.py index c6c0cc4fb9dd59c630dfd8e97ecaea3e1d518978..e8f486fedf994dc665e518a7e501dc560d56c4d8 100755 --- a/Documentation/Cookbook/Scripts/otbGenerateWrappersRstDoc.py +++ b/Documentation/Cookbook/Scripts/otbGenerateWrappersRstDoc.py @@ -360,7 +360,7 @@ def multireplace(string, replacements): def make_links(text, allapps): "Replace name of applications by internal rst links" - rep = {appname: ":ref:`{}`".format("app-" + appname) for appname in allapps} + rep = {appname: ":ref:`{}`".format(appname) for appname in allapps} return multireplace(text, rep) def render_application(appname, allapps): @@ -374,7 +374,7 @@ def render_application(appname, allapps): application_documentation_warnings(app) output = template_application.format( - label="app-" + appname, + label=appname, heading=rst_section(app.GetName(), '='), description=app.GetDescription(), longdescription=make_links(app.GetDocLongDescription(), allapps), diff --git a/Documentation/Cookbook/rst/C++.rst b/Documentation/Cookbook/rst/C++.rst index 4898c812bd869d8071324cd0722276e9b1e1d7a8..5f9ceed4be7819e8471e9c57a2b8bb15b60a3875 100644 --- a/Documentation/Cookbook/rst/C++.rst +++ b/Documentation/Cookbook/rst/C++.rst @@ -4,5 +4,14 @@ C++ API ======= .. toctree:: + :maxdepth: 2 + C++/SystemOverview.rst + C++/Tutorial.rst + C++/Iterators.rst + C++/Filters.rst + C++/StreamingAndThreading.rst + C++/PersistentFilters.rst + C++/WriteAnApplication.rst + C++/AddingNewModules.rst C++/Examples.rst diff --git a/Documentation/Cookbook/rst/C++/AddingNewModules.rst b/Documentation/Cookbook/rst/C++/AddingNewModules.rst new file mode 100644 index 0000000000000000000000000000000000000000..36dbdcb2c0c2d57299358e7b50d2dacb5948a877 --- /dev/null +++ b/Documentation/Cookbook/rst/C++/AddingNewModules.rst @@ -0,0 +1,326 @@ +Adding New Modules +================== + +This chapter is concerned with the creation of new modules. The +following sections give precise instructions about: + +- the organization of directories + +- the included files + +- what they must contain + +- ... + +How to Write a Module +--------------------- + +There is a template of OTB remote module which help you start developing +a remote module: `External Module +Template <https://gitlab.orfeo-toolbox.org/remote_modules/remote-module-template>`__. + +Each module is made of different components, described in the +following sections. + +The otb-module.cmake file +------------------------- + +This file is mandatory. It follows the CMake syntax, and has two +purposes: + +- Declare dependencies to other modules, + +- Provide a short description of the module purpose. + +These purposes are fulfilled by a single CMake Macro call: + +.. code-block:: cmake + + otb_module(TheModuleName DEPENDS OTBModule1 OTBModule2 ... OTBModuleN DESCRIPTION "A description string") + +**Note**: You can use the keyword ``TESTDEPENDS`` to declare module +dependencies that only applies to the tests. + +The CMakeLists.txt file +----------------------- + +The ``CMakeLists.txt`` file is mandatory. It contains only a few things. +First, it declares a new CMake project with the name of the module: + +.. code-block:: cmake + + project(TheModuleName) + +Second, if the module contain a library (see src folder section below), +it initializes the TheModuleNameLIBRARIES CMake variable (if your module +only contains headers or template code, skip this line): + +.. code-block:: cmake + + set(TheModuleName_LIBRARIES OTBTheModuleName) + +You can build your remote modules inside the OTB source tree by copying +your source inside the directory ``Module/Remote`` or against an existing +OTB build tree (note that it does not work with an install version of +OTB). + +The configuration below will handle both cases and take care of all the +CMake plumbing of the module: + +.. code-block:: cmake + + if(NOT OTB_SOURCE_DIR) + find_package(OTB REQUIRED) + list(APPEND CMAKE_MODULE_PATH ${OTB_CMAKE_DIR}) + include(OTBModuleExternal) + else() + otb_module_impl() + endif() + +The overall file should look like this: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 2.8.9) + project(TheModuleName) + set(ExternalTemplate_LIBRARIES OTBTheModuleName) + + if(NOT OTB_SOURCE_DIR) + find_package(OTB REQUIRED) + list(APPEND CMAKE_MODULE_PATH ${OTB_CMAKE_DIR}) + include(OTBModuleExternal) + else() + otb_module_impl() + endif() + +The include folder +------------------ + +The include folder will contain all your headers (``*.h`` files) and +template method files (``*.hxx`` or ``*.hxx``). It does not require any +additional file (in particular, no CMakeLists.txt file is required). + +The src folder +-------------- + +The src folder contains the internal implementation of your module: + +- It typically contains cxx source files that will be compiled into a + library. + +- It can contain header files for classes used only within the + implementation files of your module. Any header file present in the + src folder will not be installed, and will not be available to other + modules depending on your module. + +If your modules is made of template only code, you do not need a src +folder at all. + +If present, the src folder requires a CMakeLists.txt file. + +The first part of the CMakeLists.txt file is classical, as it builds the +library and links it: + +.. code-block:: cmake + + set(OTBTheModuleName_SRC + sourceFile1.cxx + sourceFile2.cxx + sourceFile3.cxx + ... + sourceFileN.cxx) + + add_library(OTBTheModuleName ${OTBTheModuleName_SRC}) + + target_link_libraries(OTBTheModuleName ${OTBModule1_LIBRARIES} ${OTBModule2_LIBRARIES} ... ${OTBModuleN_LIBRARIES}) + +**Notes**: + +- Library name should match the one declared in the root CMakeLists.txt + when setting CMake variable TheModuleNameLIBRARIES, + +- Linked libraries should match the dependencies of your module + declared in the root otb-module.cmake file. + +The last line of CMake code takes care of installation instructions: + +.. code-block:: cmake + + otb_module_target(TBTheModuleName) + +The overall CMakeLists.txt file should look like: + +.. code-block:: cmake + + set(OTBTheModuleName_SRC + sourceFile1.cxx + sourceFile2.cxx + sourceFile3.cxx + ... + sourceFileN.cxx) + + add_library(OTBTheModuleName ${OTBTheModuleName_SRC}) + + target_link_libraries(OTBTheModuleName ${OTBModule1_LIBRARIES} ${OTBModule2_LIBRARIES} ... ${OTBModuleN_LIBRARIES}) + + otb_module_target(TBTheModuleName) + +The app folder +-------------- + +The app folder contains the code of applications shipped with your +module. If your module has no application, you do not need the app +folder. + +**Notes**: If your module contains application (and an app folder), do +not forget to add the ApplicationEngine in the dependencies listed in +the otb-module.cmake file. + +In addition to the applications source code, the app folder should +contain a CMakeLists.txt file as follows. + +For each application, a single call otbcreateapplication is required: + +.. code-block:: cmake + + otb_create_application( + NAME TheModuleApplication1 + SOURCES TheModuleApplication1.cxx + LINK_LIBRARIES ${OTBModule1_LIBRARIES} ${OTBModule2_LIBRARIES} ... ${OTBModuleN_LIBRARIES}) + +The test folder +--------------- + +This folder contains tests of the module. If your module has no test in +it (which is not recommended, you do not need it). + +The test folder should contain the source files of tests, as well as a +CMakeLists.txt file. This file will contain the following. + +First, indicate that this folder contains tests. + +.. code-block:: cmake + + otb_module_test() + +Then, build the test driver: + +.. code-block:: cmake + + set(OTBTheModuleNameTests + testFile1.cxx + testFile2.cxx + ... + testFileN.cxx) + + add_executable(otbTheModuleNameTestDriver ${OTBTheModuleNameTests}) + + target_link_libraries(otbTheModuleNameTestDriver ${OTBTheModuleName-Test_LIBRARIES}) + + otb_module_target_label(otbTheModuleNameTestDriver) + +Finally, you can add your tests: + +.. code-block:: cmake + + otb_add_test(NAME nameOfTheTest COMMAND otbTheModuleNameTestDriver + --compare-image ${EPSILON_8} ... # baseline comparison if needed + nameOfTheTestFunction + testParameters) + +If your module contains one or more application in the app folder, you +should also write tests for them, in the test folder. Running an +application test is easily done with the helper macro +otbtestapplication: + +.. code-block:: cmake + + otb_test_application(NAME nameofApplication1Test1 + APP TheModuleApplication1 + OPTIONS -in1 ${INPUTDATA}/input1.tif + -in2 ${INPUTDATA}/input2.tif + -out ${TEMP}/nameofApplication1Test1_result.tif + VALID --compare-image ${EPSILON_8} + ${BASELINE}/nameofApplication1Test1_result.tif + ${TEMP}/nameofApplication1Test1_result.tif) + +Overall CMakeLists.txt should look like: + +.. code-block:: cmake + + otb_module_test() + + set(OTBTheModuleNameTests + testFile1.cxx + testFile2.cxx + ... + testFileN.cxx) + + add_executable(otbTheModuleNameTestDriver ${OTBTheModuleNameTests}) + + target_link_libraries(otbTheModuleNameTestDriver ${OTBTheModuleName-Test_LIBRARIES}) + + otb_module_target_label(otbTheModuleNameTestDriver) + + otb_add_test(NAME nameOfTheTest COMMAND otbTheModuleNameTestDriver + --compare-image ${EPSILON_8} ... # baseline comparison if needed + nameOfTheTestFunction + testParameters) + +Including a remote module in OTB +-------------------------------- + +* Local build of a remote module + +Your remote module can be build inside the OTB source tree or outside as +a external CMake project with an existing OTB. Please note in that case +that you’ll have to set OTBDIR CMake option. + +If OTBDIR is an OTB build tree, there are two ways of compiling: + +- Build as a module, in which case build files will be written to the + OTB build tree as other modules. Main benefit is that this will + enrich the current OTB build with your new module, but you need to + have write access to the build directory. + +- Build as a standalone CMake project, in which case build files will + remain in the module build folder. This build is fully independent + from the build (or install) directory, but the module will not be + recognized as an OTB module (still you will be able to use its + binaries and libraries). + +This behaviour is controlled by the ``OTB_BUILD_MODULE_AS_STANDALONE``, which is +OFF by default (hence first behaviour). + +Note that when dealing with an installed OTB, only the second behaviour +(build as standalone) is available. + +Optionally, you can build your new remote module inside the OTB source +tree by simply copy the folder containing the module component to +Modules/Remote, then run CMake configuration. you should see a new CMake +option named MODULETheModuleName. Simply turn this option to ON, and +finish CMake configuration. Your module will be built with the rest of +the OTB project. + +* Sharing your remote module + +To make your remote module available to others when building OTB, you +should provide a CMake file named TheModuleName.remote.cmake file for +inclusion in the Modules/Remote folder in OTB source tree. + +This file should contain the following: + +.. code-block:: cmake + + # Contact: Author name <author email address> + + otb_fetch_module(TheModuleName + "A description of the module, to appear during CMake configuration step" + + GIT_REPOSITORY http_link_to_a_git_repository_hosting the module + GIT TAG the git revision to checkout + ) + +This file should be provided along with your remote module inclusion +proposal email to the otb community list. Please refer to the +contributors guidelines for more information. diff --git a/Documentation/Cookbook/rst/C++/Filters.rst b/Documentation/Cookbook/rst/C++/Filters.rst new file mode 100644 index 0000000000000000000000000000000000000000..9345cac93536a818c649f8049721fca6b4b9e981 --- /dev/null +++ b/Documentation/Cookbook/rst/C++/Filters.rst @@ -0,0 +1,589 @@ +.. _Filters: + +Filters +======= + +This purpose of this chapter is help developers create their own filter +(process object). This chapter is divided into four major parts. An +initial definition of terms is followed by an overview of the filter +creation process. Next, data streaming is discussed. The way data is +streamed in ITK must be understood in order to write correct filters. +Finally, a section on multithreading describes what you must do in order +to take advantage of shared memory parallel processing. + +Terminology +----------- + +The following is some basic terminology for the discussion that follows. +Chapter :ref:`SystemOverview` provides additional background +information. + +- The **data processing pipeline** is a directed graph of **process** + and **data objects**. The pipeline inputs, operators on, and outputs + data. + +- A **filter**, or **process object**, has one or more inputs, and one + or more outputs. + +- A **source**, or source process object, initiates the data processing + pipeline, and has one or more outputs. + +- A **mapper**, or mapper process object, terminates the data + processing pipeline. The mapper has one or more outputs, and may + write data to disk, interface with a display system, or interface to + any other system. + +- A **data object** represents and provides access to data. In ITK, the + data object (ITK class :doxygen-itk:`DataObject`) is typically of + type :doxygen:`Image` or :doxygen-itk:`Mesh`. + +- A **region** (ITK class :doxygen-itk:`Region`) represents a piece, or + subset of the entire data set. + +- An **image region** (ITK class :doxygen-itk:`ImageRegion`) represents + a structured portion of data. ImageRegion is implemented using the + :doxygen-itk:`Index` and :doxygen-itk:`Size` classes + +- A **mesh region** (ITK class :doxygen-itk:`MeshRegion`) represents an + unstructured portion of data. + +- The **LargestPossibleRegion** is the theoretical single, largest + piece (region) that could represent the entire dataset. The + LargestPossibleRegion is used in the system as the measure of the + largest possible data size. + +- The **BufferedRegion** is a contiguous block of memory that is less + than or equal to in size to the LargestPossibleRegion. The buffered + region is what has actually been allocated by a filter to hold its + output. + +- The **RequestedRegion** is the piece of the dataset that a filter is + required to produce. The RequestedRegion is less than or equal in + size to the BufferedRegion. The RequestedRegion may differ in size + from the BufferedRegion due to performance reasons. The + RequestedRegion may be set by a user, or by an application that needs + just a portion of the data. + +- The **modified time** (represented by ITK class + :doxygen-itk:`TimeStamp`) is a monotonically increasing integer value + that characterizes a point in time when an object was last modified. + +- **Downstream** is the direction of dataflow, from sources to mappers. + +- **Upstream** is the opposite of downstream, from mappers to sources. + +- The **pipeline modified time** for a particular data object is the + maximum modified time of all upstream data objects and process + objects. + +- The term **information** refers to metadata that characterizes data. + For example, index and dimensions are information characterizing an + image region. + +Overview of Filter Creation +--------------------------- + +.. figure:: /Art/C++/DataPipelineOneConnection.png + :align: center + +Filters are defined with respect to the type of data they input (if +any), and the type of data they output (if any). The key to writing a +ITK filter is to identify the number and types of input and output. +Having done so, there are often superclasses that simplify this task via +class derivation. For example, most filters in ITK take a single image +as input, and produce a single image on output. The superclass +:doxygen-itk:`ImageToImageFilter` is a convenience class that provide +most of the functionality needed for such a filter. + +Some common base classes for new filters include: + +- ``ImageToImageFilter``: the most common filter base for segmentation + algorithms. Takes an image and produces a new image, by default of + the same dimensions. Override ``GenerateOutputInformation`` to + produce a different size. + +- ``UnaryFunctorImageFilter``: used when defining a filter that applies + a function to an image. + +- ``BinaryFunctorImageFilter``: used when defining a filter that + applies an operation to two images. + +- ``ImageFunction``: a functor that can be applied to an image, + evaluating :math:`f(x)` at each point in the image. + +- ``MeshToMeshFilter``: a filter that transforms meshes, such as + tessellation, polygon reduction, and so on. + +- ``LightObject``: abstract base for filters that don’t fit well + anywhere else in the class hierarchy. Also useful for “calculator” + filters; ie. a sink filter that takes an input and calculates a + result which is retrieved using a ``Get()`` method. + +Once the appropriate superclass is identified, the filter writer +implements the class defining the methods required by most all ITK +objects: ``New()``, ``PrintSelf()``, and protected constructor, copy +constructor, delete, and operator=, and so on. Also, don’t forget +standard typedefs like ``Self``, ``Superclass``, ``Pointer``, and +``ConstPointer``. Then the filter writer can focus on the most important +parts of the implementation: defining the API, data members, and other +implementation details of the algorithm. In particular, the filter +writer will have to implement either a ``GenerateData()`` (non-threaded) +or ``ThreadedGenerateData()`` method. (See Section [sec:MultiThreading] +for an overview of multi-threading in ITK.) + +An important note: the GenerateData() method is required to allocate +memory for the output. The ThreadedGenerateData() method is not. In +default implementation (see :doxygen-itk:`ImageSource`, a superclass of +:doxygen-itk:`ImageToImageFilter`) ``GenerateData()`` allocates memory +and then invokes ``ThreadedGenerateData()``. + +One of the most important decisions that the developer must make is +whether the filter can stream data; that is, process just a portion of +the input to produce a portion of the output. Often superclass behavior +works well: if the filter processes the input using single pixel access, +then the default behavior is adequate. If not, then the user may have to +a) find a more specialized superclass to derive from, or b) override one +or more methods that control how the filter operates during pipeline +execution. The next section describes these methods. + +.. _StreamingLargeData: + +Streaming Large Data +-------------------- + +The data associated with multi-dimensional images is large and becoming +larger. This trend is due to advances in scanning resolution, as well as +increases in computing capability. Any practical segmentation and +registration software system must address this fact in order to be +useful in application. ITK addresses this problem via its data streaming +facility. + +In ITK, streaming is the process of dividing data into pieces, or +regions, and then processing this data through the data pipeline. Recall +that the pipeline consists of process objects that generate data +objects, connected into a pipeline topology. The input to a process +object is a data object (unless the process initiates the pipeline and +then it is a source process object). These data objects in turn are +consumed by other process objects, and so on, until a directed graph of +data flow is constructed. Eventually the pipeline is terminated by one +or more mappers, that may write data to storage, or interface with a +graphics or other system. This is illustrated in figures +[fig:DataPipeLineOneConnection] and [fig:DataPipeLine]. + +A significant benefit of this architecture is that the relatively +complex process of managing pipeline execution is designed into the +system. This means that keeping the pipeline up to date, executing only +those portions of the pipeline that have changed, multithreading +execution, managing memory allocation, and streaming is all built into +the architecture. However, these features do introduce complexity into +the system, the bulk of which is seen by class developers. The purpose +of this chapter is to describe the pipeline execution process in detail, +with a focus on data streaming. + +Overview of Pipeline Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The pipeline execution process performs several important functions. + +.. figure:: /Art/C++/DataPipeline.png + :align: center + + The Data Pipeline + +#. It determines which filters, in a pipeline of filters, need to + execute. This prevents redundant execution and minimizes overall + execution time. + +#. It initializes the (filter’s) output data objects, preparing them for + new data. In addition, it determines how much memory each filter must + allocate for its output, and allocates it. + +#. The execution process determines how much data a filter must process + in order to produce an output of sufficient size for downstream + filters; it also takes into account any limits on memory or special + filter requirements. Other factors include the size of data + processing kernels, that affect how much data input data (extra + padding) is required. + +#. It subdivides data into subpieces for multithreading. (Note that the + division of data into subpieces is exactly same problem as dividing + data into pieces for streaming; hence multithreading comes for free + as part of the streaming architecture.) + +#. It may free (or release) output data if filters no longer need it to + compute, and the user requests that data is to be released. (Note: a + filter’s output data object may be considered a “cache”. If the cache + is allowed to remain (``ReleaseDataFlagOff()``) between pipeline + execution, and the filter, or the input to the filter, never changes, + then process objects downstream of the filter just reuse the filter’s + cache to re-execute.) + +To perform these functions, the execution process negotiates with the +filters that define the pipeline. Only each filter can know how much +data is required on input to produce a particular output. For example, a +shrink filter with a shrink factor of two requires an image twice as +large (in terms of its x-y dimensions) on input to produce a particular +size output. An image convolution filter would require extra input +(boundary padding) depending on the size of the convolution kernel. Some +filters require the entire input to produce an output (for example, a +histogram), and have the option of requesting the entire input. (In this +case streaming does not work unless the developer creates a filter that +can request multiple pieces, caching state between each piece to +assemble the final output.) + +.. figure:: /Art/C++/DataPipelineUpdate.png + :align: center + + Sequence of the Data Pipeline updating mechanism + +Ultimately the negotiation process is controlled by the request for data +of a particular size (i.e., region). It may be that the user asks to +process a region of interest within a large image, or that memory +limitations result in processing the data in several pieces. For +example, an application may compute the memory required by a pipeline, +and then use :doxygen-itk:`StreamingImageFilter` to break the data +processing into several pieces. The data request is propagated through +the pipeline in the upstream direction, and the negotiation process +configures each filter to produce output data of a particular size. + +The secret to creating a streaming filter is to understand how this +negotiation process works, and how to override its default behavior by +using the appropriate virtual functions defined in +:doxygen-itk:`ProcessObject`. The next section describes the specifics +of these methods, and when to override them. Examples are provided along +the way to illustrate concepts. + +Details of Pipeline Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Typically pipeline execution is initiated when a process object receives +the ``ProcessObject::Update()`` method invocation. This method is simply +delegated to the output of the filter, invoking the +``DataObject::Update()`` method. Note that this behavior is typical of +the interaction between ProcessObject and DataObject: a method invoked +on one is eventually delegated to the other. In this way the data +request from the pipeline is propagated upstream, initiating data flow +that returns downstream. + +The ``DataObject::Update()`` method in turn invokes three other methods: + +- ``DataObject::UpdateOutputInformation()`` + +- ``DataObject::PropagateRequestedRegion()`` + +- ``DataObject::UpdateOutputData()`` + +UpdateOutputInformation() +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``UpdateOutputInformation()`` method determines the pipeline +modified time. It may set the RequestedRegion and the +LargestPossibleRegion depending on how the filters are configured. (The +RequestedRegion is set to process all the data, i.e., the +LargestPossibleRegion, if it has not been set.) The +UpdateOutputInformation() propagates upstream through the entire +pipeline and terminates at the sources. + +During ``UpdateOutputInformation()``, filters have a chance to override +the ``ProcessObject::GenerateOutputInformation()`` method +(``GenerateOutputInformation()`` is invoked by +``UpdateOutputInformation()``). The default behavior is for the +``GenerateOutputInformation()`` to copy the metadata describing the +input to the output (via ``DataObject::CopyInformation()``). Remember, +information is metadata describing the output, such as the origin, +spacing, and LargestPossibleRegion (i.e., largest possible size) of an +image. + +A good example of this behavior is :doxygen-itk:`ShrinkImageFilter`. +This filter takes an input image and shrinks it by some integral value. +The result is that the spacing and LargestPossibleRegion of the output +will be different to that of the input. Thus, +``GenerateOutputInformation()`` is overloaded. + +PropagateRequestedRegion() +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``PropagateRequestedRegion()`` call propagates upstream to satisfy a +data request. In typical application this data request is usually the +LargestPossibleRegion, but if streaming is necessary, or the user is +interested in updating just a portion of the data, the RequestedRegion +may be any valid region within the LargestPossibleRegion. + +The function of ``PropagateRequestedRegion()`` is, given a request for +data (the amount is specified by RequestedRegion), propagate upstream +configuring the filter’s input and output process object’s to the +correct size. Eventually, this means configuring the BufferedRegion, +that is the amount of data actually allocated. + +The reason for the buffered region is this: the output of a filter may +be consumed by more than one downstream filter. If these consumers each +request different amounts of input (say due to kernel requirements or +other padding needs), then the upstream, generating filter produces the +data to satisfy both consumers, that may mean it produces more data than +one of the consumers needs. + +The ``ProcessObject::PropagateRequestedRegion()`` method invokes three +methods that the filter developer may choose to overload. + +- ``EnlargeOutputRequestedRegion(DataObject *output)`` gives the + (filter) subclass a chance to indicate that it will provide more data + than required for the output. This can happen, for example, when a + source can only produce the whole output (i.e., the + LargestPossibleRegion). + +- ``GenerateOutputRequestedRegion(DataObject *output)`` gives the + subclass a chance to define how to set the requested regions for each + of its outputs, given this output’s requested region. The default + implementation is to make all the output requested regions the same. + A subclass may need to override this method if each output is a + different resolution. This method is only overridden if a filter has + multiple outputs. + +- ``GenerateInputRequestedRegion()`` gives the subclass a chance to + request a larger requested region on the inputs. This is necessary + when, for example, a filter requires more data at the “internal” + boundaries to produce the boundary values - due to kernel operations + or other region boundary effects. + +:doxygen-itk:`RGBGibbsPriorFilter` is an example of a filter that needs +to invoke ``EnlargeOutputRequestedRegion()``. The designer of this +filter decided that the filter should operate on all the data. Note that +a subtle interplay between this method and +``GenerateInputRequestedRegion()`` is occurring here. The default +behavior of ``GenerateInputRequestedRegion()`` (at least for +:doxygen-itk:`ImageToImageFilter`) is to set the input RequestedRegion +to the output’s ReqestedRegion. Hence, by overriding the method +``EnlargeOutputRequestedRegion()`` to set the output to the +LargestPossibleRegion, effectively sets the input to this filter to the +LargestPossibleRegion (and probably causing all upstream filters to +process their LargestPossibleRegion as well. This means that the filter, +and therefore the pipeline, does not stream. This could be fixed by +reimplementing the filter with the notion of streaming built in to the +algorithm.) + +:doxygen-itk:`GradientMagnitudeImageFilter` is an example of a filter +that needs to invoke ``GenerateInputRequestedRegion()``. It needs a +larger input requested region because a kernel is required to compute +the gradient at a pixel. Hence the input needs to be “padded out” so the +filter has enough data to compute the gradient at each output pixel. + +UpdateOutputData() +^^^^^^^^^^^^^^^^^^ + +``UpdateOutputData()`` is the third and final method as a result of the +``Update()`` method. The purpose of this method is to determine whether +a particular filter needs to execute in order to bring its output up to +date. (A filter executes when its ``GenerateData()`` method is invoked.) +Filter execution occurs when a) the filter is modified as a result of +modifying an instance variable; b) the input to the filter changes; c) +the input data has been released; or d) an invalid RequestedRegion was +set previously and the filter did not produce data. Filters execute in +order in the downstream direction. Once a filter executes, all filters +downstream of it must also execute. + +``DataObject::UpdateOutputData()`` is delegated to the DataObject’s +source (i.e., the ProcessObject that generated it) only if the +DataObject needs to be updated. A comparison of modified time, pipeline +time, release data flag, and valid requested region is made. If any one +of these conditions indicate that the data needs regeneration, then the +source’s ``ProcessObject::UpdateOutputData()`` is invoked. These calls +are made recursively up the pipeline until a source filter object is +encountered, or the pipeline is determined to be up to date and valid. +At this point, the recursion unrolls, and the execution of the filter +proceeds. (This means that the output data is initialized, StartEvent is +invoked, the filters ``GenerateData()`` is called, EndEvent is invoked, +and input data to this filter may be released, if requested. In +addition, this filter’s InformationTime is updated to the current time.) + +The developer will never override ``UpdateOutputData()``. The developer +need only write the ``GenerateData()`` method (non-threaded) or +``ThreadedGenerateData()`` method. A discussion of threading follows in +the next section. + +.. _ThreadedFilterExecution: + +Threaded Filter Execution +------------------------- + +Filters that can process data in pieces can typically multi-process +using the data parallel, shared memory implementation built into the +pipeline execution process. To create a multithreaded filter, simply +define and implement a ``ThreadedGenerateData()`` method. For example, a +:doxygen-itk:`ImageToImageFilter` would create the method: + +.. code-block:: cpp + + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) + +The key to threading is to generate output for the output region given +(as the first parameter in the argument list above). In ITK, this is +simple to do because an output iterator can be created using the region +provided. Hence the output can be iterated over, accessing the +corresponding input pixels as necessary to compute the value of the +output pixel. + +Multi-threading requires caution when performing I/O (including using +``cout`` or ``cerr``) or invoking events. A safe practice is to allow +only thread id zero to perform I/O or generate events. (The thread id is +passed as argument into ``ThreadedGenerateData()``). If more than one +thread tries to write to the same place at the same time, the program +can behave badly, and possibly even deadlock or crash. + +Filter Conventions +------------------ + +In order to fully participate in the ITK pipeline, filters are expected +to follow certain conventions, and provide certain interfaces. This +section describes the minimum requirements for a filter to integrate +into the ITK framework. + +The class declaration for a filter should include the macro +``ITK_EXPORT``, so that on certain platforms an export declaration can +be included. + +A filter should define public types for the class itself (``Self``) and +its ``Superclass``, and ``const`` and non-\ ``const`` smart pointers, +thus: + +.. code-block:: cpp + + typedef ExampleImageFilter Self; + typedef ImageToImageFilter<TImage,TImage> Superclass; + typedef SmartPointer<Self> Pointer; + typedef SmartPointer<const Self> ConstPointer; + +The ``Pointer`` type is particularly useful, as it is a smart pointer +that will be used by all client code to hold a reference-counted +instantiation of the filter. + +Once the above types have been defined, you can use the following +convenience macros, which permit your filter to participate in the +object factory mechanism, and to be created using the canonical +``::New()``: + +.. code-block:: cpp + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ExampleImageFilter, ImageToImageFilter); + +The default constructor should be ``protected``, and provide sensible +defaults (usually zero) for all parameters. The copy constructor and +assignment operator should be declared ``private`` and not implemented, +to prevent instantiating the filter without the factory methods (above). + +Finally, the template implementation code (in the ``.hxx`` file) should +be included, bracketed by a test for manual instantiation, thus: + +.. code-block:: cpp + + #ifndef ITK_MANUAL_INSTANTIATION + #include "itkExampleFilter.hxx" + #endif + +Optional +~~~~~~~~ + +A filter can be printed to an ``std::ostream`` (such as ``std::cout``) +by implementing the following method: + +.. code-block:: cpp + + void PrintSelf(std::ostream& os, Indent indent) const; + +and writing the name-value pairs of the filter parameters to the +supplied output stream. This is particularly useful for debugging. + +Useful Macros +~~~~~~~~~~~~~ + +Many convenience macros are provided by ITK, to simplify filter coding. +Some of these are described below: + +itkStaticConstMacro + Declares a static variable of the given type, with the specified + initial value. + +itkGetMacro + Defines an accessor method for the specified scalar data member. The + convention is for data members to have a prefix of ``m_``. + +itkSetMacro + Defines a mutator method for the specified scalar data member, of + the supplied type. This will automatically set the ``Modified`` + flag, so the filter stage will be executed on the next ``Update()``. + +itkBooleanMacro + Defines a pair of ``OnFlag`` and ``OffFlag`` methods for a boolean + variable ``m_Flag``. + +itkGetObjectMacro, itkSetObjectMacro + Defines an accessor and mutator for an ITK object. The Get form + returns a smart pointer to the object. + +Much more useful information can be learned from browsing the source in +``Code/Common/itkMacro.h`` and for the :doxygen-itk:`Object` and +:doxygen-itk:`LightObject` classes. + +Composite filters +----------------- + +In general, most ITK/OTB filters implement one particular algorithm, +whether it be image filtering, an information metric, or a segmentation +algorithm. In the previous section, we saw how to write new filters from +scratch. However, it is often very useful to be able to make a new +filter by combining two or more existing filters, which can then be used +as a building block in a complex pipeline. This approach follows the +Composite pattern, whereby the composite +filter itself behaves just as a regular filter, providing its own +(potentially higher level) interface and using other filters (whose +detail is hidden to users of the class) for the implementation. This +composite structure is shown in Figure [fig:CompositeFilterStages], +where the various ``Stage-n`` filters are combined into one by the +``Composite`` filter. The ``Source`` and ``Sink`` filters only see the +interface published by the ``Composite``. Using the Composite pattern, a +composite filter can encapsulate a pipeline of arbitrary complexity. +These can in turn be nested inside other pipelines. + +.. figure:: /Art/C++/CompositeFilterStages.png + :align: center + + A Composite filter encapsulates a number of other filters. + +There are a few considerations to take into account when implementing a +composite filter. All the usual requirements for filters apply (as +discussed above), but the following guidelines should be considered: + +#. The template arguments it takes must be sufficient to instantiate all + of the component filters. Each component filter needs a type supplied + by either the implementor or the enclosing class. For example, an + ``ImageToImageFilter`` normally takes an input and output image type + (which may be the same). But if the output of the composite filter is + a classified image, we need to either decide on the output type + inside the composite filter, or restrict the choices of the user when + she/he instantiates the filter. + +#. The types of the component filters should be declared in the header, + preferably with ``protected`` visibility. This is because the + internal structure normally should not be visible to users of the + class, but should be to descendent classes that may need to modify or + customize the behavior. + +#. The component filters should be private data members of the composite + class, as in ``FilterType::Pointer``. + +#. The default constructor should build the pipeline by creating the + stages and connect them together, along with any default parameter + settings, as appropriate. + +#. The input and output of the composite filter need to be grafted on to + the head and tail (respectively) of the component filters. + +.. figure:: /Art/C++/CompositeExamplePipeline.png + :align: center + + Example of a typical composite filter. Note that the output of the last filter in the internal pipeline must be grafted into the output of the composite filter. + +See example :ref:`CompositeFilterExample.cxx` diff --git a/Documentation/Cookbook/rst/C++/Iterators.rst b/Documentation/Cookbook/rst/C++/Iterators.rst new file mode 100644 index 0000000000000000000000000000000000000000..dc78ceb9047390cb85fe662f2af5e4be6d637251 --- /dev/null +++ b/Documentation/Cookbook/rst/C++/Iterators.rst @@ -0,0 +1,624 @@ +Iterators +========= + +This chapter introduces the *image iterator*, an important generic +programming construct for image processing in ITK. An iterator is a +generalization of the familiar C programming language pointer used to +reference data in memory. ITK has a wide variety of image iterators, +some of which are highly specialized to simplify common image processing +tasks. + +Introduction +------------ + +Generic programming models define functionally independent components +called *containers* and *algorithms*. Container objects store data and +algorithms operate on data. To access data in containers, algorithms use +a third class of objects called *iterators*. An iterator is an +abstraction of a memory pointer. Every container type must define its +own iterator type, but all iterators are written to provide a common +interface so that algorithm code can reference data in a generic way and +maintain functional independence from containers. + +The iterator is so named because it is used for *iterative*, sequential +access of container values. Iterators appear in ``for`` and ``while`` +loop constructs, visiting each data point in turn. A C pointer, for +example, is a type of iterator. It can be moved forward (incremented) +and backward (decremented) through memory to sequentially reference +elements of an array. Many iterator implementations have an interface +similar to a C pointer. + +In ITK we use iterators to write generic image processing code for +images instantiated with different combinations of pixel type, pixel +container type, and dimensionality. Because ITK image iterators are +specifically designed to work with *image* containers, their interface +and implementation is optimized for image processing tasks. Using the +ITK iterators instead of accessing data directly through the +:doxygen:`Image` interface has many advantages. Code is more compact and +often generalizes automatically to higher dimensions, algorithms run +much faster, and iterators simplify tasks such as multithreading and +neighborhood-based image processing. + +Programming Interface +--------------------- + +This section describes the standard ITK image iterator programming +interface. Some specialized image iterators may deviate from this +standard or provide additional methods. + +Creating Iterators +~~~~~~~~~~~~~~~~~~ + +All image iterators have at least one template parameter that is the +image type over which they iterate. There is no restriction on the +dimensionality of the image or on the pixel type of the image. + +An iterator constructor requires at least two arguments, a smart pointer +to the image to iterate across, and an image region. The image region, +called the *iteration region*, is a rectilinear area in which iteration +is constrained. The iteration region must be wholly contained within the +image. More specifically, a valid iteration region is any subregion of +the image within the current ``BufferedRegion``. + +There is a const and a non-const version of most ITK image iterators. A +non-const iterator cannot be instantiated on a non-const image pointer. +Const versions of iterators may read, but may not write pixel values. + +Here is a simple example that defines and constructs a simple image +iterator for an :doxygen:`Image`. + +.. code-block:: cpp + + typedef otb::Image<float, 3> ImageType; + typedef itk::ImageRegionConstIterator<ImageType> ConstIteratorType; + typedef itk::ImageRegionIterator<ImageType> IteratorType; + + ImageType::Pointer image = SomeFilter->GetOutput(); + + ConstIteratorType constIterator(image, image->GetRequestedRegion()); + IteratorType iterator(image, image->GetRequestedRegion()); + +Moving Iterators +~~~~~~~~~~~~~~~~ + +An iterator is described as *walking* its iteration region. At any time, +the iterator will reference, or “point to”, one pixel location in the +N-dimensional (ND) image. *Forward iteration* goes from the beginning of +the iteration region to the end of the iteration region. *Reverse +iteration*, goes from just past the end of the region back to the +beginning. There are two corresponding starting positions for iterators, +the *begin* position and the *end* position. An iterator can be moved +directly to either of these two positions using: + +- ``GoToBegin()`` Points the iterator to the first valid data + element in the region. + +- ``GoToEnd()`` Points the iterator to *one position past* the last + valid element in the region. + +Note that the end position is not actually located within the iteration +region. This is important to remember because attempting to dereference +an iterator at its end position will have undefined results. + +ITK iterators are moved back and forth across their iterations using the +decrement and increment operators: + +- ``operator++()`` Increments the iterator one position in the + positive direction. Only the prefix increment operator is defined for + ITK image iterators. + +- ``operator–()`` Decrements the iterator one position in the + negative direction. Only the prefix decrement operator is defined for + ITK image iterators. + +The figure below illustrates typical iteration over an image +region. Most iterators increment and decrement in the direction of the +fastest increasing image dimension, wrapping to the first position in +the next higher dimension at region boundaries. In other words, an +iterator first moves across columns, then down rows, then from slice to +slice, and so on. + +.. figure:: /Art/C++/IteratorFigure1.png + :align: center + + Normal path of an iterator through a + 2D image. The iteration region is shown in a darker shade. An arrow denotes + a single iterator step, the result of one ++ operation. + +In addition to sequential iteration through the image, some iterators +may define random access operators. Unlike the increment operators, +random access operators may not be optimized for speed and require some +knowledge of the dimensionality of the image and the extent of the +iteration region to use properly. + +- ``operator+=(OffsetType)`` Moves the iterator to the pixel + position at the current index plus specified :doxygen-itk:`Offset`. + +- ``operator-=(OffsetType)`` Moves the iterator to the pixel + position at the current index minus specified Offset. + +- ``SetPosition(IndexType)`` Moves the iterator to the given + :doxygen-itk:`Index` position. + +The ``SetPosition()`` method may be extremely slow for more complicated +iterator types. In general, it should only be used for setting a +starting iteration position, like you would use ``GoToBegin()`` or +``GoToEnd()``. + +Some iterators do not follow a predictable path through their iteration +regions and have no fixed beginning or ending pixel locations. A +conditional iterator, for example, visits pixels only if they have +certain values or connectivities. Random iterators, increment and +decrement to random locations and may even visit a given pixel location +more than once. + +An iterator can be queried to determine if it is at the end or the +beginning of its iteration region. + +- ``bool IsAtEnd()`` True if the iterator points to *one position + past* the end of the iteration region. + +- ``bool IsAtBegin()`` True if the iterator points to the first + position in the iteration region. The method is typically used to + test for the end of reverse iteration. + +An iterator can also report its current image index position. + +- ``IndexType GetIndex()`` Returns the Index of the image pixel + that the iterator currently points to. + +For efficiency, most ITK image iterators do not perform bounds checking. +It is possible to move an iterator outside of its valid iteration +region. Dereferencing an out-of-bounds iterator will produce undefined +results. + +Accessing Data +~~~~~~~~~~~~~~ + +ITK image iterators define two basic methods for reading and writing +pixel values. + +- ``PixelType Get()`` Returns the value of the pixel at the + iterator position. + +- ``void Set(PixelType)`` Sets the value of the pixel at the + iterator position. Not defined for const versions of iterators. + +The ``Get()`` and ``Set()`` methods are inlined and optimized for speed +so that their use is equivalent to dereferencing the image buffer +directly. There are a few common cases, however, where using ``Get()`` +and ``Set()`` do incur a penalty. Consider the following code, which +fetches, modifies, and then writes a value back to the same pixel +location: + +.. code-block:: cpp + + it.Set(it.Get() + 1); + +As written, this code requires one more memory dereference than is +necessary. Some iterators define a third data access method that avoids +this penalty. + +- ``PixelType & Value()`` Returns a reference to the pixel at the + iterator position. + +The ``Value()`` method can be used as either an lval or an rval in an +expression. It has all the properties of ``operator*``. The ``Value()`` +method makes it possible to rewrite our example code more efficiently: + +.. code-block:: cpp + + it.Value()++; + +Consider using the ``Value()`` method instead of ``Get()`` or ``Set()`` +when a call to ``operator=`` on a pixel is non-trivial, such as when +working with vector pixels, and operations are done in-place in the +image. + +Iteration Loops +~~~~~~~~~~~~~~~ + +Using the methods described in the previous sections, we can now write a +simple example to do pixel-wise operations on an image. The following +code calculates the squares of all values in an input image and writes +them to an output image. + +.. code-block:: cpp + + ConstIteratorType in(inputImage, inputImage->GetRequestedRegion()); + IteratorType out(outputImage, inputImage->GetRequestedRegion()); + + for (in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd(); ++in, ++out) + { + out.Set(in.Get() * in.Get()); + } + +Notice that both the input and output iterators are initialized over the +same region, the ``RequestedRegion`` of ``inputImage``. This is good +practice because it ensures that the output iterator walks exactly the +same set of pixel indices as the input iterator, but does not require +that the output and input be the same size. The only requirement is that +the input image must contain a region (a starting index and size) that +matches the ``RequestedRegion`` of the output image. + +Equivalent code can be written by iterating through the image in +reverse. The syntax is slightly more awkward because the *end* of the +iteration region is not a valid position and we can only test whether +the iterator is strictly *equal* to its beginning position. It is often +more convenient to write reverse iteration in a ``while`` loop. + +.. code-block:: cpp + + in.GoToEnd(); + out.GoToEnd(); + while (!in.IsAtBegin()) + { + --in; + --out; + out.Set(in.Get() * in.Get()); + } + +Image Iterators +--------------- + +This section describes iterators that walk rectilinear image regions and +reference a single pixel at a time. The +:doxygen-itk:`ImageRegionIterator` is the most basic ITK image iterator +and the first choice for most applications. The rest of the iterators in +this section are specializations of ImageRegionIterator that are +designed make common image processing tasks more efficient or easier to +implement. + +* ImageRegionIterator: See example :ref:`ImageRegionIterator.cxx` + +* ImageRegionIteratorWithIndex: See example :ref:`ImageRegionIteratorWithIndex.cxx` + +* ImageLinearIteratorWithIndex: See example :ref:`ImageLinearIteratorWithIndex.cxx` + +Neighborhood Iterators +---------------------- + +In ITK, a pixel neighborhood is loosely defined as a small set of pixels +that are locally adjacent to one another in an image. The size and shape +of a neighborhood, as well the connectivity among pixels in a +neighborhood, may vary with the application. + +Many image processing algorithms are neighborhood-based, that is, the +result at a pixel :math:`i` is computed from the values of pixels in the +ND neighborhood of :math:`i`. Consider finite difference operations in +2D. A derivative at pixel index :math:`i = (j, k)`, for example, is +taken as a weighted difference of the values at :math:`(j+1, k)` and +:math:`(j-1, k)`. Other common examples of neighborhood operations +include convolution filtering and image morphology. + +This section describes a class of ITK image iterators that are designed +for working with pixel neighborhoods. An ITK neighborhood iterator walks +an image region just like a normal image iterator, but instead of only +referencing a single pixel at each step, it simultaneously points to the +entire ND neighborhood of pixels. Extensions to the standard iterator +interface provide read and write access to all neighborhood pixels and +information such as the size, extent, and location of the neighborhood. + +Neighborhood iterators use the same operators defined in +Section [sec:IteratorsInterface] and the same code constructs as normal +iterators for looping through an image. +Figure [fig:NeighborhoodIteratorFig1] shows a neighborhood iterator +moving through an iteration region. This iterator defines a :math:`3x3` +neighborhood around each pixel that it visits. The *center* of the +neighborhood iterator is always positioned over its current index and +all other neighborhood pixel indices are referenced as offsets from the +center index. The pixel under the center of the neighborhood iterator +and all pixels under the shaded area, or *extent*, of the iterator can +be dereferenced. + +.. figure:: /Art/C++/NeighborhoodIteratorFig1.png + :align: center + + Path of a ``3x3`` neighborhood iterator through a 2D image region. The extent + of the neighborhood is indicated by the hashing around the iterator + position. Pixels that lie within this extent are accessible through the + iterator. An arrow denotes a single iterator step, the result of one ++ + operation. + +In addition to the standard image pointer and iteration region +(Section [sec:IteratorsInterface]), neighborhood iterator constructors +require an argument that specifies the extent of the neighborhood to +cover. Neighborhood extent is symmetric across its center in each axis +and is given as an array of :math:`N` distances that are collectively +called the *radius*. Each element :math:`d` of the radius, where +:math:`0 < d < N` and :math:`N` is the dimensionality of the +neighborhood, gives the extent of the neighborhood in pixels for +dimension :math:`N`. The length of each face of the resulting ND +hypercube is :math:`2d + 1` pixels, a distance of :math:`d` on either +side of the single pixel at the neighbor center. +Figure [fig:NeighborhoodIteratorFig2] shows the relationship between the +radius of the iterator and the size of the neighborhood for a variety of +2D iterator shapes. + +The radius of the neighborhood iterator is queried after construction by +calling the ``GetRadius()`` method. Some other methods provide some +useful information about the iterator and its underlying image. + +.. figure:: /Art/C++/NeighborhoodIteratorFig2.png + :align: center + :figwidth: 75% + + Several possible 2D neighborhood iterator shapes are shown along with their + radii and sizes. A neighborhood pixel can be dereferenced by its integer + index (top) or its offset from the center (bottom). The center pixel of each + iterator is shaded. + +- ``SizeType GetRadius()`` Returns the ND radius of the + neighborhood as an :doxygen-itk:`Size`. + +- ``const ImageType *GetImagePointer()`` Returns the pointer to the + image referenced by the iterator. + +- ``unsigned long Size()`` Returns the size in number of pixels of + the neighborhood. + +The neighborhood iterator interface extends the normal ITK iterator +interface for setting and getting pixel values. One way to dereference +pixels is to think of the neighborhood as a linear array where each +pixel has a unique integer index. The index of a pixel in the array is +determined by incrementing from the upper-left-forward corner of the +neighborhood along the fastest increasing image dimension: first column, +then row, then slice, and so on. In +Figure [fig:NeighborhoodIteratorFig2], the unique integer index is shown +at the top of each pixel. The center pixel is always at position +:math:`n/2`, where :math:`n` is the size of the array. + +- ``PixelType GetPixel(const unsigned int i)`` Returns the value of + the pixel at neighborhood position ``i``. + +- ``void SetPixel(const unsigned int i, PixelType p)`` Sets the + value of the pixel at position ``i`` to ``p``. + +Another way to think about a pixel location in a neighborhood is as an +ND offset from the neighborhood center. The upper-left-forward corner of +a :math:`3x3x3` neighborhood, for example, can be described by offset +:math:`(-1, -1, -1)`. The bottom-right-back corner of the same +neighborhood is at offset :math:`(1, 1, 1)`. In +Figure [fig:NeighborhoodIteratorFig2], the offset from center is shown +at the bottom of each neighborhood pixel. + +- ``PixelType GetPixel(const OffsetType &o)`` Get the value of the + pixel at the position offset ``o`` from the neighborhood center. + +- ``void SetPixel(const OffsetType &o, PixelType p)`` Set the value + at the position offset ``o`` from the neighborhood center to the + value ``p``. + +The neighborhood iterators also provide a shorthand for setting and +getting the value at the center of the neighborhood. + +- ``PixelType GetCenterPixel()`` Gets the value at the center of + the neighborhood. + +- ``void SetCenterPixel(PixelType p)`` Sets the value at the center + of the neighborhood to the value ``p`` + +There is another shorthand for setting and getting values for pixels +that lie some integer distance from the neighborhood center along one of +the image axes. + +- ``PixelType GetNext(unsigned int d)`` Get the value immediately + adjacent to the neighborhood center in the positive direction along + the ``d`` axis. + +- ``void SetNext(unsigned int d, PixelType p)`` Set the value + immediately adjacent to the neighborhood center in the positive + direction along the ``d`` axis to the value ``p``. + +- ``PixelType GetPrevious(unsigned int d)`` Get the value + immediately adjacent to the neighborhood center in the negative + direction along the ``d`` axis. + +- ``void SetPrevious(unsigned int d, PixelType p)`` Set the value + immediately adjacent to the neighborhood center in the negative + direction along the ``d`` axis to the value ``p``. + +- ``PixelType GetNext(unsigned int d, unsigned int s)`` Get the + value of the pixel located ``s`` pixels from the neighborhood center + in the positive direction along the ``d`` axis. + +- ``void SetNext(unsigned int d, unsigned int s, PixelType p)`` Set + the value of the pixel located ``s`` pixels from the neighborhood + center in the positive direction along the ``d`` axis to value ``p``. + +- ``PixelType GetPrevious(unsigned int d, unsigned int s)`` Get the + value of the pixel located ``s`` pixels from the neighborhood center + in the positive direction along the ``d`` axis. + +- ``void SetPrevious(unsigned int d, unsigned int s, PixelType p)`` + Set the value of the pixel located ``s`` pixels from the neighborhood + center in the positive direction along the ``d`` axis to value ``p``. + +It is also possible to extract or set all of the neighborhood values +from an iterator at once using a regular ITK neighborhood object. This +may be useful in algorithms that perform a particularly large number of +calculations in the neighborhood and would otherwise require multiple +dereferences of the same pixels. + +- ``NeighborhoodType GetNeighborhood()`` Return a + :doxygen-itk:`Neighborhood` of the same size and shape as the + neighborhood iterator and contains all of the values at the iterator + position. + +- ``void SetNeighborhood(NeighborhoodType &N)`` Set all of the + values in the neighborhood at the iterator position to those + contained in Neighborhood ``N``, which must be the same size and + shape as the iterator. + +Several methods are defined to provide information about the +neighborhood. + +- ``IndexType GetIndex()`` Return the image index of the center + pixel of the neighborhood iterator. + +- ``IndexType GetIndex(OffsetType o)`` Return the image index of + the pixel at offset ``o`` from the neighborhood center. + +- ``IndexType GetIndex(unsigned int i)`` Return the image index of + the pixel at array position ``i``. + +- ``OffsetType GetOffset(unsigned int i)`` Return the offset from + the neighborhood center of the pixel at array position ``i``. + +- ``unsigned long GetNeighborhoodIndex(OffsetType o)`` Return the + array position of the pixel at offset ``o`` from the neighborhood + center. + +- ``std::slice GetSlice(unsigned int n)`` Return a ``std::slice`` + through the iterator neighborhood along axis ``n``. + +A neighborhood-based calculation in a neighborhood close to an image +boundary may require data that falls outside the boundary. The iterator +in Figure [fig:NeighborhoodIteratorFig1], for example, is centered on a +boundary pixel such that three of its neighbors actually do not exist in +the image. When the extent of a neighborhood falls outside the image, +pixel values for missing neighbors are supplied according to a rule, +usually chosen to satisfy the numerical requirements of the algorithm. A +rule for supplying out-of-bounds values is called a *boundary +condition*. + +ITK neighborhood iterators automatically detect out-of-bounds +dereferences and will return values according to boundary conditions. +The boundary condition type is specified by the second, optional +template parameter of the iterator. By default, neighborhood iterators +use a Neumann condition where the first derivative across the boundary +is zero. The Neumann rule simply returns the closest in-bounds pixel +value to the requested out-of-bounds location. Several other common +boundary conditions can be found in the ITK toolkit. They include a +periodic condition that returns the pixel value from the opposite side +of the data set, and is useful when working with periodic data such as +Fourier transforms, and a constant value condition that returns a set +value :math:`v` for all out-of-bounds pixel dereferences. The constant +value condition is equivalent to padding the image with value :math:`v`. + +Bounds checking is a computationally expensive operation because it +occurs each time the iterator is incremented. To increase efficiency, a +neighborhood iterator automatically disables bounds checking when it +detects that it is not necessary. A user may also explicitly disable or +enable bounds checking. Most neighborhood based algorithms can minimize +the need for bounds checking through clever definition of iteration +regions. These techniques are explored in +Section [sec:NeighborhoodExample3]. + +- ``void NeedToUseBoundaryConditionOn()`` Explicitly turn bounds + checking on. This method should be used with caution because + unnecessarily enabling bounds checking may result in a significant + performance decrease. In general you should allow the iterator to + automatically determine this setting. + +- ``void NeedToUseBoundaryConditionOff()`` Explicitly disable + bounds checking. This method should be used with caution because + disabling bounds checking when it is needed will result in + out-of-bounds reads and undefined results. + +- ``void OverrideBoundaryCondition(BoundaryConditionType *b)`` + Overrides the templated boundary condition, using boundary condition + object ``b`` instead. Object ``b`` should not be deleted until it has + been released by the iterator. This method can be used to change + iterator behavior at run-time. + +- ``void ResetBoundaryCondition()`` Discontinues the use of any + run-time specified boundary condition and returns to using the + condition specified in the template argument. + +- ``void SetPixel(unsigned int i, PixelType p, bool status)`` Sets + the value at neighborhood array position ``i`` to value ``p``. If the + position ``i`` is out-of-bounds, ``status`` is set to ``false``, + otherwise ``status`` is set to ``true``. + +The following sections describe the two ITK neighborhood iterator +classes, :doxygen-itk:`NeighborhoodIterator` and +:doxygen-itk:`ShapedNeighborhoodIterator`. Each has a const and a +non-const version. The shaped iterator is a refinement of the standard +NeighborhoodIterator that supports an arbitrarily-shaped +(non-rectilinear) neighborhood. + +NeighborhoodIterator +~~~~~~~~~~~~~~~~~~~~ + +The standard neighborhood iterator class in ITK is the +:doxygen-itk:`NeighborhoodIterator`. Together with its ``const`` +version, :doxygen-itk:`ConstNeighborhoodIterator`, it implements the +complete API described above. This section provides several examples to +illustrate the use of NeighborhoodIterator. + +* Basic neighborhood techniques: edge detection. See example :ref:`NeighborhoodIterators1.cxx` + +* Convolution filtering: Sobel operator. See example :ref:`NeighborhoodIterators2.cxx` + +* Optimizing iteration speed. See example :ref:`NeighborhoodIterators3.cxx` + +* Separable convolution: Gaussian filtering. See example :ref:`NeighborhoodIterators4.cxx` + +* Random access iteration: See example :ref:`NeighborhoodIterators6.cxx` + +ShapedNeighborhoodIterator +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section describes a variation on the neighborhood iterator called a +*shaped* neighborhood iterator. A shaped neighborhood is defined like a +bit mask, or *stencil*, with different offsets in the rectilinear +neighborhood of the normal neighborhood iterator turned off or on to +create a pattern. Inactive positions (those not in the stencil) are not +updated during iteration and their values cannot be read or written. The +shaped iterator is implemented in the class +:doxygen-itk:`ShapedNeighborhoodIterator`, which is a subclass of +:doxygen-itk:`NeighborhoodIterator`. A const version, +:doxygen-itk:`ConstShapedNeighborhoodIterator`, is also available. + +Like a regular neighborhood iterator, a shaped neighborhood iterator +must be initialized with an ND radius object, but the radius of the +neighborhood of a shaped iterator only defines the set of *possible* +neighbors. Any number of possible neighbors can then be activated or +deactivated. The shaped neighborhood iterator defines an API for +activating neighbors. When a neighbor location, defined relative to the +center of the neighborhood, is activated, it is placed on the *active +list* and is then part of the stencil. An iterator can be “reshaped” at +any time by adding or removing offsets from the active list. + +- ``void ActivateOffset(OffsetType &o)`` Include the offset ``o`` + in the stencil of active neighborhood positions. Offsets are relative + to the neighborhood center. + +- ``void DeactivateOffset(OffsetType &o)`` Remove the offset ``o`` + from the stencil of active neighborhood positions. Offsets are + relative to the neighborhood center. + +- ``void ClearActiveList()`` Deactivate all positions in the + iterator stencil by clearing the active list. + +- ``unsigned int GetActiveIndexListSize()`` Return the number of + pixel locations that are currently active in the shaped iterator + stencil. + +Because the neighborhood is less rigidly defined in the shaped iterator, +the set of pixel access methods is restricted. Only the ``GetPixel()`` +and ``SetPixel()`` methods are available, and calling these methods on +an inactive neighborhood offset will return undefined results. + +For the common case of traversing all pixel offsets in a neighborhood, +the shaped iterator class provides an iterator through the active +offsets in its stencil. This *stencil iterator* can be incremented or +decremented and defines ``Get()`` and ``Set()`` for reading and writing +the values in the neighborhood. + +- ``ShapedNeighborhoodIterator::Iterator Begin()`` Return a const + or non-const iterator through the shaped iterator stencil that points + to the first valid location in the stencil. + +- ``ShapedNeighborhoodIterator::Iterator End()`` Return a const or + non-const iterator through the shaped iterator stencil that points + *one position past* the last valid location in the stencil. + +The functionality and interface of the shaped neighborhood iterator is +best described by example. We will use the ShapedNeighborhoodIterator to +implement some binary image morphology algorithms. +The examples that follow implement erosion and dilation. + +For shaped neighborhoods morphological operations, see also examples +:ref:`ShapedNeighborhoodIterators1.cxx` and :ref:`ShapedNeighborhoodIterators2.cxx`. diff --git a/Documentation/Cookbook/rst/C++/PersistentFilters.rst b/Documentation/Cookbook/rst/C++/PersistentFilters.rst new file mode 100644 index 0000000000000000000000000000000000000000..2c7b6073bb376b3716efe9abecf89bd465637358 --- /dev/null +++ b/Documentation/Cookbook/rst/C++/PersistentFilters.rst @@ -0,0 +1,258 @@ +Persistent filters +================== + +Introduction +------------ + +As presented in chapter :ref:`StreamingAndThreading`, OTB has two main mechanisms +to handle large data: streaming allows to process image piece-wise, and +multi-threading allows to process concurrently several pieces of one streaming +block. Using these concepts, one can easily write pixel-wise or +neighborhood-based filters and insert them into a pipeline which will be +scalable with respect to the input image size. + +Yet, sometimes we need to compute global features on the whole image. +One example is to determine image mean and variance of the input image +in order to produce a centered and reduced image. The operation of +centering and reducing each pixel is fully compliant with streaming and +threading, but one has to first estimate the mean and variance of the +image. This first step requires to walk the whole image once, and +traditional streaming and multi-threading based filter architecture is +of no help here. + +This is because there is a fundamental difference between these two +operations: one supports streaming, and the other needs to perform +streaming. In fact we would like to stream the whole image piece by +piece through some filter that will collect and keep mean and variance +cumulants, and then synthetize theses cumulants to compute the final +mean and variance once the full image as been streamed. Each stream +would also benefit from parallel processing. This is exactly what +persistent filters are for. + +Architecture +------------ + +There are two main objects in the persistent filters framework. The +first is the :doxygen:`PersistentImageFilter`, the second is the +:doxygen:`PersistentFilterStreamingDecorator`. + +The persistent filter class +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :doxygen:`PersistentImageFilter` class is a regular +:doxygen-itk:`ImageToImageFilter`, with two additional pure virtual +methods: the ``Synthetize()`` and the ``Reset()`` methods. + +Imagine that the ``GenerateData()`` or ``ThreadedGenerateData()`` +progressively computes some global feature of the whole image, using +some member of the class to store intermediate results. The +``Synthetize()`` is an additional method which is designed to be called +one the whole image has been processed, in order to compute the final +results from the intermediate results. The ``Reset()`` method is +designed to allow the reset of the intermediate results members so as to +start a fresh processing. + +Any sub-class of the :doxygen:`PersistentImageFilter` can be used as a +regular :doxygen-itk:`ImageToImageFilter` (provided that both +``Synthetize()`` and ``Reset()`` have been implemented, but the real +interest of these filters is to be used with the streaming decorator +class presented in the next section. + +The streaming decorator class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :doxygen:`PersistentFilterStreamingDecorator` is a class designed to +be templated with subclasses of the :doxygen:`PersistentImageFilter`. It +provides the mechanism to stream the whole image through the templated +filter, using a third class called +:doxygen:`StreamingImageVirtualWriter`. When the ``Update()`` method is +called on a :doxygen:`PersistentFilterStreamingDecorator`, a pipeline +plugging the templated subclass of the :doxygen:`PersistentImageFilter` +to an instance of :doxygen:`StreamingImageVirtualWriter` is created. The +latter is then updated, and acts like a regular +:doxygen:`ImageFileWriter` but it does not actually write anything to +the disk : streaming pieces are requested and immediately discarded. The +:doxygen:`PersistentFilterStreamingDecorator` also calls the ``Reset()`` +method at the beginning and the ``Synthetize()`` method at the end of +the streaming process. Therefore, it packages the whole mechanism for +the use of a :doxygen:`PersistentImageFilter`: + +#. Call the ``Reset()`` method on the filter so as to reset any + temporary results members, + +#. Stream the image piece-wise through the filter, + +#. Call the ``Synthetize()`` method on the filter so as to compute the + final results. + +There are some methods that allows to tune the behavior of the +:doxygen:`StreamingImageVirtualWriter`, allowing to change the image +splitting methods (tiles or strips) or the size of the streams with +respect to some target available amount of memory. Please see the class +documentation for details. The instance of the +:doxygen:`StreamingImageVirtualWriter` can be retrieved from the +:doxygen:`PersistentFilterStreamingDecorator` through the +``GetStreamer()`` method. + +Though the internal filter of the +:doxygen:`PersistentFilterStreamingDecorator` can be accessed through +the ``GetFilter()`` method, the class is often derived to package the +streaming-decorated filter and wrap the parameters setters and getters. + +An end-to-end example +--------------------- + +This is an end-to-end example to compute the mean over a full image, +using a streaming and threading-enabled filter. Please note that only +specific details are explained here. For more general information on how +to write a filter, please refer to section :ref:`Filters`. + +First step: writing a persistent filter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The first step is to write a persistent mean image filter. We need to +include the appropriate header : + +.. code-block:: cpp + + #include "otbPersistentImageFilter.h" + +Then, we declare the class prototype as follows: + +.. code-block:: cpp + + template<class TInputImage> + class ITK_EXPORT PersistentMeanImageFilter : + public PersistentImageFilter<TInputImage, TInputImage> + +Since the output image will only be used for streaming purpose, we do +not need to declare different input and output template types. + +In the *private* section of the class, we will declare a member which +will be used to store temporary results, and a member which will be used +to store the final result. + +.. code-block:: cpp + + private: + // Temporary results container + std::vector<PixelType> m_TemporarySums; + + // Final result member + double m_Mean; + +Next, we will write the ``Reset()`` method implementation in the +*protected* section of the class. Proper allocation of the temporary +results container with respect to the number of threads is handled here. + +.. code-block:: cpp + + protected: + virtual void Reset() + { + // Retrieve the number of threads + unsigned int numberOfThreads = this->GetNumberOfThreads(); + + // Reset the temporary results container + m_TemporarySums = std::vector<PixelType>(numberOfThreads, itk::NumericTraits<PixelType>::Zero); + + // Reset the final result + m_Mean = 0.; + } + +Now, we need to write the ``ThreadedGenerateData()`` methods (also in +the *protected* section), were temporary results will be computed for +each piece of stream. + +.. code-block:: cpp + + virtual void ThreadedGenerateData(const RegionType& + outputRegionForThread, + itk::ThreadIdType threadId) + { + // Enable progress reporting + itk::ProgressReporter(this,threadId,outputRegionForThread.GetNumberOfPixels()); + + // Retrieve the input pointer + InputImagePointer inputPtr = const_cast<TInputImage *>(this->GetInput()); + + // Declare an iterator on the region + itk::ImageRegionConstIteratorWithIndex<TInputImage> it(inputPtr, + outputRegionForThread); + + // Walk the region of the image with the iterator + for (it.GoToBegin(); !it.IsAtEnd(); ++it, progress.CompletedPixel()) + { + // Retrieve pixel value + const PixelType& value = it.Get(); + + // Update temporary results for the current thread + m_TemporarySums[threadId]+= value; + } + } + +Last, we need to define the ``Synthetize()`` method (still in the +*protected* section), which will yield the final results: + +.. code-block:: cpp + + virtual void Synthetize() + { + // For each thread + for(unsigned int threadId = 0; threadId <this->GetNumberOfThreads();++threadId) + { + // Update final result + m_Mean+=m_TemporarySums[threadId]; + } + + // Complete calculus by dividing by the total number of pixels + unsigned int nbPixels = this->GetInput()->GetLargestPossibleRegion().GetNumberOfPixels(); + + if(nbPixels != 0) + { + m_Mean /= nbPixels; + } + } + +Second step: Decorating the filter and using it +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now, to use the filter, one only has to decorate it with the +:doxygen:`PersistentFilterStreamingDecorator`. First step is to include +the appropriate header: + +.. code-block:: cpp + + #include "otbPersistentMeanImageFilter.h" + #include "otbPersistentFilterStreamingDecorator.h" + +Then, we decorate the filter with some typedefs: + +.. code-block:: cpp + + typedef otb::PersistentMeanImageFilter<ImageType> PersitentMeanFilterType; + typedef otb::PersistentFilterStreamingDecorator <PersitentMeanFilterType> StreamingMeanFilterType; + +Now, the decorated filter can be used like any standard filter: + +.. code-block:: cpp + + StreamingMeanFilterType::Pointer filter = StreamingMeanFilterType::New(); + + filter->SetInput(reader->GetOutput()); + filter->Update(); + +Third step: one class to rule them all +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is often convenient to avoid the few typedefs of the previous section +by deriving a new class from the decorated filter: + +.. code-block:: cpp + + template<class TInputImage> + class ITK_EXPORT StreamingMeanImageFilter : + public PersistentFilterStreamingDecorator<PersistentImageFilter<TInputImage, TInputImage>> + +This also allows to redefine setters and getters for parameters, +avoiding to call the ``GetFilter()`` method to set them. diff --git a/Documentation/Cookbook/rst/C++/StreamingAndThreading.rst b/Documentation/Cookbook/rst/C++/StreamingAndThreading.rst new file mode 100644 index 0000000000000000000000000000000000000000..0d7d29f4be418af512fcb6ab48231a17ae7cec0f --- /dev/null +++ b/Documentation/Cookbook/rst/C++/StreamingAndThreading.rst @@ -0,0 +1,68 @@ +.. _StreamingAndThreading: + +Streaming and Threading +======================= + +Streaming and threading are two +different things even if they are linked to a certain extent. In OTB: + +- Streaming describes the ability to combine the processing of several + portion of a big image and to make the output identical as what you + would have got if the whole image was processed at once. Streaming is + compulsory when you’re processing gigabyte images. + +- Threading is the ability to process simultaneously different parts of + the image. Threading will give you some benefits only if you have a + fairly recent processor. + +To sum up: streaming is good if you have big images, threading is good +if you have several processing units. + +However, these two properties are not unrelated. Both rely on the filter +ability to process parts of the image and combine the result, that's what +the ``ThreadedGenerateData()`` method can do. + +Streaming and threading in OTB +------------------------------ + +For OTB, streaming is pipeline related while threading is filter +related. If you build a pipeline where one filter is not streamable, the +whole pipeline is not streamable: at one point, you would hold the +entire image in memory. Whereas you will benefit from a threaded filter +even if the rest of the pipeline is made of non-threadable filters (the +processing time will be shorter for this particular filter). + +Even if you use a non streamed writer, each filter which has a +``ThreadedGenerateData()`` will split the image into two and send each part +to one thread and you will notice two calls to the function. + +If you have some particular requirement and want to use only one thread, +you can call the ``SetNumberOfThreads()`` method on each of your filter. + +When you are writing your own filter, you have to follow some rules to +make your filter streamable and threadable. Some details are provided in +sections :ref:`StreamingLargeData` and :ref:`ThreadedFilterExecution`. + +Division strategies +------------------- + +The division of the image occurs generally at the writer level. +Different strategies are available and can be specified explicitly. In +OTB, these are referred as *splitter*. Several available splitters are: + +- :doxygen-itk:`ImageRegionSplitter` + +- :doxygen-itk:`ImageRegionMultidimensionalSplitter` + +- :doxygen:`ImageRegionNonUniformMultidimensionalSplitter` + +You can add your own strategies based on these examples. + +To change the splitting strategy of the writer, you can use the +following model: + +.. code-block:: cpp + + typedef otb::ImageRegionNonUniformMultidimensionalSplitter<3> splitterType; + splitterType::Pointer splitter=splitterType::New() ; + writer->SetRegionSplitter(splitter); diff --git a/Documentation/Cookbook/rst/C++/SystemOverview.rst b/Documentation/Cookbook/rst/C++/SystemOverview.rst new file mode 100644 index 0000000000000000000000000000000000000000..7eafff2e0b15697488513ee4e110102a9ecf6002 --- /dev/null +++ b/Documentation/Cookbook/rst/C++/SystemOverview.rst @@ -0,0 +1,358 @@ +.. _SystemOverview: + +System Overview +=============== + +The purpose of this chapter is to provide you with an overview of the +*ORFEO Toolbox* system. We recommend that you read this chapter to gain +an appreciation for the breadth and area of application of OTB. In this +chapter, we will make reference either to *OTB features* or *ITK +features* without distinction. Bear in mind that OTB uses ITK as its +core element, so all the fundamental elements of OTB come from ITK. OTB +extends the functionalities of ITK for the remote sensing image +processing community. We benefit from the Open Source development +approach chosen for ITK, which allows us to provide an impressive set of +functionalities with much less effort than would have been the case in a +closed source universe! + +System Organization +------------------- + +The Orfeo Toolbox consists of several subsystems: + +Essential System Concepts + Like any software system, OTB is built around some core design + concepts. OTB uses those of ITK. Some of the more important concepts + include generic programming, smart pointers for memory management, + object factories for adaptable object instantiation, event + management using the command/observer design paradigm, and + multithreading support. + +Numerics + OTB, as ITK uses VXL’s VNL numerics libraries. These are easy-to-use + C++ wrappers around the Netlib Fortran numerical analysis routines + (http://www.netlib.org). + +Data Representation and Access + Two principal classes are used to represent data: the + :doxygen:`Image` and :doxygen-itk:`Mesh` classes. In addition, + various types of iterators and containers are used in ITK to hold + and traverse the data. Other important but less popular classes are + also used to represent data such as histograms. + +ITK’s Data Processing Pipeline + The data representation classes (known as *data objects*) are + operated on by *filters* that in turn may be organized into data + flow *pipelines*. These pipelines maintain state and therefore + execute only when necessary. They also support multi-threading, and + are streaming capable (i.e., can operate on pieces of data to + minimize the memory footprint). + +IO Framework + Associated with the data processing pipeline are *sources*, filters + that initiate the pipeline, and *mappers*, filters that terminate + the pipeline. The standard examples of sources and mappers are + *readers* and *writers* respectively. Readers input data (typically + from a file), and writers output data from the pipeline. *Viewers* + are another example of mappers. + +Spatial Objects + Geometric shapes are represented in OTB using the ITK spatial object + hierarchy. These classes are intended to support modeling of + anatomical structures in ITK. OTB uses them in order to model + cartographic elements. Using a common basic interface, the spatial + objects are capable of representing regions of space in a variety of + different ways. For example: mesh structures, image masks, and + implicit equations may be used as the underlying representation + scheme. Spatial objects are a natural data structure for + communicating the results of segmentation methods and for + introducing geometrical priors in both segmentation and registration + methods. + +ITK’s Registration Framework + A flexible framework for registration supports four different types + of registration: image registration, multiresolution registration, + PDE-based registration, and FEM (finite element method) + registration. + +FEM Framework + ITK includes a subsystem for solving general FEM problems, in + particular non-rigid registration. The FEM package includes mesh + definition (nodes and elements), loads, and boundary conditions. + +Level Set Framework + The level set framework is a set of classes for creating filters to + solve partial differential equations on images using an iterative, + finite difference update scheme. The level set framework consists of + finite difference solvers including a sparse level set solver, a + generic level set segmentation filter, and several specific + subclasses including threshold, Canny, and Laplacian based methods. + +Wrapping + ITK uses a unique, powerful system for producing interfaces (i.e., + “wrappers”) to interpreted languages such as Tcl and Python. The + GCC\_XML tool is used to produce an XML description of arbitrarily + complex C++ code; CSWIG is then used to transform the XML + description into wrappers using the `SWIG <http://www.swig.org/>`__ + package. OTB does not use this system at present. + +Essential System Concepts +------------------------- + +This section describes some of the core concepts and implementation +features found in ITK and therefore also in OTB. + +Generic Programming +~~~~~~~~~~~~~~~~~~~ + +Generic programming is a method of organizing libraries consisting of +generic—or reusable—software components. The idea is to make software +that is capable of “plugging together” in an efficient, adaptable +manner. The essential ideas of generic programming are *containers* to +hold data, *iterators* to access the data, and *generic algorithms* that +use containers and iterators to create efficient, fundamental algorithms +such as sorting. Generic programming is implemented in C++ with the +*template* programming mechanism and the use of the STL Standard +Template Library. + +C++ templating is a programming technique allowing users to write +software in terms of one or more unknown types ``T``. To create +executable code, the user of the software must specify all types ``T`` +(known as *template instantiation*) and successfully process the code +with the compiler. The ``T`` may be a native type such as ``float`` or +``int``, or ``T`` may be a user-defined type (e.g., ``class``). At +compile-time, the compiler makes sure that the templated types are +compatible with the instantiated code and that the types are supported +by the necessary methods and operators. + +ITK uses the techniques of generic programming in its implementation. +The advantage of this approach is that an almost unlimited variety of +data types are supported simply by defining the appropriate template +types. For example, in OTB it is possible to create images consisting of +almost any type of pixel. In addition, the type resolution is performed +at compile-time, so the compiler can optimize the code to deliver +maximal performance. The disadvantage of generic programming is that +many compilers still do not support these advanced concepts and cannot +compile OTB. And even if they do, they may produce completely +undecipherable error messages due to even the simplest syntax errors. + +Include Files and Class Definitions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In ITK and OTB classes are defined by a maximum of two files: a header +``.h`` file and an implementation file—\ ``.cxx`` if a non-templated +class, and a ``.hxx`` if a templated class. The header files contain +class declarations and formatted comments that are used by the Doxygen +documentation system to automatically produce HTML manual pages. + +In addition to class headers, there are a few other important ITK header +files. + +``itkMacro.h`` + defines standard system-wide macros (such as ``Set/Get``, constants, + and other parameters). + +``itkNumericTraits.h`` + defines numeric characteristics for native types such as its maximum + and minimum possible values. + +``itkWin32Header.h`` + is used to define operating system parameters to control the + compilation process. + +Object Factories +~~~~~~~~~~~~~~~~ + +Most classes in OTB are instantiated through an *object factory* +mechanism. That is, rather than using the standard C++ class constructor +and destructor, instances of an OTB class are created with the static +class ``New()`` method. In fact, the constructor and destructor are +``protected:`` so it is generally not possible to construct an OTB +instance on the heap. (Note: this behavior pertains to classes that are +derived from :doxygen-itk:`LightObject`. In some cases the need for +speed or reduced memory footprint dictates that a class not be derived +from LightObject and in this case instances may be created on the heap. +An example of such a class is :doxygen-itk:`EventObject`.) + +The object factory enables users to control run-time instantiation of +classes by registering one or more factories with +:doxygen-itk:`ObjectFactoryBase`. These registered factories support the +method ``CreateInstance(classname)`` which takes as input the name of a +class to create. The factory can choose to create the class based on a +number of factors including the computer system configuration and +environment variables. For example, in a particular application an OTB +user may wish to deploy their own class implemented using specialized +image processing hardware (i.e., to realize a performance gain). By +using the object factory mechanism, it is possible at run-time to +replace the creation of a particular OTB filter with such a custom +class. (Of course, the class must provide the exact same API as the one +it is replacing.) To do this, the user compiles their class (using the +same compiler, build options, etc.) and inserts the object code into a +shared library or DLL. The library is then placed in a directory +referred to by the ``OTB_AUTOLOAD_PATH`` environment variable. On +instantiation, the object factory will locate the library, determine +that it can create a class of a particular name with the factory, and +use the factory to create the instance. (Note: if the +``CreateInstance()`` method cannot find a factory that can create the +named class, then the instantiation of the class falls back to the usual +constructor.) + +In practice object factories are used mainly (and generally +transparently) by the OTB input/output (IO) classes. For most users the +greatest impact is on the use of the ``New()`` method to create a class. +Generally the ``New()`` method is declared and implemented via the macro +``itkNewMacro()`` found in ``Modules/Core/Common/include/itkMacro.h``. + +Smart Pointers and Memory Management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By their nature object-oriented systems represent and operate on data +through a variety of object types, or classes. When a particular class +is instantiated to produce an instance of that class, memory allocation +occurs so that the instance can store data attribute values and method +pointers (i.e., the vtable). This object may then be referenced by other +classes or data structures during normal operation of the program. +Typically during program execution all references to the instance may +disappear at which point the instance must be deleted to recover memory +resources. Knowing when to delete an instance, however, is difficult. +Deleting the instance too soon results in program crashes; deleting it +too late and memory leaks (or excessive memory consumption) will occur. +This process of allocating and releasing memory is known as memory +management. + +In ITK, memory management is implemented through reference counting. +This compares to another popular approach—garbage collection—used by +many systems including Java. In reference counting, a count of the +number of references to each instance is kept. When the reference goes +to zero, the object destroys itself. In garbage collection, a background +process sweeps the system identifying instances no longer referenced in +the system and deletes them. The problem with garbage collection is that +the actual point in time at which memory is deleted is variable. This is +unacceptable when an object size may be gigantic (think of a large 3D +volume gigabytes in size). Reference counting deletes memory immediately +(once all references to an object disappear). + +Reference counting is implemented through a ``Register()``/``Delete()`` +member function interface. All instances of an OTB object have a +``Register()`` method invoked on them by any other object that +references an them. The ``Register()`` method increments the instances’ +reference count. When the reference to the instance disappears, a +``Delete()`` method is invoked on the instance that decrements the +reference count—this is equivalent to an ``UnRegister()`` method. When +the reference count returns to zero, the instance is destroyed. + +This protocol is greatly simplified by using a helper class called a +:doxygen-itk:`SmartPointer`. The smart pointer acts like a regular +pointer (e.g. supports operators ``->`` and ``*``) but automagically +performs a ``Register()`` when referring to an instance, and an +``UnRegister()`` when it no longer points to the instance. Unlike most +other instances in OTB, SmartPointers can be allocated on the program +stack, and are automatically deleted when the scope that the +SmartPointer was created is closed. As a result, you should *rarely if +ever call Register() or Delete()* in OTB. For example: + +.. code-block:: cpp + + void MyRegistrationFunction() + { // Start of scope + // here an interpolator is created and associated to the + // SmartPointer "interp". + InterpolatorType::Pointer interp = InterpolatorType::New(); + } // End of scope + +In this example, reference counted objects are created (with the +``New()`` method) with a reference count of one. Assignment to the +SmartPointer ``interp`` does not change the reference count. At the end +of scope, ``interp`` is destroyed, the reference count of the actual +interpolator object (referred to by ``interp``) is decremented, and if +it reaches zero, then the interpolator is also destroyed. + +Note that in ITK SmartPointers are always used to refer to instances of +classes derived from :doxygen-itk:`LightObject`. Method invocations and +function calls often return “real” pointers to instances, but they are +immediately assigned to a SmartPointer. Raw pointers are used for +non-LightObject classes when the need for speed and/or memory demands a +smaller, faster class. + +Data Representation +------------------- + +:doxygen:`Image` represents an *n*-dimensional, regular sampling of +data. The sampling direction is parallel to each of the coordinate axes, +and the origin of the sampling, inter-pixel spacing, and the number of +samples in each direction (i.e., image dimension) can be specified. The +sample, or pixel, type in OTB is arbitrary—a template parameter +``TPixel`` specifies the type upon template instantiation. (The +dimensionality of the image must also be specified when the image class +is instantiated.) The key is that the pixel type must support certain +operations (for example, addition or difference) if the code is to +compile in all cases (for example, to be processed by a particular +filter that uses these operations). In practice the OTB user will use a +C++ simple type (e.g., ``int``, ``float``) or a pre-defined pixel type +and will rarely create a new type of pixel class. + +One of the important ITK concepts regarding images is that rectangular, +continuous pieces of the image are known as *regions*. Regions are used +to specify which part of an image to process, for example in +multithreading, or which part to hold in memory. In ITK there are three +common types of regions: + +#. ``LargestPossibleRegion`` —the image in its entirety. + +#. ``BufferedRegion`` —the portion of the image retained in memory. + +#. ``RequestedRegion`` —the portion of the region requested by a filter + or other class when operating on the image. + +The :doxygen:`Image` class extends the functionalities of the +:doxygen-itk:`Image` in order to take into account particular remote +sensing features as geographical projections, etc. + +Data Processing Pipeline +------------------------ + +While data objects (e.g., images) are used to represent data, *process +objects* are classes that operate on data objects and may produce new +data objects. Process objects are classed as *sources*, *filter +objects*, or *mappers*. Sources (such as readers) produce data, filter +objects take in data and process it to produce new data, and mappers +accept data for output either to a file or some other system. Sometimes +the term *filter* is used broadly to refer to all three types. + +The data processing pipeline ties together data objects (e.g., images) +and process objects. The pipeline supports an automatic updating +mechanism that causes a filter to execute if and only if its input or +its internal state changes. Further, the data pipeline supports +*streaming*, the ability to automatically break data into smaller +pieces, process the pieces one by one, and reassemble the processed data +into a final result. + +Typically data objects and process objects are connected together using +the ``SetInput()`` and ``GetOutput()`` methods as follows: + +.. code-block:: cpp + + typedef otb::Image<float,2> FloatImage2DType; + + itk::RandomImageSource<FloatImage2DType>::Pointer random; + random = itk::RandomImageSource<FloatImage2DType>::New(); + random->SetMin(0.0); + random->SetMax(1.0); + + itk::ShrinkImageFilter<FloatImage2DType,FloatImage2DType>::Pointer shrink; + shrink = itk::ShrinkImageFilter<FloatImage2DType,FloatImage2DType>::New(); + shrink->SetInput(random->GetOutput()); + shrink->SetShrinkFactors(2); + + otb::ImageFileWriter::Pointer<FloatImage2DType> writer; + writer = otb::ImageFileWriter::Pointer<FloatImage2DType>::New(); + writer->SetInput (shrink->GetOutput()); + writer->SetFileName("test.raw"); + writer->Update(); + +In this example the source object :doxygen-itk:`RandomImageSource` is +connected to the :doxygen-itk:`ShrinkImageFilter`, and the shrink filter +is connected to the mapper :doxygen:`ImageFileWriter`. When the +``Update()`` method is invoked on the writer, the data processing +pipeline causes each of these filters in order, culminating in writing +the final data to a file on disk. diff --git a/Documentation/Cookbook/rst/C++/Tutorial.rst b/Documentation/Cookbook/rst/C++/Tutorial.rst new file mode 100644 index 0000000000000000000000000000000000000000..00811eda2c6e807cd869c95781a5ca5b27b72f9e --- /dev/null +++ b/Documentation/Cookbook/rst/C++/Tutorial.rst @@ -0,0 +1,239 @@ +Building simple OTB code +======================== + +Well, that’s it, you’ve just downloaded and installed OTB, lured by the +promise that you will be able to do everything with it. That’s true, you +will be able to do everything but - there is always a *but* - some +effort is required. + +OTB uses the very powerful systems of generic programming, many classes +are already available, some powerful tools are defined to help you with +recurrent tasks, but it is not an easy world to enter. + +These tutorials are designed to help you enter this world and grasp the +logic behind OTB. Each of these tutorials should not take more than 10 +minutes (typing included) and each is designed to highlight a specific +point. You may not be concerned by the latest tutorials but it is +strongly advised to go through the first few which cover the basics +you’ll use almost everywhere. + +Hello world +----------- + +Let’s start by the typical *Hello world* program. We are going to +compile this C++ program linking to your new OTB. + +First, create a new folder to put your new programs (all the examples +from this tutorial) in and go into this folder. + +Since all programs using OTB are handled using the CMake system, we need +to create a ``CMakeLists.txt`` that will be used by CMake to compile our +program. An example of this file can be found in the +``OTB/Examples/Tutorials`` directory. The ``CMakeLists.txt`` will be +very similar between your projects. + +Open the ``CMakeLists.txt`` file and write in the few lines: + +.. code-block:: cmake + + project(Tutorials) + + cmake_minimum_required(VERSION 3.1.0) + + find_package(OTB) + if(OTB_FOUND) + include(${OTB_USE_FILE}) + else(OTB_FOUND) + message(FATAL_ERROR "Cannot build OTB project without OTB. Please set OTB_DIR.") + endif(OTB_FOUND) + + add_executable(HelloWorldOTB HelloWorldOTB.cxx ) + target_link_libraries(HelloWorldOTB ${OTB_LIBRARIES}) + +The first line defines the name of your project as it appears in Visual +Studio (it will have no effect under UNIX or Linux). The second line +loads a CMake file with a predefined strategy for finding OTB. If +the strategy for finding OTB fails, CMake will prompt you for the +directory where OTB is installed in your system. In that case you will +write this information in the ``OTB_DIR`` variable. The line +``include(${USE_OTB_FILE})`` loads the ``UseOTB.cmake`` file to set all +the configuration information from OTB. + +The line ``add_executable`` defines as its first argument the name of +the executable that will be produced as result of this project. The +remaining arguments of ``add_executable`` are the names of the source +files to be compiled and linked. Finally, the ``target_link_libraries`` +line specifies which OTB libraries will be linked against this project. + +:ref:`HelloWorldOTB.cxx` + +Once the file is written, run ``ccmake`` on the current directory (that +is ``ccmake ./`` under Linux/Unix). If OTB is on a non standard place, +you will have to tell CMake where it is. Once your done with CMake (you +shouldn’t have to do it anymore) run ``make``. + +You finally have your program. When you run it, you will have the *OTB +Hello World !* printed. + +Ok, well done! You’ve just compiled and executed your first OTB program. +Actually, using OTB for that is not very useful, and we doubt that you +downloaded OTB only to do that. It’s time to move on to a more advanced +level. + +Pipeline basics: read and write +------------------------------- + +OTB is designed to read images, process them and write them to disk or +view the result. In this tutorial, we are going to see how to read and +write images and the basics of the pipeline system. + +First, let’s add the following lines at the end of the +``CMakeLists.txt`` file: + +.. code-block:: cmake + + add_executable(Pipeline Pipeline.cxx ) + target_link_libraries(Pipeline ${OTB_LIBRARIES}) + +Now, create a ``Pipeline.cxx`` file: :ref:`Pipeline.cxx`. + +Once this file is written you just have to run ``make``. The ``ccmake`` +call is not required anymore. + +Get one image from the ``OTB-Data/Examples`` directory from the OTB-Data +repository. You can get it either by cloning the OTB data repository +(``git clone https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb-data.git``), +but that might be quite long as this also gets the data to run the +tests. Alternatively, you can get it from +http://www.orfeo-toolbox.org/packages/OTB-Data-Examples.tgz. Take for +example get ``QB_Suburb.png``. + +Now, run your new program as ``Pipeline QB_Suburb.png output.png``. You +obtain the file ``output.png`` which is the same image as +``QB_Suburb.png``. When you triggered the ``Update()`` method, OTB +opened the original image and wrote it back under another name. + +Well…that’s nice but a bit complicated for a copy program! + +Wait a minute! We didn’t specify the file format anywhere! Let’s try +``Pipeline QB_Suburb.png output.jpg``. And voila! The output image is a +jpeg file. + +That’s starting to be a bit more interesting: this is not just a program +to copy image files, but also to convert between image formats. + +You have just experienced the pipeline structure which executes the +filters only when needed and the automatic image format detection. + +Now it’s time to do some processing in between. + +Filtering pipeline +------------------ + +We are now going to insert a simple filter to do some processing between +the reader and the writer. + +Let’s first add the 2 following lines to the ``CMakeLists.txt`` file: + +.. code-block:: cmake + + add_executable(FilteringPipeline FilteringPipeline.cxx ) + target_link_libraries(FilteringPipeline ${OTB_LIBRARIES}) + +See example :ref:`FilteringPipeline.cxx` + +Compile with ``make`` and execute as +``FilteringPipeline QB_Suburb.png output.png``. + +You have the filtered version of your image in the ``output.png`` file. + +Now, you can practice a bit and try to replace the filter by one of the +150+ filters which inherit from the :doxygen-itk:`ImageToImageFilter` +class. You will definitely find some useful filters here! + +Handling types: scaling output +------------------------------ + +If you tried some other filter in the previous example, you may have +noticed that in some cases, it does not make sense to save the output +directly as an integer. This is the case if you tried the +:doxygen-itk:`CannyEdgeDetectionImageFilter`. If you tried to use it +directly in the previous example, you will have some warning about +converting to unsigned char from double. + +The output of the Canny edge detection is a floating point number. A +simple solution would be to used double as the pixel type. +Unfortunately, most image formats use integer typed and you should +convert the result to an integer image if you still want to visualize +your images with your usual viewer (we will see in a tutorial later how +you can avoid that using the built-in viewer). + +To realize this conversion, we will use the +:doxygen-itk:`RescaleIntensityImageFilter`. + +Add the two lines to the ``CMakeLists.txt`` file: + +.. code-block:: cmake + + add_executable(ScalingPipeline ScalingPipeline.cxx ) + target_link_libraries(ScalingPipeline ${OTB_LIBRARIES}) + +See example :ref:`ScalingPipeline.cxx` + +As you should be getting used to it by now, compile with ``make`` and +execute as ``ScalingPipeline QB_Suburb.png output.png``. + +You have the filtered version of your image in the ``output.png`` file. + +Working with multispectral or color images +------------------------------------------ + +So far, as you may have noticed, we have been working with grey level +images, i.e. with only one spectral band. If you tried to process a +color image with some of the previous examples you have probably +obtained a deceiving grey result. + +Often, satellite images combine several spectral band to help the +identification of materials: this is called multispectral imagery. In +this tutorial, we are going to explore some of the mechanisms used by +OTB to process multispectral images. + +Add the following lines in the ``CMakeLists.txt`` file: + +.. code-block:: cmake + + add_executable(Multispectral Multispectral.cxx ) + target_link_libraries(Multispectral ${OTB_LIBRARIES}) + +See example :ref:`Multispectral.cxx` + +Compile with ``make`` and execute as +``./Multispectral qb_RoadExtract.tif qb_blue.tif qb_shiftscale.tif``. + +Going from raw satellite images to useful products +-------------------------------------------------- + +Quite often, when you buy satellite images, you end up with several +images. In the case of optical satellite, you often have a panchromatic +spectral band with the highest spatial resolution and a multispectral +product of the same area with a lower resolution. The resolution ratio +is likely to be around 4. + +To get the best of the image processing algorithms, you want to combine +these data to produce a new image with the highest spatial resolution +and several spectral band. This step is called fusion and you can find +more details about it in [sec:Fusion]. However, the fusion suppose that +your two images represents exactly the same area. There are different +solutions to process your data to reach this situation. Here we are +going to use the metadata available with the images to produce an +orthorectification as detailed in [sec:Ortho]. + +First you need to add the following lines in the ``CMakeLists.txt`` +file: + +.. code-block:: cmake + + add_executable(OrthoFusion OrthoFusion.cxx) + target_link_libraries(OrthoFusion ${OTB_LIBRARIES}) + +See example :ref:`OrthoFusion.cxx` diff --git a/Documentation/Cookbook/rst/C++/WriteAnApplication.rst b/Documentation/Cookbook/rst/C++/WriteAnApplication.rst new file mode 100644 index 0000000000000000000000000000000000000000..7bf160f4e8a3eb751e0a0131b7337f7f64b9d7df --- /dev/null +++ b/Documentation/Cookbook/rst/C++/WriteAnApplication.rst @@ -0,0 +1,383 @@ +How to write an application +=========================== + +This chapter presents the different steps to write your own application, +and the framework surrounding it. + +Application design +------------------ + +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 images (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 :ref:`appParam`). + +Architecture of the class +------------------------- + +Every application derives from the class `otb::Wrapper::Application <https://www.orfeo-toolbox.org/doxygen/classotb_1_1Wrapper_1_1Application.html>`_. 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()`` + +DoInit() +~~~~~~~~ + +This method is called once, when the application is instantiated. 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 + +- Define the documentation link: using for contrib application use ``SetDocLink("docLink")``, for official application use ``SetOfficialDocLink()``. + +DoUpdateParameters() +~~~~~~~~~~~~~~~~~~~~ + +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 and relationship +between parameters (e.g. in ExtractROI: when changing the input image, +maybe the ROI size has to be updated). + +DoExecute() +~~~~~~~~~~~ + +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. + +.. _appParam: + +Parameters selection +~~~~~~~~~~~~~~~~~~~~ + +In the new application framework, every input, output or parameter +derive from `otb::Wrapper::Parameter <https://www.orfeo-toolbox.org/doxygen/classotb_1_1Wrapper_1_1Parameter.html>`_. The application engine supplies the following types of +parameters: + +- ``ParameterType_Bool`` : parameter storing a boolean. + +- ``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 and single-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. + +Parameters description +~~~~~~~~~~~~~~~~~~~~~~ + +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 <https://www.orfeo-toolbox.org/doxygen/classotb_1_1Wrapper_1_1Application.html>`_. 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. + +Composite application +--------------------- + +The application framework has been extended to allow the implementation +of composite applications : **applications that use other +applications**. The concept is simple : you have two applications A and +B that you want to chain in order to build a third application C. Rather +than writing C by copying the code of A and B, you would like to re-use +applications A and B. This plain example will be re-used in this section +for explanations. + +A dedicated class `otb::Wrapper::CompositeApplication <https://www.orfeo-toolbox.org/doxygen/classotb_1_1Wrapper_1_1CompositeApplication.html>`_ exists to create such applications. If you +derive this class to implement application C, you will be able to create +a composite application. + +Creating internal applications +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Like with standard applications, you have to write a ``DoInit()`` +function. In this function, you should first clean any internal +application with the function ``ClearApplications()`` (the ``DoInit()`` +function is called twice in some cases). Then you can instantiate the +internal applications that you want to use (for instance A and B). The +function ``AddApplication()`` will do that, based on : + +- The application type (i.e. its official name, such as ExtractROI, + BandMath, …) + +- An identifier : like with parameter keys, you have to specify an + identifier to refer to this internal application. Use the same naming + conventions as parameters. + +- A description : give a small description of the role of this internal + application. + +Using the function ``GetInternalApplication()``, you can get a pointer +to the internal application corresponding to a given identifier. + +In the example given in introduction, we assume that : + +- An internal application of type A has been added with identifier + ``a`` + +- An internal application of type B has been added with identifier + ``b`` + +Connecting parameters +~~~~~~~~~~~~~~~~~~~~~ + +Once you have internal applications, you may want to setup their +parameters. There are typically 3 cases. + +You may want to expose a parameter of an internal application as a +parameter of your composite application. Let say you want to expose +parameter ``io.in`` from application ``a`` into your composite +application C with the key ``input``. You can call the function : + +``ShareParameter(input,a.io.in)`` + +As a result, the parameters ``input`` in application C and ``io.in`` in +application ``a`` will point to the same object. Under the two parameter +keys, there is a unique value. These two parameters can be considered as +synchronized. + +This leads to the second case : you may want to synchronize two +parameters from internal applications. Let say you want to synchronize +parameter ``field`` from application ``a`` with parameter ``fname`` from +application ``b``. You can call the function : + +``Connect(a.field,b.fname)`` + +Note that the functions ``ShareParameter()`` and ``Connect()`` : + +- Use the same syntax to access internal parameters (“application + identifier” dot “parameter key”). + +- Shall be used in the DoInit() function, after the internal + applications have been added. + +In this synchronization, the two parameters should have the same type, +or have a similar interface, such as input and output filenames that are +both accessed using ``GetParameterString()`` and +``SetParameterString()``. + +This type of connection is a transition to the third case : you may want +to connect the output of an internal application to the input of an +other internal application. Here the difficulty is that the two +parameters to connect probably have different types. Let say you want to +connect parameter ``a.out`` to parameter ``b.in``. The “Connect()” +function may work in favorable cases (see previous paragraph), but for +images, you have two options : + +- Explicitly copy the image pointer from the output image parameter in + the input image parameter (with functions + ``SetParameterInputImage()`` and ``GetParameterOutputImage()``). It + will connect the pipelines in applications A and B, to form an + “in-memory” connexion. This has to be done between the calls to + ``DoExecute()`` of application A and B. + +- Use a temporary filename to store the output image ``a.out`` and read + it with ``b.in``. In this case, you have to manually call the writers + of parameter ``a.out``. + +At the moment, the in-memory connexion of vector data parameters is not +supported. + +Orchestration +~~~~~~~~~~~~~ + +In the ``DoUpdateParameters()`` of your composite application, you can +call the same function on an internal application with the function +``UpdateInternalParameters()``. This is needed only if your internal +applications have a specific behaviour during parameter update. + +In the ``DoExecute()`` of your composite application, you have to call +``ExecuteInternal()`` in order to launch each internal application. The +order should be compatible with image parameter connexions. If you want +to do “in-memory” connexions, you can do it between two calls to +``ExecuteInternal()``, for instance : + +.. code-block:: cpp + + ExecuteInternal("a"); + GetInternalApplication("b")->SetParameterInputImage("in", GetInternalApplication("a")->GetParameterOutputImage("out")); + ExecuteInternal("b"); + +The application :ref:`BundleToPerfectSensor` is a simple example of composite +applications. For a more complex example, you can check the application +TrainImagesClassifier. + +Compile your application +------------------------ + +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/lib/otb/applications), where *XXX* refers to the class +name. + +Execute your application +------------------------ + +There 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. + +Testing your application +------------------------ + +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. + +Application Example +------------------- + +See example :ref:`ApplicationExample.cxx` diff --git a/Documentation/Cookbook/rst/conf.py.in b/Documentation/Cookbook/rst/conf.py.in index 828b4a8087feaeaf5b35902d5fd53f5a5de0ea5e..8b9c33a3945fdbf92ebabbf692602f64e0caff77 100644 --- a/Documentation/Cookbook/rst/conf.py.in +++ b/Documentation/Cookbook/rst/conf.py.in @@ -38,6 +38,7 @@ extensions = [ 'sphinx.ext.todo', 'sphinx.ext.imgmath', 'sphinx.ext.viewcode', + 'sphinx.ext.extlinks', ] imgmath_latex='@LATEX_COMMAND@' @@ -281,3 +282,8 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + +extlinks = { + 'doxygen': ("http://www.orfeo-toolbox.org/doxygen/classotb_1_1%s.html", "otb::"), + 'doxygen-itk': ("http://www.itk.org/Doxygen/html/classitk_1_1%s.html", "itk::") +} diff --git a/Documentation/Cookbook/rst/templates/example.rst b/Documentation/Cookbook/rst/templates/example.rst index 9153a7e2d35aef4525369fbff25ad36619206050..ed844cd23975bb12e4d4c769255504c2bd8a12bc 100644 --- a/Documentation/Cookbook/rst/templates/example.rst +++ b/Documentation/Cookbook/rst/templates/example.rst @@ -6,7 +6,7 @@ {usage} -Example source code (`{link_name} <{link_href}>`_): +Example source code (`{link_name} <{link_href}>`__): .. code-block:: cpp diff --git a/Documentation/SoftwareGuide/Latex/Applications.tex b/Documentation/SoftwareGuide/Latex/Applications.tex deleted file mode 100644 index 45587a8a0b14c681eb55e8e7d4e57e6d0436ba14..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/Applications.tex +++ /dev/null @@ -1,17 +0,0 @@ -\chapter{Applications} -\label{sec:Applications} - -This chapter introduces a set of ready-to-use applications. -These applications were designed to perform simple remote sensing tasks, -more complex than simple examples, to demonstrate the use of the OTB -functions. They were previously known as the OTB-Applications -package but are now part of the OTB library. The new framework is -slightly different from before but they can be used pretty much the -same way: each application has its set of inputs, outputs, parameters. -The applications can be launched as a command line interface but also -via a Qt GUI. In addition, they can be wrapped for SWIG and PyQt. For a -complete list of these applications, please refer to the -\href{http://orfeo-toolbox.org/Applications}{applications documentation}. - -\section{Example of use} -\label{sec:appExample} diff --git a/Documentation/SoftwareGuide/Latex/CMakeLists.txt b/Documentation/SoftwareGuide/Latex/CMakeLists.txt index 9036226ef385bb5d77c535d820789560716249b0..c47c266da03454b84f844dec5aa19ffb582654cd 100644 --- a/Documentation/SoftwareGuide/Latex/CMakeLists.txt +++ b/Documentation/SoftwareGuide/Latex/CMakeLists.txt @@ -105,14 +105,12 @@ ${SoftwareGuide_BINARY_DIR}/SoftwareGuideConfiguration.tex ) SET( Tex_SRCS - Applications.tex DataRepresentation.tex Filtering.tex GUI.tex ImageInterpolators.tex Infrastructure.tex IO.tex - Iterators.tex Numerics.tex Registration.tex StereoReconstruction.tex @@ -121,14 +119,12 @@ SET( Tex_SRCS SoftwareProcess.tex SpatialObjects.tex Statistics.tex - SystemOverview.tex Visualization.tex Watersheds.tex Fusion.tex Radiometry.tex FeatureExtraction.tex ObjectBasedImageAnalysis.tex - Hyperspectral.tex ) diff --git a/Documentation/SoftwareGuide/Latex/DataRepresentation.tex b/Documentation/SoftwareGuide/Latex/DataRepresentation.tex index ce255b864ab0cc06589ec9ab29dccdd6ed219c9a..5e626c40475ceeed44124154576c91edfd40ee2f 100644 --- a/Documentation/SoftwareGuide/Latex/DataRepresentation.tex +++ b/Documentation/SoftwareGuide/Latex/DataRepresentation.tex @@ -48,86 +48,6 @@ a file. \label{sec:AccessingImageMetadata} \input{MetadataExample} -\subsection{RGB Images} - -The term RGB (Red, Green, Blue) stands for a color representation commonly used -in digital imaging. RGB is a representation of the human physiological -capability to analyze visual light using three spectral-selective -sensors~\cite{Malacara2002,Wyszecki2000}. The human retina possess different -types of light sensitive cells. Three of them, known as \emph{cones}, are -sensitive to color~\cite{Gray2003} and their regions of sensitivity loosely -match regions of the spectrum that will be perceived as red, green and blue -respectively. The \emph{rods} on the other hand provide no color discrimination -and favor high resolution and high sensitivity\footnote{The human eye is -capable of perceiving a single isolated photon.}. A fifth type of receptors, -the \emph{ganglion cells}, also known as circadian\footnote{The term -\emph{Circadian} refers to the cycle of day and night, that is, events that are -repeated with 24 hours intervals.} receptors are sensitive to the lighting -conditions that differentiate day from night. These receptors evolved as a -mechanism for synchronizing the physiology with the time of the day. Cellular -controls for circadian rythms are present in every cell of an organism and are -known to be exquisitively precise~\cite{Lodish2000}. - -The RGB space has been constructed as a representation of a physiological -response to light by the three types of \emph{cones} in the human eye. RGB is -not a Vector space. For example, negative numbers are not appropriate in a -color space because they will be the equivalent of ``negative stimulation'' on -the human eye. In the context of colorimetry, negative color values are used -as an artificial construct for color comparison in the sense that - -\begin{equation} -\label{eqn:ColorSubtraction} - ColorA = ColorB - ColorC -\end{equation} - -just as a way of saying that we can produce $ColorB$ by combining $ColorA$ and -$ColorC$. However, we must be aware that (at least in emitted light) it is not -possible to \emph{subtract light}. So when we mention -Equation~\ref{eqn:ColorSubtraction} we actually mean - -\begin{equation} -\label{eqn:ColorAddition} - ColorB = ColorA + ColorC -\end{equation} - -On the other hand, when dealing with printed color and with paint, as opposed -to emitted light like in computer screens, the physical behavior of color -allows for subtraction. This is because strictly speaking the objects that we -see as red are those that absorb all light frequencies except those in the red -section of the spectrum~\cite{Wyszecki2000}. - -The concept of addition and subtraction of colors has to be carefully -interpreted. In fact, RGB has a different definition regarding whether we are -talking about the channels associated to the three color sensors of the human -eye, or to the three phosphors found in most computer monitors or to the color -inks that are used for printing reproduction. Color spaces are usually non -linear and do not even from a Group. For example, not all visible colors can be -represented in RGB space~\cite{Wyszecki2000}. - -ITK introduces the \doxygen{itk}{RGBPixel} type as a support for representing the -values of an RGB color space. As such, the RGBPixel class embodies a different -concept from the one of an \doxygen{itk}{Vector} in space. For this reason, the -RGBPixel lack many of the operators that may be naively expected from it. In -particular, there are no defined operations for subtraction or addition. - -When you anticipate to perform the operation of ``Mean'' on a RGB type you are -assuming that in the color space provides the action of finding a color in the -middle of two colors, can be found by using a linear operation between their -numerical representation. This is unfortunately not the case in color spaces -due to the fact that they are based on a human physiological -response~\cite{Malacara2002}. - -If you decide to interpret RGB images as simply three independent channels then -you should rather use the \doxygen{itk}{Vector} type as pixel type. In this way, you -will have access to the set of operations that are defined in Vector spaces. -The current implementation of the RGBPixel in ITK presumes that RGB color -images are intended to be used in applications where a formal interpretation of -color is desired, therefore only the operations that are valid in a color space -are available in the RGBPixel class. - -The following example illustrates how RGB images can be represented in OTB. - - \subsection{Vector Images} \label{sec:DefiningVectorImages} diff --git a/Documentation/SoftwareGuide/Latex/Hyperspectral.tex b/Documentation/SoftwareGuide/Latex/Hyperspectral.tex deleted file mode 100644 index dbab164ba81adc2b86d31ffd1f521be085e8caf9..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/Hyperspectral.tex +++ /dev/null @@ -1,4 +0,0 @@ -\chapter{Hyperspectral} - -\input{HyperspectralUnmixingExample} - diff --git a/Documentation/SoftwareGuide/Latex/Iterators.tex b/Documentation/SoftwareGuide/Latex/Iterators.tex deleted file mode 100644 index 3746d0857a1d538437758f9f10a8f3781b8f9a4a..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/Iterators.tex +++ /dev/null @@ -1,891 +0,0 @@ -\chapter{Iterators} -\label{sec:ImageIteratorsChapter} -\index{Iterators!image|(} -\index{Generic Programming} -This chapter introduces the \emph{image iterator}, an important generic -programming construct for image processing in ITK. An iterator is a -generalization of the familiar C programming language pointer used to -reference data in memory. ITK has a wide variety of image iterators, some of -which are highly specialized to simplify common image processing tasks. - -The next section is a brief introduction that defines iterators in the context -of ITK. Section \ref{sec:IteratorsInterface} describes the programming -interface common to most ITK image iterators. -Sections~\ref{sec:ImageIterators}--\ref{sec:NeighborhoodIterators} document -specific ITK iterator types and provide examples of how they are used. - -\section{Introduction} -\label{sec:IteratorsIntroduction} -% Further define iterators in the context of generic programming. -\index{generic programming} -\index{Iterators!definition of} -Generic programming models define functionally independent components called -\emph{containers} and \emph{algorithms}. Container objects store data and -algorithms operate on data. To access data in containers, algorithms use a -third class of objects called \emph{iterators}. An iterator is an -abstraction of a memory pointer. Every container type must define its own -iterator type, but all iterators are written to provide a common interface so -that algorithm code can reference data in a generic way and maintain -functional independence from containers. - -The iterator is so named because it is used for \emph{iterative}, sequential -access of container values. Iterators appear in \code{for} and -\code{while} loop constructs, visiting each data point in turn. -A C pointer, for example, is a type of iterator. It can be moved -forward (incremented) and backward (decremented) through memory to -sequentially reference elements of an array. Many iterator implementations -have an interface similar to a C pointer. - -\index{Iterators!advantages of} -In ITK we use iterators to write generic image processing code for images -instantiated with different combinations of pixel type, pixel -container type, and dimensionality. Because ITK image iterators are -specifically designed to work with \emph{image} containers, their interface and -implementation is optimized for image processing tasks. Using the ITK -iterators instead of accessing data directly through the -\doxygen{otb}{Image} interface has many advantages. Code is more -compact and often generalizes automatically to higher dimensions, algorithms -run much faster, and iterators simplify tasks such as multithreading and -neighborhood-based image processing. - - -\section{Programming Interface} -\label{sec:IteratorsInterface} - -\index{Iterators!programming interface|(} -%Creating iterators -This section describes the standard ITK image iterator programming interface. -Some specialized image iterators may deviate from this standard or provide -additional methods. - -\subsection{Creating Iterators} -\label{sec:CreatingIterators} - -\index{Iterators!construction of} -All image iterators have at least one template parameter that is the image -type over which they iterate. There is no restriction on the dimensionality -of the image or on the pixel type of the image. - -\index{Iterators!and image regions} - -An iterator constructor requires at least two arguments, a smart pointer to the -image to iterate across, and an image region. The image region, called the -\emph{iteration region}, is a rectilinear area in which iteration is -constrained. The iteration region must be wholly contained within the image. -More specifically, a valid iteration region is any subregion of the image -within the current \code{BufferedRegion}. See Section~\ref{sec:ImageSection} -for more information on image regions. - -\index{Iterators!const} -There is a const and a non-const version of most ITK image iterators. A -non-const iterator cannot be instantiated on a non-const image pointer. -Const versions of iterators may read, but may not write pixel values. - -Here is a simple example that defines and constructs a simple image iterator -for an \doxygen{otb}{Image}. - -\small -\begin{verbatim} - typedef otb::Image<float, 3> ImageType; - typedef itk::ImageRegionConstIterator< ImageType > ConstIteratorType; - typedef itk::ImageRegionIterator< ImageType > IteratorType; - - ImageType::Pointer image = SomeFilter->GetOutput(); - - ConstIteratorType constIterator( image, image->GetRequestedRegion() ); - IteratorType iterator( image, image->GetRequestedRegion() ); -\end{verbatim} -\normalsize - -\subsection{Moving Iterators} -\label{sec:MovingIterators} -An iterator is described as \emph{walking} its iteration region. At any -time, the iterator will reference, or ``point to'', one pixel location in the -N-dimensional (ND) image. \emph{Forward iteration} goes from the beginning -of the iteration region to the end of the iteration region. \emph{Reverse -iteration}, goes from just past the end of the region back to the beginning. -There are two corresponding starting positions for iterators, the -\emph{begin} position and the \emph{end} position. An iterator can be moved -directly to either of these two positions using the following methods. - -\index{forward iteration} -\index{reverse iteration} -\index{iteration region} -\index{Iterators!GoToBegin()} - -\begin{itemize} -\item \textbf{\code{GoToBegin()}} Points the iterator to the first valid -data element in the region. - -\index{Iterators!GoToEnd()} -\item \textbf{\code{GoToEnd()}} Points the iterator to \emph{one position past} -the last valid element in the region. -\end{itemize} - -Note that the end position is not actually located within the iteration region. This is -important to remember because attempting to dereference an iterator at its end -position will have undefined results. - -%Moving iteators -ITK iterators are moved back and forth across their iterations using the -decrement and increment operators. - -\index{Iterators!operator++()} -\begin{itemize} -\item \textbf{\code{operator++()}} Increments the iterator one position in the -positive direction. Only the prefix increment operator is defined for ITK image -iterators. - -\index{Iterators!operator--} -\item \textbf{\code{operator--()}} Decrements the iterator one position in the -negative direction. Only the prefix decrement operator is defined for ITK -image iterators. -\end{itemize} - -Figure~\ref{fig:WalkingIterator} illustrates typical iteration over -an image region. Most iterators increment and decrement in the direction of -the fastest increasing image dimension, wrapping to the first position in the -next higher dimension at region boundaries. In other words, an -iterator first moves across columns, then down rows, then from slice to slice, -and so on. - -\begin{figure} -\centering -\includegraphics[width=0.4\textwidth]{IteratorFigure1.eps} -\itkcaption[ITK image iteration]{Normal path of an iterator through a -2D image. The iteration region is shown in a darker shade. An arrow denotes -a single iterator step, the result of one \code{++} operation.} -\protect\label{fig:WalkingIterator} -\end{figure} - -In addition to sequential iteration through the image, some iterators may define -random access operators. Unlike the increment operators, random access -operators may not be optimized for speed and require some knowledge of the -dimensionality of the image and the extent of the iteration region to use properly. - -\begin{itemize} -\index{Iterators!operator+=()} -\item \textbf{\code{operator+=( OffsetType )}} Moves the iterator to the pixel -position at the current index plus specified \doxygen{itk}{Offset}. - -\index{Iterators!operator-=()} -\item \textbf{\code{operator-=( OffsetType )}} Moves the iterator to -the pixel position at the current index minus specified Offset. - -\index{Iterators!SetPosition()} -\item \textbf{\code{SetPosition( IndexType )}} Moves the iterator to the given -\doxygen{itk}{Index} position. -\end{itemize} - -The \code{SetPosition()} method may be extremely slow for more complicated -iterator types. In general, it should only be used for setting a starting -iteration position, like you would use \code{GoToBegin()} or \code{GoToEnd()}. - -Some iterators do not follow a predictable path through their -iteration regions and have no fixed beginning or ending pixel -locations. A conditional iterator, for example, visits pixels only if -they have certain values or connectivities. Random iterators, -increment and decrement to random locations and may even visit a given -pixel location more than once. - -%Testing for location -An iterator can be queried to determine if it is at the end or the beginning of -its iteration region. - -\begin{itemize} -\index{Iterators!IsAtEnd()} -\item \textbf{\code{bool IsAtEnd()}} True if the iterator points to \emph{one -position past} the end of the iteration region. - -\index{Iterators!IsAtBegin()} -\item \textbf{\code{bool IsAtBegin()}} True if the iterator points to the first -position in the iteration region. The method is typically used to test for the -end of reverse iteration. - -\end{itemize} - -An iterator can also report its current image index position. - -\begin{itemize} -\index{Iterators!GetIndex()} -\item \textbf{\code{IndexType GetIndex()}} Returns the Index -of the image pixel that the iterator currently points to. -\end{itemize} - -% A note on bounds checking -\index{Iterators!and bounds checking} -For efficiency, most ITK image iterators do not perform bounds checking. It is -possible to move an iterator outside of its valid iteration region. -Dereferencing an out-of-bounds iterator will produce undefined results. - -\subsection{Accessing Data} -\label{sec:AccessingData} -ITK image iterators define two basic methods for reading and writing pixel -values. - -\begin{itemize} -\index{Iterators!Get()} -\item \textbf{\code{PixelType Get()}} Returns the value of the pixel at the -iterator position. - -\index{Iterators!Set()} -\item \textbf{\code{void Set( PixelType )}} Sets the value of the pixel at the -iterator position. Not defined for const versions of iterators. -\end{itemize} - -% Describe efficiency due to inlining for all cases -The \code{Get()} and \code{Set()} methods are inlined and optimized -for speed so that their use is equivalent to dereferencing the image -buffer directly. There are a few common cases, however, where using -\code{Get()} and \code{Set()} do incur a penalty. Consider the -following code, which fetches, modifies, and then writes a value back -to the same pixel location. - -\small -\begin{verbatim} - it.Set( it.Get() + 1 ); -\end{verbatim} -\normalsize - -As written, this code requires one more memory dereference than is necessary. -Some iterators define a third data access method that avoids this penalty. - -\begin{itemize} -\index{Iterators!Value()} -\item \textbf{\code{PixelType \& Value()}} Returns a reference to the pixel at -the iterator position. -\end{itemize} - -The \code{Value()} method can be used as either an lval or an rval in an -expression. It has all the properties of \code{operator*}. The -\code{Value()} method makes it possible to rewrite our example code more -efficiently. - -\small -\begin{verbatim} - it.Value()++; -\end{verbatim} -\normalsize - -Consider using the \code{Value()} method instead of \code{Get()} or -\code{Set()} when a call to \code{operator=} on a pixel is non-trivial, such as -when working with vector pixels, and operations are done in-place in the -image. - -\subsection{Iteration Loops} -\label{sec:IterationExample} -% Now give a pseudo code example for putting all of this together. -Using the methods described in the previous sections, we can now write a simple -example to do pixel-wise operations on an image. The following code calculates -the squares of all values in an input image and writes them to an output image. - -\small -\begin{verbatim} - ConstIteratorType in( inputImage, inputImage->GetRequestedRegion() ); - IteratorType out( outputImage, inputImage->GetRequestedRegion() ); - - for ( in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd(); ++in, ++out ) - { - out.Set( in.Get() * in.Get() ); - } -\end{verbatim} -\normalsize - -\index{Iterators!and image regions} -Notice that both the input and output iterators are initialized over the same -region, the \code{RequestedRegion} of \code{inputImage}. This is good -practice because it ensures that the output iterator walks exactly the same set -of pixel indices as the input iterator, but does not require that the output -and input be the same size. The only requirement is that the input image -must contain a region (a starting index and size) that matches the -\code{RequestedRegion} of the output image. - -\index{reverse iteration} -Equivalent code can be written by iterating through the image in reverse. -The syntax is slightly more awkward because the \emph{end} of the -iteration region is not a valid position and we can only test whether the -iterator is strictly \emph{equal} to its beginning position. It is often more -convenient to write reverse iteration in a \code{while} loop. - -\small -\begin{verbatim} - in.GoToEnd(); - out.GoToEnd(); - while ( ! in.IsAtBegin() ) - { - --in; - --out; - out.Set( in.Get() * in.Get() ); - } -\end{verbatim} -\normalsize - -%\begin{itemize} -%\item \textbf{\code{operator==}} -%\item \textbf{\code{operator<}} -%\item \textbf{\code{operator<=}} -%\item \textbf{\code{operator>}} -%\item \textbf{\code{operator>=}} -%\end{itemize} - -%operator +=, -=, etc - -% SetIndex() - -% operator <, operator >, etc. - -\index{Iterators!programming interface|)} -\section{Image Iterators} -\label{sec:ImageIterators} -%Introduction and overview -This section describes iterators that walk rectilinear image regions and -reference a single pixel at a time. The \doxygen{itk}{ImageRegionIterator} is the -most basic ITK image iterator and the first choice for most applications. The -rest of the iterators in this section are specializations of -ImageRegionIterator that are designed make common image processing -tasks more efficient or easier to implement. - -% Each of the iterators has a const and non-const version - -\subsection{ImageRegionIterator} -\index{itk::ImageRegionIterator|(} -\label{sec:itkImageRegionIterator} -\input{ImageRegionIterator.tex} -\index{itk::ImageRegionIterator|)} - -\subsection{ImageRegionIteratorWithIndex} -\label{sec:itkImageRegionIteratorWithIndex} -\index{itk::ImageRegionIteratorWithIndex|(} -\input{ImageRegionIteratorWithIndex.tex} -\index{itk::ImageRegionIteratorWithIndex|)} - -\subsection{ImageLinearIteratorWithIndex} -\label{sec:itkImageLinearIteratorWithIndex} -\index{itk::ImageLinearIteratorWithIndex|(} -\input{ImageLinearIteratorWithIndex.tex} -%\input{ImageLinearIteratorWithIndex2.tex} -\index{itk::ImageLinearIteratorWithIndex|)} - -%% \subsection{ImageSliceIteratorWithIndex} -%% \label{sec:itkImageSliceIteratorWithIndex} -%% \index{itk::ImageSliceIteratorWithIndex|(} -%% \input{ImageSliceIteratorWithIndex.tex} -%% \index{itk::ImageSliceIteratorWithIndex|)} - -%% \subsection{ImageRandomConstIteratorWithIndex} -%% \label{sec:itkImageRandomConstIteratorWithIndex} -%% \index{itk::Image\-Random\-Const\-Iterator\-With\-Index|(} -%% \input{ImageRandomConstIteratorWithIndex} -%% \index{itk::Image\-Random\-Const\-Iterator\-With\-Index|)} - -%\section{Conditional Iterators} -%\index{Iterators!conditional|(} -%\label{sec:ConditionalIterators} -%This section describes iterators that walk only pixels in an image region whose -%values satisfy a specified condition. The condition is usually based on some -%function of the image values, such as comparing to a threshold. When the -%condition function returns \code{true} at a pixel location, the iterator -%includes that location in its path. The biggest use of these iterators is for -%walking non-rectilinear regions of interest, such as might be defined by -%implicit geometric shape functions or connected component regions. - -%./Common/itkConditionalConstIterator.h (BaseClass) -%./Common/itkConditionalIterator.h (BaseClass) -%./Common/itkFloodFilledFunctionConditionalConstIterator.h (BaseClass) -%./Common/itkFloodFilledFunctionConditionalIterator.h (BaseClass) - -%[ here are all classes where these filters are used: -% ./BasicFilters/itkConfidenceConnectedImageFilter.hxx (ImageFunction) -% ./BasicFilters/itkConnectedThresholdImageFilter.hxx (ImageFunction) -% ./BasicFilters/itkIsolatedConnectedImageFilter.hxx (ImageFunction) -% ./BasicFilters/itkNeighborhoodConnectedImageFilter.hxx (ImageFunction) -% -% ./Common/itkBinaryBallStructuringElement.hxx (SpatialFunction) -% ./Common/itkBloxCoreAtomImage.hxx (SpatialFunction) -% ./BasicFilters/itkBloxBoundaryPointToCoreAtomImageFilter.hxx (SpatialFunction) -% ./BasicFilters/itkBloxBoundaryPointImageToBloxBoundaryProfileImageFilter.hxx (SpatialFunction) -%] - -%\subsection{itk::FloodFilledImageFunctionConditionalIterator} -%\label{itk::FloodFilledImageFunctionConditionalIterator} -%\index{itk::FloodFilledImageFunctionConditionalIterator|(} -%./Common/itkFloodFilledImageFunctionConditionalConstIterator.h -%./Common/itkFloodFilledImageFunctionConditionalIterator.h -%\index{itk::FloodFilledImageFunctionConditionalIterator|)} - -%\subsection{itk::FloodFilledSpatialFunctionConditionalIterator} -%\label{itk::FloodFilledSpatialFunctionConditionalIterator} -%\index{itk::FloodFilledSpatialFunctionConditionalIterator|(} -%./Common/itkFloodFilledSpatialFunctionConditionalConstIterator.h -%./Common/itkFloodFilledSpatialFunctionConditionalIterator.h -%\index{itk::FloodFilledImageFunctionConditionalIterator|)} -%\index{Iterators!conditional|)} - -\section{Neighborhood Iterators} -\label{sec:NeighborhoodIterators} -\index{Iterators!neighborhood|(} -In ITK, a pixel neighborhood is loosely defined as a small set of pixels that -are locally adjacent to one another in an image. The size and shape -of a neighborhood, as well the connectivity among pixels in a neighborhood, -may vary with the application. - -Many image processing algorithms are neighborhood-based, that is, the result at -a pixel $i$ is computed from the values of pixels in the ND neighborhood of -$i$. Consider finite difference operations in 2D. A derivative at pixel index -$i = (j, k)$, for example, is taken as a weighted difference of the values -at $(j+1, k)$ and $(j-1, k)$. Other common examples of neighborhood operations -include convolution filtering and image morphology. - -This section describes a class of ITK image iterators that are designed for -working with pixel neighborhoods. An ITK neighborhood iterator walks an image -region just like a normal image iterator, but instead of only referencing a -single pixel at each step, it simultaneously points to the entire ND -neighborhood of pixels. Extensions to the standard iterator interface provide -read and write access to all neighborhood pixels and information -such as the size, extent, and location of the neighborhood. - -Neighborhood iterators use the same operators defined in -Section~\ref{sec:IteratorsInterface} and the same code constructs as normal -iterators for looping through an -image. Figure~\ref{fig:NeighborhoodIteratorFig1} shows a neighborhood iterator -moving through an iteration region. This iterator defines a $3x3$ neighborhood -around each pixel that it visits. The \emph{center} of the neighborhood -iterator is always positioned over its current index and all other neighborhood -pixel indices are referenced as offsets from the center index. The pixel -under the center of the neighborhood iterator and all pixels under the shaded -area, or \emph{extent}, of the iterator can be dereferenced. - - - -\begin{figure} -\centering -\includegraphics[width=0.6\textwidth]{NeighborhoodIteratorFig1.eps} -\itkcaption[Neighborhood iterator]{Path of a $3x3$ neighborhood -iterator through a 2D image region. The extent of the neighborhood is -indicated by the hashing around the iterator position. Pixels that lie within -this extent are accessible through the iterator. An arrow denotes a single -iterator step, the result of one \code{++} operation.} -\protect\label{fig:NeighborhoodIteratorFig1} -\end{figure} - -\index{Neighborhood iterators!construction of} -\index{Neighborhood iterators!radius of} - -In addition to the standard image pointer and iteration region -(Section~\ref{sec:IteratorsInterface}), neighborhood iterator constructors -require an argument that specifies the extent of the neighborhood to cover. -Neighborhood extent is symmetric across its center in each -axis and is given as an array of $N$ distances that are collectively called the -\emph{radius}. Each element $d$ of the radius, where $0 < d < N$ and -$N$ is the dimensionality of the neighborhood, gives the extent of the -neighborhood in pixels for dimension $N$. The length of each face of the -resulting ND hypercube is $2d + 1$ pixels, a distance of $d$ on either side of -the single pixel at the neighbor center. -Figure~{\ref{fig:NeighborhoodIteratorFig2} shows the relationship between the -radius of the iterator and the size of the neighborhood for a variety of 2D -iterator shapes. - -The radius of the neighborhood iterator is queried after construction -by calling the \code{GetRadius()} method. Some other methods provide -some useful information about the iterator and its underlying image. - -\begin{figure} -\centering -\includegraphics[width=0.9\textwidth]{NeighborhoodIteratorFig2.eps} -\itkcaption[Some possible neighborhood iterator shapes]{Several possible 2D -neighborhood iterator shapes are shown along with their radii and sizes. A -neighborhood pixel can be dereferenced by its integer index (top) or its -offset from the center (bottom). The center pixel of each iterator is -shaded.} -\protect\label{fig:NeighborhoodIteratorFig2} -\end{figure} - -\begin{itemize} - -\index{NeighborhoodIterator!GetRadius()} -\item \textbf{\code{SizeType GetRadius()}} Returns the ND radius of the -neighborhood as an \doxygen{itk}{Size}. - -\index{NeighborhoodIterator!GetImagePointer()} -\item \textbf{\code{const ImageType *GetImagePointer()}} Returns the pointer to -the image referenced by the iterator. - -\index{NeighborhoodIterator!Size()} -\item \textbf{\code{unsigned long Size()}} Returns the size in number of -pixels of the neighborhood. - -\end{itemize} - -The neighborhood iterator interface extends the normal ITK iterator interface -for setting and getting pixel values. One way to dereference pixels is to -think of the neighborhood as a linear array where each pixel has a unique -integer index. The index of a pixel in the array is determined by incrementing -from the upper-left-forward corner of the neighborhood along the fastest -increasing image dimension: first column, then row, then slice, and so on. In -Figure~\ref{fig:NeighborhoodIteratorFig2}, the unique integer index is shown -at the top of each pixel. The center pixel is always at position $n/2$, where -$n$ is the size of the array. - -\begin{itemize} - -\index{NeighborhoodIterator!GetPixel()} -\item \textbf{\code{PixelType GetPixel(const unsigned int i)}} Returns the -value of the pixel at neighborhood position \code{i}. - -\index{NeighborhoodIterator!SetPixel()} -\item \textbf{\code{void SetPixel(const unsigned int i, PixelType p)}} -Sets the value of the pixel at position \code{i} to \code{p}. - -\end{itemize} - -Another way to think about a pixel location in a neighborhood is as an -ND offset from the neighborhood center. The upper-left-forward corner -of a $3x3x3$ neighborhood, for example, can be described by offset -$(-1, -1, -1)$. The bottom-right-back corner of the same neighborhood -is at offset $(1, 1, 1)$. In -Figure~\ref{fig:NeighborhoodIteratorFig2}, the offset from center is -shown at the bottom of each neighborhood pixel. - -\begin{itemize} - -\index{NeighborhoodIterator!GetPixel()} -\item \textbf{\code{PixelType GetPixel(const OffsetType \&o)}} Get the value of -the pixel at the position offset \code{o} from the neighborhood center. - -\index{NeighborhoodIterator!SetPixel()} -\item \textbf{\code{void SetPixel(const OffsetType \&o, PixelType p)}} Set -the value at the position offset \code{o} from the neighborhood center to -the value \code{p}. - -\end{itemize} - -The neighborhood iterators also provide a shorthand for setting and getting the -value at the center of the neighborhood. - -\index{NeighborhoodIterators!} -\begin{itemize} - -\index{NeighborhoodIterator!GetCenterPixel()} -\item \textbf{\code{PixelType GetCenterPixel()}} Gets the value at the center -of the neighborhood. - -\index{NeighborhoodIterator!SetCenterPixel()} -\item \textbf{\code{void SetCenterPixel(PixelType p)}} Sets the value at the -center of the neighborhood to the value \code{p} - -\end{itemize} - -There is another shorthand for setting and getting values for pixels that -lie some integer distance from the neighborhood center along one of the image -axes. - -\index{NeighborhoodIterators!} -\begin{itemize} - -\index{NeighborhoodIterator!GetNext()} -\item \textbf{\code{PixelType GetNext(unsigned int d)}} Get the value -immediately adjacent to the neighborhood center in the positive direction along -the \code{d} axis. - -\index{NeighborhoodIterator!SetNext()} -\item \textbf{\code{void SetNext(unsigned int d, PixelType p)}} Set the value -immediately adjacent to the neighborhood center in the positive direction along -the \code{d} axis to the value \code{p}. - -\index{NeighborhoodIterator!GetPrevious()} -\item \textbf{\code{PixelType GetPrevious(unsigned int d)}} Get the value -immediately adjacent to the neighborhood center in the negative direction along -the \code{d} axis. - -\index{NeighborhoodIterator!SetPrevious()} -\item \textbf{\code{void SetPrevious(unsigned int d, PixelType p)}} -Set the value immediately adjacent to the neighborhood center in the -negative direction along the \code{d} axis to the value \code{p}. - -\item \textbf{\code{PixelType GetNext(unsigned int d, unsigned int -s)}} Get the value of the pixel located \code{s} pixels from the -neighborhood center in the positive direction along the \code{d} axis. - -\item \textbf{\code{void SetNext(unsigned int d, unsigned int s, PixelType p)}} -Set the value of the pixel located \code{s} pixels from the neighborhood center -in the positive direction along the \code{d} axis to value \code{p}. - -\item \textbf{\code{PixelType GetPrevious(unsigned int d, unsigned int -s)}} Get the value of the pixel located \code{s} pixels from the -neighborhood center in the positive direction along the \code{d} axis. - -\item \textbf{\code{void SetPrevious(unsigned int d, unsigned int s, -PixelType p)}} Set the value of the pixel located \code{s} pixels from -the neighborhood center in the positive direction along the \code{d} -axis to value \code{p}. - -\end{itemize} - -It is also possible to extract or set all of the neighborhood values -from an iterator at once using a regular ITK neighborhood object. -This may be useful in algorithms that perform a particularly large -number of calculations in the neighborhood and would otherwise require -multiple dereferences of the same pixels. - -\begin{itemize} - -\index{NeighborhoodIterator!GetNeighborhood()} -\index{NeighborhoodIterator!SetNeighborhood()} -\item \textbf{\code{NeighborhoodType GetNeighborhood()}} Return a -\doxygen{itk}{Neighborhood} of the same size and shape as the neighborhood -iterator and contains all of the values at the iterator position. - -\item \textbf{\code{void SetNeighborhood(NeighborhoodType \&N)}} Set all -of the values in the neighborhood at the iterator position to those contained -in Neighborhood \code{N}, which must be the same size and shape as the -iterator. - -\end{itemize} - -Several methods are defined to provide information about the neighborhood. - -\index{NeighborhoodIterators!} -\begin{itemize} - -\index{NeighborhoodIterator!GetIndex()} -\item \textbf{\code{IndexType GetIndex()}} Return the image -index of the center pixel of the neighborhood iterator. - -\item \textbf{\code{IndexType GetIndex(OffsetType o)}} Return the -image index of the pixel at offset \code{o} from the neighborhood -center. - -\item \textbf{\code{IndexType GetIndex(unsigned int i)}} Return the -image index of the pixel at array position \code{i}. - -\index{NeighborhoodIterator!GetOffset()} -\item \textbf{\code{OffsetType GetOffset(unsigned int i)}} Return the offset -from the neighborhood center of the pixel at array position \code{i}. - -\index{NeighborhoodIterator!GetNeighborhoodIndex()} -\item \textbf{\code{unsigned long GetNeighborhoodIndex(OffsetType o)}} -Return the array position of the pixel at offset \code{o} from the -neighborhood center. - -\index{NeighborhoodIterator!GetSlice()} -\item \textbf{\code{std::slice GetSlice(unsigned int n)}} Return a -\code{std::slice} through the iterator neighborhood along axis \code{n}. - -\end{itemize} - -\index{Neighborhood iterators!boundary conditions} -\index{Neighborhood iterators!bounds checking} -A neighborhood-based calculation in a neighborhood close to an image -boundary may require data that falls outside the boundary. The -iterator in Figure~\ref{fig:NeighborhoodIteratorFig1}, for example, is -centered on a boundary pixel such that three of its neighbors actually -do not exist in the image. When the extent of a neighborhood falls -outside the image, pixel values for missing neighbors are supplied -according to a rule, usually chosen to satisfy the numerical -requirements of the algorithm. A rule for supplying out-of-bounds -values is called a \emph{boundary condition}. - -ITK neighborhood iterators automatically detect out-of-bounds dereferences and -will return values according to boundary conditions. The boundary condition -type is specified by the second, optional template parameter of the iterator. -By default, neighborhood iterators use a Neumann condition where the first -derivative across the boundary is zero. The Neumann rule simply returns the -closest in-bounds pixel value to the requested out-of-bounds location. Several -other common boundary conditions can be found in the ITK toolkit. They include -a periodic condition that returns the pixel value from the opposite side of the -data set, and is useful when working with periodic data such as Fourier -transforms, and a constant value condition that returns a set value $v$ for all -out-of-bounds pixel dereferences. The constant value condition is equivalent -to padding the image with value $v$. - -Bounds checking is a computationally expensive operation because it occurs each -time the iterator is incremented. To increase efficiency, a neighborhood -iterator automatically disables bounds checking when it detects that it is -not necessary. A user may also explicitly disable or enable bounds checking. -Most neighborhood based algorithms can minimize the need for bounds checking -through clever definition of iteration regions. These techniques are explored -in Section~\ref{sec:NeighborhoodExample3}. - -\begin{itemize} - -\index{NeighborhoodIterator!NeedToUseBoundaryConditionOn()} -\item \textbf{\code{void NeedToUseBoundaryConditionOn()}} Explicitly turn -bounds checking on. This method should be used with caution because -unnecessarily enabling bounds checking may result in a significant performance -decrease. In general you should allow the iterator to automatically determine -this setting. - -\index{NeighborhoodIterator!NeedToUseBoundaryConditionOff()} -\item \textbf{\code{void NeedToUseBoundaryConditionOff()}} Explicitly disable -bounds checking. This method should be used with caution because disabling -bounds checking when it is needed will result in out-of-bounds reads and -undefined results. - -\index{NeighborhoodIterator!OverrideBoundaryCondition()} -\item \textbf{\code{void OverrideBoundaryCondition(BoundaryConditionType *b)}} -Overrides the templated boundary condition, using boundary condition -object \code{b} instead. Object \code{b} should not be deleted until -it has been released by the iterator. This method can be used to -change iterator behavior at run-time. - -\index{NeighborhoodIterator!ResetBoundaryCondition()} -\item \textbf{\code{void ResetBoundaryCondition()}} Discontinues the use of any -run-time specified boundary condition and returns to using the condition -specified in the template argument. - -\index{NeighborhoodIterator!SetPixel()} -\item \textbf{\code{void SetPixel(unsigned int i, PixelType p, bool -status)}} Sets the value at neighborhood array position \code{i} to value -\code{p}. If the position \code{i} is out-of-bounds, \code{status} is set to -\code{false}, otherwise \code{status} is set to \code{true}. -\end{itemize} - -The following sections describe the two ITK neighborhood iterator classes, -\doxygen{itk}{NeighborhoodIterator} and \doxygen{itk}{ShapedNeighborhoodIterator}. -Each has a const and a non-const version. The shaped iterator is a refinement -of the standard NeighborhoodIterator that supports an -arbitrarily-shaped (non-rectilinear) neighborhood. - -\subsection{NeighborhoodIterator} -\label{sec:itkNeighborhoodIterator} - -\index{NeighborhoodIterator!examples} -\index{Neighborhood iterators!examples} -The standard neighborhood iterator class in ITK is the -\doxygen{itk}{NeighborhoodIterator}. Together with its \code{const} version, -\doxygen{itk}{ConstNeighborhoodIterator}, it implements the complete API -described above. This section provides several examples to illustrate the use -of NeighborhoodIterator. - -\index{edge detection} -\index{Sobel operator} -\subsubsection{Basic neighborhood techniques: edge detection} -\label{sec:NeighborhoodExample1} -\input{NeighborhoodIterators1.tex} - -\index{convolution filtering} -\index{Sobel operator} -\subsubsection{Convolution filtering: Sobel operator} -\label{sec:NeighborhoodExample2} -\input{NeighborhoodIterators2.tex} - -\subsubsection{Optimizing iteration speed} -\label{sec:NeighborhoodExample3} -\input{NeighborhoodIterators3.tex} - -\index{Gaussian blurring} -\subsubsection{Separable convolution: Gaussian filtering} -\label{sec:NeighborhoodExample4} -\input{NeighborhoodIterators4.tex} - -%% \subsubsection{Slicing the neighborhood} -%% \label{sec:NeighborhoodExample5} -%% \input{NeighborhoodIterators5.tex} - -\subsubsection{Random access iteration} -\label{sec:NeighborhoodExample6} -\input{NeighborhoodIterators6.tex} - -%./Common/itkConstNeighborhoodIterator.h -%./Common/itkNeighborhoodIterator.h - -% Example1: Edge detection using ``hand-coded'' Sobel operator -% Example2: Sobel edge detection using convolution filtering and Sobel operator -% Example3: Improving boundary condition efficiency -% Example4: gaussian filtering, separable convolution -% Example5: Slicing the neighborhood: gaussian filtering, separable convolution -% Example6: Advanced Neighborhood Techniques: local minima, local maxima - -\subsection{ShapedNeighborhoodIterator} -\label{sec:itkShapedNeighborhoodIterator} -\index{ShapedNeighborhoodIterator} -\index{Neighborhood iterators!shaped} -\index{Neighborhood iterators!as stencils} -This section describes a variation on the neighborhood iterator called a -\emph{shaped} neighborhood iterator. A shaped neighborhood is defined like -a bit mask, or \emph{stencil}, with different offsets in the rectilinear -neighborhood of the normal neighborhood iterator turned off or on to create a -pattern. Inactive positions (those not in the stencil) are not updated during -iteration and their values cannot be read or written. The shaped iterator is -implemented in the class \doxygen{itk}{ShapedNeighborhoodIterator}, which is a -subclass of -\doxygen{itk}{NeighborhoodIterator}. A const version, -\doxygen{itk}{ConstShapedNeighborhoodIterator}, is also available. - -\index{Neighborhood iterators!active neighbors} -\index{Neighborhood iterators!inactive neighbors} -Like a regular neighborhood iterator, a shaped neighborhood iterator must be -initialized with an ND radius object, but the radius of the neighborhood of a -shaped iterator only defines the set of \emph{possible} neighbors. Any number -of possible neighbors can then be activated or deactivated. The shaped -neighborhood iterator defines an API for activating neighbors. When a neighbor -location, defined relative to the center of the neighborhood, is activated, it -is placed on the \emph{active list} and is then part of the stencil. An -iterator can be ``reshaped'' at any time by adding or removing offsets from the -active list. - -\begin{itemize} - -\index{ShapedNeighborhoodIterator!ActivateOffset()} -\item \textbf{\code{void ActivateOffset(OffsetType \&o)}} Include the offset -\code{o} in the stencil of active neighborhood positions. Offsets are relative -to the neighborhood center. - -\index{ShapedNeighborhoodIterator!DeactivateOffset()} -\item \textbf{\code{void DeactivateOffset(OffsetType \&o)}} Remove the offset -\code{o} from the stencil of active neighborhood positions. Offsets are -relative to the neighborhood center. - -\index{ShapedNeighborhoodIterator!ClearActiveList()} -\item \textbf{\code{void ClearActiveList()}} Deactivate all positions in the -iterator stencil by clearing the active list. - -\index{ShapedNeighborhoodIterator!GetActiveIndexListSize()} -\item \textbf{\code{unsigned int GetActiveIndexListSize()}} Return the number -of pixel locations that are currently active in the shaped iterator stencil. - -\end{itemize} - -Because the neighborhood is less rigidly defined in the shaped iterator, the -set of pixel access methods is restricted. Only the \code{GetPixel()} and -\code{SetPixel()} methods are available, and calling these methods on an -inactive neighborhood offset will return undefined results. - -For the common case of traversing all pixel offsets in a neighborhood, the -shaped iterator class provides an iterator through the active offsets in its -stencil. This \emph{stencil iterator} can be incremented or decremented and -defines \code{Get()} and \code{Set()} for reading and writing the values in the -neighborhood. - -\begin{itemize} -\index{ShapedNeighborhoodIterator!Iterator::Begin()} -\item \textbf{\code{ShapedNeighborhoodIterator::Iterator Begin()}} Return a -const or non-const iterator through the shaped iterator stencil that points to -the first valid location in the stencil. - -\index{ShapedNeighborhoodIterator!Iterator::End()} -\item \textbf{\code{ShapedNeighborhoodIterator::Iterator End()}} Return a -const or non-const iterator through the shaped iterator stencil that points -\emph{one position past} the last valid location in the stencil. -\end{itemize} - -The functionality and interface of the shaped neighborhood iterator is best -described by example. We will use the ShapedNeighborhoodIterator to -implement some binary image morphology algorithms (see \cite{Gonzalez1993}, -\cite{Castleman1996}, et al.). The examples that follow implement erosion and -dilation. - -\index{ShapedNeighborhoodIterator!examples of} -\subsubsection{Shaped neighborhoods: morphological operations} -\label{sec:ShapedNeighborhoodExample} -\input{ShapedNeighborhoodIterators1.tex} -\input{ShapedNeighborhoodIterators2.tex} - -%./Common/itkConstShapedNeighborhoodIterator.h -%./Common/itkShapedNeighborhoodIterator.h - -\index{Iterators!neighborhood|)} - -% ADD A SECTION WITH TIPS, SUGGESTIONS ON USING ITERATORS? EXTENDING ITERATORS? -% USING ITERATORS FOR MULTITHREADING EXAMPLE? -\index{Iterators!image|)} diff --git a/Documentation/SoftwareGuide/Latex/Persistent.tex b/Documentation/SoftwareGuide/Latex/Persistent.tex deleted file mode 100644 index 5474815669d596f2c934908274a8d6d1b5dab4a5..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/Persistent.tex +++ /dev/null @@ -1,262 +0,0 @@ -\chapter{Persistent filters} -\label{chapter:PersistentFilters} - -\section{Introduction} - -As presented in chapter~\ref{sec:StreamingAndThreading}, OTB has two -main mechanisms to handle efficiently large data: streaming allows to -process image piece-wise, and multi-threading allows to process -concurrently several pieces of one streaming block. Using these -concepts, one can easily write pixel-wise or neighborhood-based -filters and insert them into a pipeline which will be scalable with -respect to the input image size. - -Yet, sometimes we need to compute global features on the whole image. One -example is to determine image mean and variance of the input image in -order to produce a centered and reduced image. The operation of -centering and reducing each pixel is fully compliant with streaming and -threading, but one has to first estimate the mean and variance of the -image. This first step requires to walk the whole image once, and -traditional streaming and multi-threading based filter architecture is -of no help here. - -This is because there is a fundamental difference between these two -operations: one supports streaming, and the other needs to perform -streaming. In fact we would like to stream the whole image piece by -piece through some filter that will collect and keep mean and variance -cumulants, and then synthetize theses cumulants to compute the final -mean and variance once the full image as been streamed. Each -stream would also benefit from parallel processing. This is exactly -what persistent filters are for. - -\section{Architecture} - -There are two main objects in the persistent filters framework. The -first is the \doxygen{otb}{PersistentImageFilter}, the second is the -\doxygen{otb}{PersistentFilterStreamingDecorator}. - -\subsection{The persistent filter class} - -The \doxygen{otb}{PersistentImageFilter} class is a regular -\doxygen{itk}{ImageToImageFilter}, with two additional pure virtual -methods: the \verb?Synthetize()? and the \verb?Reset()? methods. - -Imagine that the \verb?GenerateData()? or -\verb?ThreadedGenerateData()? progressively computes some global -feature of the whole image, using some member of the class to store -intermediate results. The \verb?Synthetize()? is an additional method -which is designed to be called one the whole image has been processed, -in order to compute the final results from the intermediate -results. The \verb?Reset()? method is designed to allow the reset of -the intermediate results members so as to start a fresh processing. - -Any sub-class of the \doxygen{otb}{PersistentImageFilter} can be used -as a regular \doxygen{itk}{ImageToImageFilter} (provided that both -\verb?Synthetize()? and \verb?Reset()? have been implemented, but the -real interest of these filters is to be used with the streaming -decorator class presented in the next section. - -\subsection{The streaming decorator class} - -The \doxygen{otb}{PersistentFilterStreamingDecorator} is a class -designed to be templated with subclasses of the -\doxygen{otb}{PersistentImageFilter}. It provides the mechanism to -stream the whole image through the templated filter, using a third -class called \doxygen{otb}{StreamingImageVirtualWriter}. When the -\verb?Update()? method is called on a -\doxygen{otb}{PersistentFilterStreamingDecorator}, a pipeline -plugging the templated subclass of the -\doxygen{otb}{PersistentImageFilter} to an instance of -\doxygen{otb}{StreamingImageVirtualWriter} is created. The latter is -then updated, and acts like a regular -\doxygen{otb}{ImageFileWriter} but it does not actually write -anything to the disk : streaming pieces are requested and immediately -discarded. The \doxygen{otb}{PersistentFilterStreamingDecorator} -also calls the \verb?Reset()? method at the beginning and the -\verb?Synthetize()? method at the end of the streaming -process. Therefore, it packages the whole mechanism for the use of a -\doxygen{otb}{PersistentImageFilter}: -\begin{enumerate} -\item Call the \verb?Reset()? method on the filter so as to reset any temporary - results members, -\item Stream the image piece-wise through the filter, -\item Call the \verb?Synthetize()? method on the filter so as to - compute the final results. -\end{enumerate} - -There are some methods that allows to tune the behavior of the -\doxygen{otb}{StreamingImageVirtualWriter}, allowing to change the -image splitting methods (tiles or strips) or the size of the streams -with respect to some target available amount of memory. Please see the -class documentation for details. The instance of the -\doxygen{otb}{StreamingImageVirtualWriter} can be retrieved from the -\doxygen{otb}{PersistentFilterStreamingDecorator} through the -\verb?GetStreamer()? method. - -Though the internal filter of the -\doxygen{otb}{PersistentFilterStreamingDecorator} can be accessed -through the \verb?GetFilter()? method, the class is often derived to -package the streaming-decorated filter and wrap the parameters setters -and getters. - -\section{An end-to-end example} - -This is an end-to-end example to compute the mean over a full image, -using a streaming and threading-enabled filter. Please note that only -specific details are explained here. For more general information on -how to write a filter, please refer to -section~\ref{chapter:WriteAFilter}, page~\pageref{chapter:WriteAFilter}. - -\subsection{First step: writing a persistent filter} - -The first step is to write a persistent mean image filter. We need to -include the appropriate header : - -\begin{cppcode} -#include "otbPersistentImageFilter.h" -\end{cppcode} - -Then, we declare the class prototype as follows: - -\begin{cppcode} -template<class TInputImage > - class ITK_EXPORT PersistentMeanImageFilter : - public PersistentImageFilter<TInputImage, TInputImage> -\end{cppcode} - -Since the output image will only be used for streaming purpose, we do -not need to declare different input and output template types. - -In the \emph{private} section of the class, we will declare a member which -will be used to store temporary results, and a member which will be -used to store the final result. - -\begin{cppcode} -private: - // Temporary results container - std::vector<PixelType> m_TemporarySums; - - // Final result member - double m_Mean; -\end{cppcode} - -Next, we will write the \verb?Reset()? method implementation in the -\emph{protected} section of the class. Proper allocation of the -temporary results container with respect to the number of threads is -handled here. - - -\begin{cppcode} -protected: - virtual void Reset() - { - // Retrieve the number of threads - unsigned int numberOfThreads = this->GetNumberOfThreads(); - - // Reset the temporary results container - m_TemporarySums = std::vector<PixelType>(numberOfThreads, - itk::NumericTraits<PixelType>::Zero); - - // Reset the final result - m_Mean = 0.; - } -\end{cppcode} - -Now, we need to write the \verb?ThreadedGenerateData()? methods (also -in the \emph{protected} section), were -temporary results will be computed for each piece of stream. - -\begin{cppcode} -virtual void ThreadedGenerateData(const RegionType& - outputRegionForThread, itk::ThreadIdType threadId) -{ -// Enable progress reporting -itk::ProgressReporter(this,threadId,outputRegionForThread.GetNumberOfPixels()); - -// Retrieve the input pointer -InputImagePointer inputPtr = const_cast<TInputImage *>(this->GetInput()); - -// Declare an iterator on the region -itk::ImageRegionConstIteratorWithIndex<TInputImage> it(inputPtr, -outputRegionForThread); - -// Walk the region of the image with the iterator -for (it.GoToBegin(); !it.IsAtEnd(); ++it, progress.CompletedPixel()) - { - // Retrieve pixel value - const PixelType& value = it.Get(); - - // Update temporary results for the current thread - m_TemporarySums[threadId]+= value; -} - -\end{cppcode} - -Last, we need to define the \verb?Synthetize()? method (still in the -\emph{protected} section), which will yield the final results: - -\begin{cppcode} -virtual void Synthetize() -{ -// For each thread -for(unsigned int threadId = 0; threadId <this->GetNumberOfThreads();++threadId) - { - // Update final result - m_Mean+=m_TemporarySums[threadId]; -} - -// Complete calculus by dividing by the total number of pixels: -unsigned int nbPixels = -this->GetInput()->GetLargestPossibleRegion().GetNumberOfPixels(); - -if(nbPixels!=0) - { - m_Mean/=nbPixels; - } -} -\end{cppcode} - -\subsection{Second step: Decorating the filter and using it} - -Now, to use the filter, one only has to decorate it with the -\doxygen{otb}{PersistentFilterStreamingDecorator}. First step is -to include the appropriate header: - -\begin{cppcode} -#include "otbPersistentMeanImageFilter.h" -#include "otbPersistentFilterStreamingDecorator.h" -\end{cppcode} - -Then, we decorate the filter with some typedefs: - -\begin{cppcode} -typedef otb::PersistentMeanImageFilter<ImageType> - PersitentMeanFilterType; -typedef otb::PersistentFilterStreamingDecorator - < PersitentMeanFilterType> StreamingMeanFilterType; -\end{cppcode} - -Now, the decorated filter can be used like any standard filter: - -\begin{cppcode} -StreamingMeanFilterType::Pointer filter = - StreamingMeanFilterType::New(); - -filter->SetInput(reader->GetOutput()); -filter->Update(); -\end{cppcode} - -\subsection{Third step: one class to rule them all} - -It is often convenient to avoid the few typedefs of the previous -section by deriving a new class from the decorated filter: - -\begin{cppcode} -template<class TInputImage > - class ITK_EXPORT StreamingMeanImageFilter : - public PersistentFilterStreamingDecorator< - PersistentImageFilter<TInputImage, TInputImage> > -\end{cppcode} - -This also allows to redefine setters and getters for parameters, -avoiding to call the \verb?GetFilter()? method to set them. diff --git a/Documentation/SoftwareGuide/Latex/SoftwareGuide.tex b/Documentation/SoftwareGuide/Latex/SoftwareGuide.tex index bad44d644ec9cf58482e9b5952d4280103fa2fe8..1af3a1f0746d5577d1db5b0342442ac00dbd5b67 100644 --- a/Documentation/SoftwareGuide/Latex/SoftwareGuide.tex +++ b/Documentation/SoftwareGuide/Latex/SoftwareGuide.tex @@ -211,15 +211,6 @@ colorlinks,linkcolor={blue},citecolor={blue},urlcolor={blue}, \mainmatter -\part{Introduction}\label{part:introduction} - -\input{SystemOverview.tex} - -\part{Tutorials}\label{part:tutorials} - -\input{Tutorial.tex} - - \part{User's guide}\label{part:userguide} \input{DataRepresentation.tex} @@ -237,21 +228,8 @@ colorlinks,linkcolor={blue},citecolor={blue},urlcolor={blue}, \input{Classification.tex} \input{ObjectBasedImageAnalysis.tex} \input{ChangeDetection.tex} -\input{Hyperspectral.tex} \input{Visualization.tex} -%%% \input{Applications.tex} - - - -\part{Developer's guide}\label{part:developerguide} -\input{Iterators.tex} -\input{StreamingAndThreading.tex} -\input{WriteAFilter.tex} -\input{Persistent.tex} -\input{WriteAnApplication.tex} -\input{WriteModules.tex} - \backmatter %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Documentation/SoftwareGuide/Latex/StreamingAndThreading.tex b/Documentation/SoftwareGuide/Latex/StreamingAndThreading.tex deleted file mode 100644 index 760e4e285c015306ac61a40dc7ea07b5294224d9..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/StreamingAndThreading.tex +++ /dev/null @@ -1,81 +0,0 @@ -\chapter{Streaming and Threading} -\label{sec:StreamingAndThreading} - -\index{Streaming}\index{Threading} - -Streaming and threading are a complex issue in computing in general. This -chapter provides the keys to help you understand how it is working so you can -make the right choices later. - -\section{Introduction} - -First, you have to be aware that streaming and threading are two different -things even if they are linked to a certain extent. In OTB: - -\begin{itemize} -\item Streaming describes the ability to combine the processing of several -portion of a big image and to make the output identical as what you would have -got if the whole image was processed at once. Streaming is compulsory when -you're processing gigabyte images. -\item Threading is the ability to process simultaneously different parts of the -image. Threading will give you some benefits only if you have a fairly recent -processor (dual, quad core and some older P4). -\end{itemize} - - - -To sum up: streaming is good if you have big images, threading is good if you -have several processing units. - -However, these two properties are not unrelated. Both rely on the filter ability -to process parts of the image and combine the result, that what the -ThreadedGenerateData() method can do. - -\section{Streaming and threading in OTB} - -For OTB, streaming is pipeline related while threading is filter related. If you -build a pipeline where one filter is not streamable, the whole pipeline is not -streamable: at one point, you would hold the entire image in memory. Whereas you -will benefit from a threaded filter even if the rest of the pipeline is made of -non-threadable filters (the processing time will be shorter for this particular -filter). - - -Even if you use a non streamed writer, each filter which has a -ThreadedGenerateData() will split the image into two and send each part to one -thread and you will notice two calls to the function. - -If you have some particular requirement and want to use only one thread, you can -call the SetNumberOfThreads() method on each of your filter. - -When you are writing your own filter, you have to follow some rules to make your -filter streamable and threadable. Some details are provided in sections -\ref{sec:StreamingLargeData} and \ref{sec:ThreadedFilterExecution}. - - -\section{Division strategies}\label{sec:Splitters} -% TODO -% Add details on the splitting strategies... -% - -The division of the image occurs generally at the writer level. Different -strategies are available and can be specified explicitly. In OTB, these are -referred as {\em splitter}. Several available splitters are: - -\begin{itemize} -\item \doxygen{itk}{ImageRegionSplitter} -\item \doxygen{itk}{ImageRegionMultidimensionalSplitter} -\item \doxygen{otb}{ImageRegionNonUniformMultidimensionalSplitter} -\end{itemize} - -You can add your own strategies based on these examples. - -To change the splitting strategy of the writer, you can use the following model: - -\begin{verbatim} - typedef otb::ImageRegionNonUniformMultidimensionalSplitter<3> splitterType; - splitterType::Pointer splitter=splitterType::New() ; - writer->SetRegionSplitter(splitter); -\end{verbatim} - - diff --git a/Documentation/SoftwareGuide/Latex/SystemOverview.tex b/Documentation/SoftwareGuide/Latex/SystemOverview.tex deleted file mode 100644 index 67715ffe09aee8b52b6a12ef8f9caa3f6b6c5280..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/SystemOverview.tex +++ /dev/null @@ -1,389 +0,0 @@ -\chapter{System Overview} -\label{chapter:SystemOverview} - -The purpose of this chapter is to provide you with an overview of the -\emph{ORFEO Toolbox} system. We recommend that you read this chapter to -gain an appreciation for the breadth and area of application of -OTB. In this chapter, we will make reference either to \emph{OTB - features} or \emph{ITK features} without distinction. Bear in mind -that OTB uses ITK as its core element, so all the fundamental elements -of OTB come from ITK. OTB extends the functionalities of ITK for the -remote sensing image processing community. We benefit from the Open -Source development approach chosen for ITK, which allows us to provide -an impressive set of functionalities with much less effort than -would have been the case in a closed source universe! - -\section{System Organization} -\label{sec:SystemOrganization} - -The Orfeo Toolbox consists of several subsystems: - -\begin{description} - \item[Essential System Concepts.] Like any software system, OTB is - built around some core design concepts. OTB uses those of - ITK. Some of the more important - concepts include generic programming, smart pointers for memory - management, object factories for adaptable object instantiation, - event management using the command/observer design paradigm, and - multithreading support. - - \item[Numerics] OTB, as ITK uses VXL's VNL numerics libraries. These are - easy-to-use C++ wrappers around the Netlib Fortran numerical - analysis routines (\url{http://www.netlib.org}). - - \item[Data Representation and Access.] Two principal classes - are used to represent data: the \doxygen{otb}{Image} and - \doxygen{itk}{Mesh} classes. In addition, various types of - iterators and containers are used in ITK to hold and traverse - the data. Other important but less popular classes are also - used to represent data such as histograms. - - \item[ITK's Data Processing Pipeline.] The data representation - classes (known as \emph{data objects}) are operated on by - \emph{filters} that in turn may be organized into data flow - \emph{pipelines}. These pipelines maintain state and therefore - execute only when necessary. They also support - multi-threading, and are streaming capable (i.e., can operate - on pieces of data to minimize the memory footprint). - - \item[IO Framework.] Associated with the data processing - pipeline are \emph{sources}, filters that initiate the - pipeline, and \emph{mappers}, filters that terminate the - pipeline. The standard examples of sources and mappers are - \emph{readers} and \emph{writers} respectively. Readers - input data (typically from a file), and writers output data - from the pipeline. \emph{Viewers} are another example of mappers. - - \item[Spatial Objects.] Geometric shapes are represented in - OTB using the ITK spatial object hierarchy. These classes are - intended to support modeling of anatomical structures in - ITK. OTB uses them in order to model cartographic elements. Using a - common basic interface, the spatial objects are capable of - representing regions of space in a variety of different - ways. For example: mesh structures, image masks, and implicit - equations may be used as the underlying representation scheme. - Spatial objects are a natural data structure for communicating - the results of segmentation methods and for introducing - geometrical priors in both segmentation and registration - methods. - - \item[ITK's Registration Framework.] A flexible framework for - registration supports four different types of registration: - image registration, multiresolution registration, PDE-based - registration, and FEM (finite element method) registration. - - \item[FEM Framework.] ITK includes a subsystem for solving general - FEM problems, in particular non-rigid registration. The FEM package - includes mesh definition (nodes and elements), loads, and boundary - conditions. - - \item[Level Set Framework.] The level set framework is a set of - classes for creating filters to solve partial differential equations - on images using an iterative, finite difference update scheme. The - level set framework consists of finite difference solvers including a - sparse level set solver, a generic level set segmentation filter, and - several specific subclasses including threshold, Canny, and Laplacian - based methods. - - \item[Wrapping.] ITK uses a unique, powerful system for - producing interfaces (i.e., ``wrappers'') to interpreted - languages such as Tcl and Python. The GCC\_XML tool is used to - produce an XML description of arbitrarily complex C++ code; - CSWIG is then used to transform the XML description into - wrappers using the \href{http://www.swig.org/}{SWIG} - package. OTB does not use this system at present. - -%% \item[Auxiliary / Utilities] Several auxiliary subsystems are -%% available to supplement other classes in the system. For example, -%% calculators are classes that perform specialized operations in -%% support of filters (e.g., MeanCalculator computes the mean of a -%% sample). Other utilities include GDAL format file -%% support, png, zlib, FLTK / Qt image viewers, and interfaces to the -%% Visualization Toolkit (VTK) system. - -\end{description} - - -\section{Essential System Concepts} -\label{sec:EssentialSystemConcepts} - -This section describes some of the core concepts and implementation features -found in ITK and therefore also in OTB. - -\subsection{Generic Programming} -\label{sec:GenericProgramming} - -\index{generic programming} -\index{template} - -Generic programming is a method of organizing libraries consisting of -generic---or reusable---software components. The idea is to -make software that is capable of ``plugging together'' in an efficient, -adaptable manner. The essential ideas of generic programming are -\emph{containers} to hold data, \emph{iterators} to access the data, and -\emph{generic algorithms} that use containers and iterators to create -efficient, fundamental algorithms such as sorting. Generic programming is -implemented in C++ with the \emph{template} programming mechanism and the -use of the STL Standard Template Library. - -C++ templating is a programming technique allowing users to write software in -terms of one or more unknown types \code{T}. To create executable code, the -user of the software must specify all types \code{T} (known as \emph{template -instantiation}) and successfully process the code with the compiler. The -\code{T} may be a native type such as -\code{float} or \code{int}, or \code{T} may be a user-defined type (e.g., -\code{class}). At compile-time, the compiler makes sure that the templated -types are compatible with the instantiated code and that the types are -supported by the necessary methods and operators. - -ITK uses the techniques of generic programming in its implementation. The -advantage of this approach is that an almost unlimited variety of data types -are supported simply by defining the appropriate template types. For example, -in OTB it is possible to create images consisting of almost any type of -pixel. In addition, the type resolution is performed at compile-time, so the -compiler can optimize the code to deliver maximal performance. The -disadvantage of generic programming is that many compilers still do not -support these advanced concepts and cannot compile OTB. And even if they do, -they may produce completely undecipherable error messages due to even the -simplest syntax errors. - -\subsection{Include Files and Class Definitions} -\label{sec:IncludeFiles} - -In ITK and OTB classes are defined by a maximum of two files: a header \code{.h} file -and an implementation file---\code{.cxx} if a non-templated class, and a -\code{.hxx} if a templated class. -The header files contain class declarations -and formatted comments that are used by the Doxygen documentation -system to automatically produce HTML manual pages. - -In addition to class headers, there are a few other important ITK header files. -\begin{description} - \item[\code{itkMacro.h}] defines standard system-wide macros (such as \code{Set/Get}, - constants, and other parameters). - - \item[\code{itkNumericTraits.h}] defines numeric characteristics for native types such - as its maximum and minimum possible values. - - \item[\code{itkWin32Header.h}] is used to define operating system parameters to control - the compilation process. -\end{description} - -\subsection{Object Factories} -\label{sec:ObjectFactories} - -\index{object factory} -\index{factory} - -Most classes in OTB are instantiated through an \emph{object factory} -mechanism. That is, rather than using the standard C++ class constructor and -destructor, instances of an OTB class are created with the static class -\code{New()} method. In fact, the constructor and destructor are -\code{protected:} so it is generally not possible to construct an OTB -instance on the heap. (Note: this behavior pertains to classes that are -derived from \doxygen{itk}{LightObject}. In some cases the need for speed or -reduced memory footprint dictates that a class not be derived from -LightObject and in this case instances may be created on the heap. An -example of such a class is \doxygen{itk}{EventObject}.) - -The object factory enables users to control run-time instantiation of classes -by registering one or more factories with \doxygen{itk}{ObjectFactoryBase}. These -registered factories support the method \code{CreateInstance(classname)} -which takes as input the name of a class to create. The factory can choose to -create the class based on a number of factors including the computer system -configuration and environment variables. For example, in a particular -application an OTB user may wish to deploy their own class implemented using -specialized image processing hardware (i.e., to realize a performance -gain). By using the object factory mechanism, it is possible at run-time to -replace the creation of a particular OTB filter with such a custom class. (Of -course, the class must provide the exact same API as the one it is -replacing.) To do this, the user compiles their class (using the same compiler, -build options, etc.) and inserts the object code into a shared library or -DLL. The library is then placed in a directory referred to by the -\code{OTB\_AUTOLOAD\_PATH} environment variable. On instantiation, the object -factory will locate the library, determine that it can create a class of a -particular name with the factory, and use the factory to create the -instance. (Note: if the \code{CreateInstance()} method cannot find a factory -that can create the named class, then the instantiation of the class falls -back to the usual constructor.) - -In practice object factories are used mainly (and generally transparently) by -the OTB input/output (IO) classes. For most users the greatest impact is on -the use of the \code{New()} method to create a class. Generally the -\code{New()} method is declared and implemented via the macro -\code{itkNewMacro()} found in \code{Modules/Core/Common/include/itkMacro.h}. - - -\subsection{Smart Pointers and Memory Management} -\label{sec:SmartPointers} - -\index{smart pointer} - -By their nature object-oriented systems represent and operate on data through -a variety of object types, or classes. When a particular class is -instantiated to produce an instance of that class, memory allocation occurs -so that the instance can store data attribute values and method pointers -(i.e., the vtable). This object may then be referenced by other classes or -data structures during normal operation of the program. Typically during -program execution all references to the instance may disappear at which point -the instance must be deleted to recover memory resources. Knowing when to -delete an instance, however, is difficult. Deleting the instance too soon -results in program crashes; deleting it too late and memory leaks (or -excessive memory consumption) will occur. This process of allocating and -releasing memory is known as memory management. - -In ITK, memory management is implemented through reference counting. This -compares to another popular approach---garbage collection---used -\index{garbage collection} by many -systems including Java. In reference counting, a count of the number of -references to each instance is kept. When the reference goes to zero, the -object destroys itself. In garbage collection, a background process sweeps -the system identifying instances no longer referenced in the system and -deletes them. The problem with garbage collection is that the actual point in -time at which memory is deleted is variable. This is unacceptable when an -object size may be gigantic (think of a large 3D volume gigabytes in -size). Reference counting deletes memory immediately (once all references to -an object disappear). - -Reference counting is implemented through a \code{Register()}/\code{Delete()} -member function interface. All instances of an OTB object have a -\code{Register()} method invoked on them by any other object that references -an them. The \code{Register()} method increments the instances' reference -count. When the reference to the instance disappears, a \code{Delete()} -method is invoked on the instance that decrements the reference count---this -is equivalent to an \code{UnRegister()} method. When the reference count -returns to zero, the instance is destroyed. - -This protocol is greatly simplified by using a helper class called a -\doxygen{itk}{SmartPointer}. The smart pointer acts like a regular pointer -(e.g. supports operators \code{->} and \code{*}) but automagically performs a -\code{Register()} when referring to an instance, and an \code{UnRegister()} -when it no longer points to the instance. Unlike most other instances in -OTB, SmartPointers can be allocated on the program stack, and are -automatically deleted when the scope that the SmartPointer was created -is closed. As a result, you should \emph{rarely if ever call Register() or -Delete()} in OTB. For example: - -\small -\begin{verbatim} - MyRegistrationFunction() - { <----- Start of scope - - // here an interpolator is created and associated to the - // SmartPointer "interp". - InterpolatorType::Pointer interp = InterpolatorType::New(); - - } <------ End of scope -\end{verbatim} -\normalsize - -In this example, reference counted objects are created (with the \code{New()} -method) with a reference count of one. Assignment to the SmartPointer -\code{interp} does not change the reference count. At the end of scope, -\code{interp} is destroyed, the reference count of the actual interpolator -object (referred to by \code{interp}) is decremented, and if it reaches zero, -then the interpolator is also destroyed. - -Note that in ITK SmartPointers are always used to refer to instances of -classes derived from \doxygen{itk}{LightObject}. Method invocations and function -calls often return ``real'' pointers to instances, but they are immediately -assigned to a SmartPointer. Raw pointers are used for non-LightObject classes when -the need for speed and/or memory demands a smaller, faster class. - - -\section{Data Representation} -\label{sec:DataRepresentationAndAccess} - -\index{data object} - -\index{otb::Image} - -\doxygen{otb}{Image} represents an \emph{n}-dimensional, regular sampling of -data. The sampling direction is parallel to each of the coordinate axes, and -the origin of the sampling, inter-pixel spacing, and the number of samples in -each direction (i.e., image dimension) can be specified. The sample, or -pixel, type in OTB is arbitrary---a template parameter \code{TPixel} -specifies the type upon template instantiation. (The dimensionality of the -image must also be specified when the image class is instantiated.) The key -is that the pixel type must support certain operations (for example, addition -or difference) if the code is to compile in all cases (for example, to be -processed by a particular filter that uses these operations). In practice the -OTB user will use a C++ simple type (e.g., \code{int}, \code{float}) or a pre-defined pixel -type and will rarely create a new type of pixel class. - -One of the important ITK concepts regarding images is that rectangular, -continuous pieces of the image are known as \emph{regions}. Regions are used -to specify which part of an image to process, for example in multithreading, -or which part to hold in memory. In ITK there are three common types of -regions: -\begin{enumerate} -\item \code{LargestPossibleRegion}---the image in its entirety. -\item \code{BufferedRegion}---the portion of the image retained in memory. -\item \code{RequestedRegion}---the portion of the region requested by a -filter or other class when operating on the image. -\end{enumerate} - -The \doxygen{otb}{Image} class extends the functionalities of the -\doxygen{itk}{Image} in order to take into account particular remote -sensing features as geographical projections, etc. - -\section{Data Processing Pipeline} -\label{sec:DataProcessingPipeline} - -\index{data processing pipeline} - -\index{process object} -\index{source} -\index{reader} -\index{filter} -\index{mapper} - -While data objects (e.g., images) are used to represent data, -\emph{process objects} are classes that operate on data objects and may -produce new data objects. Process objects are classed as -\emph{sources}, \emph{filter objects}, or \emph{mappers}. Sources (such as -readers) produce data, filter objects take in data and process it to produce -new data, and mappers accept data for output either to a file or -some other system. Sometimes the term \emph{filter} is used broadly -to refer to all three types. - -\index{streaming} - -The data processing pipeline ties together data objects (e.g., images) -and process objects. The pipeline supports an automatic updating -mechanism that causes a filter to execute if and only if its input -or its internal state changes. Further, the data pipeline supports -\emph{streaming}, the ability to automatically break data into smaller -pieces, process the pieces one by one, and reassemble the processed data into -a final result. - -Typically data objects and process objects are connected together using the -\code{SetInput()} and \code{GetOutput()} methods as follows: - -\small -\begin{verbatim} - typedef otb::Image<float,2> FloatImage2DType; - - itk::RandomImageSource<FloatImage2DType>::Pointer random; - random = itk::RandomImageSource<FloatImage2DType>::New(); - random->SetMin(0.0); - random->SetMax(1.0); - - itk::ShrinkImageFilter<FloatImage2DType,FloatImage2DType>::Pointer shrink; - shrink = itk::ShrinkImageFilter<FloatImage2DType,FloatImage2DType>::New(); - shrink->SetInput(random->GetOutput()); - shrink->SetShrinkFactors(2); - - otb::ImageFileWriter::Pointer<FloatImage2DType> writer; - writer = otb::ImageFileWriter::Pointer<FloatImage2DType>::New(); - writer->SetInput (shrink->GetOutput()); - writer->SetFileName( ``test.raw'' ); - writer->Update(); -\end{verbatim} -\normalsize - -In this example the source object \doxygen{itk}{RandomImageSource} is connected -to the \doxygen{itk}{ShrinkImageFilter}, and the shrink filter is connected to -the mapper \doxygen{otb}{ImageFileWriter}. When the \code{Update()} method is -invoked on the writer, the data processing pipeline causes each of these -filters in order, culminating in writing the final data to a file on disk. diff --git a/Documentation/SoftwareGuide/Latex/Tutorial.tex b/Documentation/SoftwareGuide/Latex/Tutorial.tex deleted file mode 100644 index 0c5a94d820f56edf15f500a22c68e0f2d34fdb7f..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/Tutorial.tex +++ /dev/null @@ -1,364 +0,0 @@ -\chapter{Building Simple Applications with OTB} -\label{chap:Tutorials} - -Well, that's it, you've just downloaded and installed OTB, lured by the promise -that you will be able to do everything with it. That's true, you will be able -to do everything but - there is always a {\em but} - some effort is required. - -OTB uses the very powerful systems of generic programming, many classes are -already available, some powerful tools are defined to help you with recurrent -tasks, but it is not an easy world to enter. - -These tutorials are designed to help you enter this world and grasp the logic -behind OTB. Each of these tutorials should not take more than 10 minutes (typing -included) and each is designed to highlight a specific point. You may not be -concerned by the latest tutorials but it is strongly advised to go through the -first few which cover the basics you'll use almost everywhere. - - -\section{Hello world} -\label{sec:TutorialHelloWorld} - -\index{Hello World} - -\subsection{Linux and Mac OS X} - -Let's start by the typical {\em Hello world} program. We are going to compile -this C++ program linking to your new OTB. - -First, create a new folder to put your new programs (all the examples from this -tutorial) in and go into this folder. - -Since all programs using OTB are handled using the CMake system, we need to create a -\code{CMakeLists.txt} that will be used by CMake to compile our program. An -example of this file can be found in the \code{OTB/Examples/Tutorials} -directory. The \code{CMakeLists.txt} will be very similar between your projects. - -Open the \code{CMakeLists.txt} file and write in the few lines: - -\begin{cmakecode} -PROJECT(Tutorials) - -cmake_minimum_required(VERSION 3.1.0) - -FIND_PACKAGE(OTB) -IF(OTB_FOUND) - INCLUDE(${OTB_USE_FILE}) -ELSE(OTB_FOUND) - MESSAGE(FATAL_ERROR - "Cannot build OTB project without OTB. Please set OTB_DIR.") -ENDIF(OTB_FOUND) - -ADD_EXECUTABLE(HelloWorldOTB HelloWorldOTB.cxx ) -TARGET_LINK_LIBRARIES(HelloWorldOTB ${OTB_LIBRARIES}) -\end{cmakecode} - - -The first line defines the name of your project as it appears in Visual Studio -(it will have no effect under UNIX or Linux). The second line loads a CMake file -with a predefined strategy for finding OTB \footnote{Similar files are provided -in CMake for other commonly used libraries, all of them named -\code{Find*.cmake}}. If the strategy for finding OTB fails, CMake will prompt -you for the directory where OTB is installed in your system. In that case you -will write this information in the \code{OTB\_DIR} variable. The line \code{ -INCLUDE(\$\{USE\_OTB\_FILE\})} loads the \code{UseOTB.cmake} file to set all the -configuration information from OTB. - -The line \code{ADD\_EXECUTABLE} defines as its first argument the name of the -executable that will be produced as result of this project. The remaining -arguments of \code{ADD\_EXECUTABLE} are the names of the source files to be -compiled and linked. Finally, the \code{TARGET\_LINK\_LIBRARIES} line specifies -which OTB libraries will be linked against this project. - -\input HelloWorldOTB.tex - -Once the file is written, run \code{ccmake} on the current directory -(that is \code{ccmake ./} under Linux/Unix). If OTB is -on a non standard place, you will have to tell CMake where it is. Once your -done with CMake (you shouldn't have to do it anymore) run \code{make}. - -You finally have your program. When you run it, you will have the {\em OTB Hello -World !} printed. - -Ok, well done! You've just compiled and executed your first OTB program. Actually, -using OTB for that is not very useful, and we doubt that you downloaded OTB only -to do that. It's time to move on to a more advanced level. - -\subsection{Windows} -\label{sec:FirstWinAppOTB} - -Create a directory (with write access) where to store your work (for example at C:\textbackslash path\textbackslash to\textbackslash MyFirstCode). -Organize your repository as it : -\begin{itemize} -\item MyFirstCode\textbackslash src -\item MyFirstCode\textbackslash build -\end{itemize} - -Follow the following steps: -\begin{enumerate} -\item Create a CMakeLists.txt into the src repository with the following lines: - - -\begin{cmakecode} -project(MyFirstProcessing) - -cmake_minimum_required(VERSION 3.1.0) - -find_package(OTB REQUIRED) -include(${OTB_USE_FILE}) - -add_executable(MyFirstProcessing MyFirstProcessing.cxx ) - -target_link_libraries(MyFirstProcessing ${OTB_LIBRARIES} ) -\end{cmakecode} - -\item Create a MyFirstProcessing.cxx into the src repository with the following lines: - -\begin{cppcode} -#include "otbImage.h" -#include "otbVectorImage.h" -#include "otbImageFileReader.h" -#include "otbImageFileWriter.h" -#include "otbMultiToMonoChannelExtractROI.h" - -int main(int argc, char* argv[]) -{ - if (argc < 3) - { - std::cerr << "Usage: " << std::endl; - std::cerr << argv[0] << " inputImageFile outputImageFile" << std::endl; - return EXIT_FAILURE; - } - - typedef unsigned short PixelType; - typedef otb::Image <PixelType, 2> ImageType; - typedef otb::VectorImage <PixelType, 2> VectorImageType; - typedef otb::MultiToMonoChannelExtractROI <PixelType, PixelType> FilterType; - typedef otb::ImageFileReader<VectorImageType> ReaderType; - typedef otb::ImageFileWriter<ImageType> WriterType; - - FilterType::Pointer filter = FilterType::New(); - ReaderType::Pointer reader = ReaderType::New(); - WriterType::Pointer writer = WriterType::New(); - - reader->SetFileName(argv[1]); - filter->SetInput(reader->GetOutput()); - writer->SetFileName(argv[2]); - writer->SetInput(filter->GetOutput()); - - return EXIT_SUCCESS; -} -\end{cppcode} -\item create a file named BuildMyFirstProcessing.bat into the MyFirstCode directory with the following lines: -\begin{batcode} -@echo off - -set /A ARGS_COUNT=0 -for %%A in (%*) do set /A ARGS_COUNT+=1 -if %ARGS_COUNT% NEQ 3 (goto :Usage) - -if NOT DEFINED OSGEO4W_ROOT (goto :NoOSGEO4W) - -set src_dir=%1 -set build_dir=%2 -set otb_install_dir=%3 -set current_dir=%CD% - -cd %build_dir% - -cmake %src_dir% ^ - -DCMAKE_INCLUDE_PATH:PATH="%OSGEO4W_ROOT%\include" ^ - -DCMAKE_LIBRARY_PATH:PATH="%OSGEO4W_ROOT%\lib" ^ - -DOTB_DIR:PATH=%otb_install_dir% ^ - -DCMAKE_CONFIGURATION_TYPES:STRING=Release - -cmake --build . --target INSTALL --config Release - -cd %current_dir% - -goto :END - -:Usage -echo You need to provide 3 arguments to the script: -echo 1. path to the source directory -echo 2. path to the build directory -echo 3. path to the installation directory -GOTO :END - -:NoOSGEO4W -echo You need to run this script from an OSGeo4W shell -GOTO :END - -:END -\end{batcode} -\item into a OSGEo4W shell, run the configure.bat with the right arguments: full path to your src directory, full path to your build directory, full path to the place where find OTBConfig.cmake file (should be C:\textbackslash path\textbackslash to\textbackslash MyOTBDir\textbackslash install\textbackslash lib\textbackslash otb). -\item into the OSGeo4W shell, open the MyFirstProcessing.sln -\item build the solution -\item into the OSGeo4W shell, go to the bin\textbackslash Release directory and run MyFirstProcessing.exe. You can try for example with the otb\_logo.tif file which can be found into the OTB source. -\end{enumerate} - -\section{Pipeline basics: read and write} -\label{sec:TutorialPipeline} - -\index{Reader, Writer, Pipeline} - -OTB is designed to read images, process them and write them to disk or -view the result. In this tutorial, we are going to see how to read and -write images and the basics of the pipeline system. - -First, let's add the following lines at the end of the \code{CMakeLists.txt} -file: - -\begin{cmakecode} -ADD_EXECUTABLE(Pipeline Pipeline.cxx ) -TARGET_LINK_LIBRARIES(Pipeline ${OTB_LIBRARIES}) -\end{cmakecode} - - -Now, create a \code{Pipeline.cxx} file. - -\input Pipeline.tex - -Once this file is written you just have to run \code{make}. The -\code{ccmake} call is not required anymore. - -Get one image from the \code{OTB-Data/Examples} directory from the OTB-Data -repository. You can get it either by cloning the OTB data repository -(\code{git clone https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb-data.git}), but that might be quite -long as this also gets the data to run the tests. Alternatively, you can get it from -\url{http://www.orfeo-toolbox.org/packages/OTB-Data-Examples.tgz}. -Take for example get \code{QB\_Suburb.png}. - -Now, run your new program as \code{Pipeline QB\_Suburb.png output.png}. You -obtain the file \code{output.png} which is the same image as -\code{QB\_Suburb.png}. When you triggered the \code{Update()} method, OTB opened -the original image and wrote it back under another name. - -Well\ldots that's nice but a bit complicated for a copy program! - -Wait a minute! We didn't specify the file format anywhere! Let's try -\code{Pipeline QB\_Suburb.png output.jpg}. And voila! The output image is a jpeg -file. - -That's starting to be a bit more interesting: this is not just a program to copy -image files, but also to convert between image formats. - -You have just experienced the pipeline structure which executes the -filters only when needed and the automatic image format detection. - -Now it's time to do some processing in between. - - -\section{Filtering pipeline} -\label{sec:TutorialFiltering} - -\index{Filter, Pipeline} - -We are now going to insert a simple filter to do some processing between the -reader and the writer. - -Let's first add the 2 following lines to the \code{CMakeLists.txt} file: - -\begin{cmakecode} -ADD_EXECUTABLE(FilteringPipeline FilteringPipeline.cxx ) -TARGET_LINK_LIBRARIES(FilteringPipeline ${OTB_LIBRARIES}) -\end{cmakecode} - -\input{FilteringPipeline.tex} - -Compile with \code{make} and execute as \code{FilteringPipeline QB\_Suburb.png -output.png}. - -You have the filtered version of your image in the \code{output.png} file. - -Now, you can practice a bit and try to replace the filter by one of the 150+ -filters which inherit from the \doxygen{itk}{ImageToImageFilter} class. You -will definitely find some useful filters here! - -\section{Handling types: scaling output} -\label{sec:TutorialScaling} - -If you tried some other filter in the previous example, you may have noticed -that in some cases, it does not make sense to save the output directly as an -integer. This is the case if you tried the -\doxygen{itk}{CannyEdgeDetectionImageFilter}. If you tried to use it directly in -the previous example, you will have some warning about converting to unsigned -char from double. - -The output of the Canny edge detection is a floating point number. A simple -solution would be to used double as the pixel type. Unfortunately, most image -formats use integer typed and you should convert the result to an integer image if you -still want to visualize your images with your usual viewer (we will see in a -tutorial later how you can avoid that using the built-in viewer). - -To realize this conversion, we will use the -\doxygen{itk}{RescaleIntensityImageFilter}. - -Add the two lines to the \code{CMakeLists.txt} file: - -\begin{cmakecode} -ADD_EXECUTABLE(ScalingPipeline ScalingPipeline.cxx ) -TARGET_LINK_LIBRARIES(ScalingPipeline ${OTB_LIBRARIES}) -\end{cmakecode} - -\input{ScalingPipeline} - -As you should be getting used to it by now, compile with \code{make} and execute -as \code{ScalingPipeline QB\_Suburb.png output.png}. - -You have the filtered version of your image in the \code{output.png} file. - -\section{Working with multispectral or color images} - -So far, as you may have noticed, we have been working with grey level images, -i.e. with only one spectral band. If you tried to process a color image with -some of the previous examples you have probably obtained a deceiving grey -result. - -Often, satellite images combine several spectral band to help the -identification of materials: this is called multispectral imagery. In this -tutorial, we are going to explore some of the mechanisms used by OTB to -process multispectral images. - -Add the following lines in the \code{CMakeLists.txt} file: - -\begin{cmakecode} -ADD_EXECUTABLE(Multispectral Multispectral.cxx ) -TARGET_LINK_LIBRARIES(Multispectral ${OTB_LIBRARIES}) -\end{cmakecode} - -\input{Multispectral} - -Compile with \code{make} and execute as \code{./Multispectral qb\_RoadExtract.tif - qb\_blue.tif qb\_shiftscale.tif}. - - - -\section{Going from raw satellite images to useful products} - -Quite often, when you buy satellite images, you end up with several images. In the case of optical satellite, you often have a panchromatic spectral band with the highest spatial resolution and a multispectral product of the same area with a lower resolution. The resolution ratio is likely to be around 4. - -To get the best of the image processing algorithms, you want to combine these data to produce a new image with the highest spatial resolution and several spectral band. This step is called fusion and you can find more details about it in \ref{sec:Fusion}. However, the fusion suppose that your two images represents exactly the same area. There are different solutions to process your data to reach this situation. Here we are going to use the metadata available with the images to produce an orthorectification as detailed in \ref{sec:Ortho}. - -First you need to add the following lines in the \code{CMakeLists.txt} file: - -\begin{cmakecode} -ADD_EXECUTABLE(OrthoFusion OrthoFusion.cxx) -TARGET_LINK_LIBRARIES(OrthoFusion ${OTB_LIBRARIES}) -\end{cmakecode} - -\input{OrthoFusion} - - -% \section{Multiband images} - -% \section{GUI} -% -% Basic GUI -% -% \section{Better GUI} -% -% Road extraction viewer - - - diff --git a/Documentation/SoftwareGuide/Latex/WriteACompositeFilter.tex b/Documentation/SoftwareGuide/Latex/WriteACompositeFilter.tex deleted file mode 100644 index 7642389965d66c27672881049859bcf7677e3dfe..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/WriteACompositeFilter.tex +++ /dev/null @@ -1,77 +0,0 @@ - -\section{How To Write A Composite Filter} - -In general, most ITK/OTB filters implement one particular algorithm, -whether it be image filtering, an information metric, or a -segmentation algorithm. In the previous section, we saw how to write -new filters from scratch. However, it is often very useful to be able -to make a new filter by combining two or more existing filters, which -can then be used as a building block in a complex pipeline. This -approach follows the Composite pattern \cite{Gamma1995}, whereby the -composite filter itself behaves just as a regular filter, providing -its own (potentially higher level) interface and using other filters -(whose detail is hidden to users of the class) for the implementation. -This composite structure is shown in -Figure~\ref{fig:CompositeFilterStages}, where the various -\code{Stage-n} filters are combined into one by the \code{Composite} -filter. The \code{Source} and \code{Sink} filters only see the -interface published by the \code{Composite}. Using the Composite -pattern, a composite filter can encapsulate a pipeline of arbitrary -complexity. These can in turn be nested inside other pipelines. - -\begin{figure} - \centering - \includegraphics[width=0.9\textwidth]{CompositeFilterStages.eps} - \itkcaption[Composite Filter Concept]{A Composite filter encapsulates a number of other filters.} - \label{fig:CompositeFilterStages} -\end{figure} - -\subsection{Implementing a Composite Filter} - -There are a few considerations to take into account when implementing a -composite filter. All the usual requirements for filters apply (as -discussed above), but the following guidelines should be considered: - -\begin{enumerate} - -\item The template arguments it takes must be sufficient to instantiate all of -the component filters. Each component filter needs a type supplied by either -the implementor or the enclosing class. For example, an -\code{ImageToImageFilter} normally takes an input and output image type (which -may be the same). But if the output of the composite filter is a classified -image, we need to either decide on the output type inside the composite filter, -or restrict the choices of the user when she/he instantiates the filter. - -\item The types of the component filters should be declared in the header, - preferably with \code{protected} visibility. This is because the - internal structure normally should not be visible to users of the class, - but should be to descendent classes that may need to modify or customize - the behavior. - -\item The component filters should be private data members of the composite - class, as in \code{FilterType::Pointer}. - -\item The default constructor should build the pipeline by creating the - stages and connect them together, along with any default parameter - settings, as appropriate. - -\item The input and output of the composite filter need to be grafted on to - the head and tail (respectively) of the component filters. - -\end{enumerate} - -This grafting process is illustrated in Figure~\ref{fig:CompositeExamplePipeline}. - - -\subsection{A Simple Example} - -\begin{figure} - \centering - \includegraphics[width=0.9\textwidth]{CompositeExamplePipeline.eps} - \itkcaption[Composite Filter Example]{Example of a typical composite filter. Note that the output of the last filter in the internal pipeline must be grafted into the output of the composite filter.} - \label{fig:CompositeExamplePipeline} -\end{figure} - -\input{CompositeFilterExample.tex} - -%--------------------------------------------------------------------------- diff --git a/Documentation/SoftwareGuide/Latex/WriteAFilter.tex b/Documentation/SoftwareGuide/Latex/WriteAFilter.tex deleted file mode 100644 index c210051ca6a0b14cfcf294cbce7065c893170e17..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/WriteAFilter.tex +++ /dev/null @@ -1,584 +0,0 @@ -\chapter{How To Write A Filter} -\label{chapter:WriteAFilter} - -This purpose of this chapter is help developers create their own -filter (process object). This chapter is divided into four major -parts. An initial definition of terms is followed by an overview of -the filter creation process. Next, data streaming is discussed. The -way data is streamed in ITK must be understood in order to write -correct filters. Finally, a section on multithreading describes what -you must do in order to take advantage of shared memory parallel -processing. - -\section{Terminology} -\label{sec:Terminology} - -The following is some basic terminology for the discussion that follows. -Chapter \ref{chapter:SystemOverview} provides additional background -information. - -\begin{itemize} - \item The \textbf{data processing pipeline} is a directed graph of - \textbf{process} and \textbf{data objects}. The pipeline inputs, - operators on, and outputs data. - \index{data processing pipeline} - \index{process object} - \index{data object} - - \item A \textbf{filter}, or \textbf{process object}, has one or more - inputs, and one or more outputs. - \index{filter} - - \item A \textbf{source}, or source process object, initiates the data - processing pipeline, and has one or more outputs. - \index{source} - - \item A \textbf{mapper}, or mapper process object, terminates the - data processing pipeline. The mapper has one or more outputs, and may - write data to disk, interface with a display system, or interface to - any other system. - \index{mapper} - - \item A \textbf{data object} represents and provides access to - data. In ITK, the data object (ITK class \doxygen{itk}{DataObject}) is - typically of type \doxygen{otb}{Image} or \doxygen{itk}{Mesh}. - \index{data object} - - \item A \textbf{region} (ITK class \doxygen{itk}{Region}) represents a - piece, or subset of the entire data set. - \index{region} - - \item An \textbf{image region} (ITK class \doxygen{itk}{ImageRegion}) - represents a structured portion of data. ImageRegion is implemented - using the \doxygen{itk}{Index} and \doxygen{itk}{Size} classes - \index{image region} - - \item A \textbf{mesh region} (ITK class \doxygen{itk}{MeshRegion}) - represents an unstructured portion of data. - \index{mesh region} - - \item The \textbf{LargestPossibleRegion} is the theoretical single, - largest piece (region) that could represent the entire dataset. The - LargestPossibleRegion is used in the system as the measure of the - largest possible data size. - \index{LargestPossibleRegion} - - \item The \textbf{BufferedRegion} is a contiguous block of memory - that is less than or equal to in size to the - LargestPossibleRegion. The buffered region is what has actually been - allocated by a filter to hold its output. - \index{BufferedRegion} - - \item The \textbf{RequestedRegion} is the piece of the dataset that a - filter is required to produce. The RequestedRegion is less than or - equal in size to the BufferedRegion. The RequestedRegion may differ - in size from the BufferedRegion due to performance reasons. The - RequestedRegion may be set by a user, or by an application that needs - just a portion of the data. - \index{RequestedRegion} - - \item The \textbf{modified time} (represented by ITK class - \doxygen{itk}{TimeStamp}) is a monotonically increasing integer value that - characterizes a point in time when an object was last modified. - \index{modified time} - - \item \textbf{Downstream} is the direction of dataflow, from sources - to mappers. - \index{pipeline!downstream} - - \item \textbf{Upstream} is the opposite of downstream, from mappers - to sources. - \index{pipeline!upstream} - - \item The \textbf{pipeline modified time} for a particular data - object is the maximum modified time of all upstream data objects and - process objects. - \index{pipeline!modified time} - - \item The term \textbf{information} refers to metadata that - characterizes data. For example, index and dimensions are information - characterizing an image region. - \index{pipeline!information} -\end{itemize} - -\section{Overview of Filter Creation} -\label{sec:OverviewFilterCreation} -\index{filter!overview of creation} - -\itkpiccaption[Relationship between DataObjects and ProcessObjects] -{Relationship between DataObject and ProcessObject. -\label{fig:DataPipeLineOneConnection}} -\parpic(7cm,2.5cm)[r]{\includegraphics[width=6cm]{DataPipelineOneConnection.eps}} - - -Filters are defined with respect to the type of data they input (if -any), and the type of data they output (if any). The key to writing a -ITK filter is to identify the number and types of input and -output. Having done so, there are often superclasses that simplify -this task via class derivation. For example, most filters in ITK take -a single image as input, and produce a single image on output. The -superclass \doxygen{itk}{ImageToImageFilter} is a convenience class that -provide most of the functionality needed for such a filter. - -Some common base classes for new filters include: - -\begin{itemize} - - \item \code{ImageToImageFilter}: the most common filter base for - segmentation algorithms. Takes an image and produces a new image, by - default of the same dimensions. Override - \code{GenerateOutputInformation} to produce a different size. - - \item \code{UnaryFunctorImageFilter}: used when defining a filter that - applies a function to an image. - - \item \code{BinaryFunctorImageFilter}: used when defining a filter that - applies an operation to two images. - - \item \code{ImageFunction}: a functor that can be applied to an image, - evaluating $f(x) $ at each point in the image. - - \item \code{MeshToMeshFilter}: a filter that transforms meshes, such as - tessellation, polygon reduction, and so on. - - \item \code{LightObject}: abstract base for filters that don't fit well - anywhere else in the class hierarchy. Also useful for ``calculator'' - filters; ie. a sink filter that takes an input and calculates a result - which is retrieved using a \code{Get()} method. - -\end{itemize} - -Once the appropriate superclass is identified, the filter writer -implements the class defining the methods required by most all ITK -objects: \code{New()}, \code{PrintSelf()}, and protected constructor, -copy constructor, delete, and operator=, and so on. Also, don't forget -standard typedefs like \code{Self}, \code{Superclass}, \code{Pointer}, and -\code{ConstPointer}. Then the filter writer can focus on the most important -parts of the implementation: defining the API, data members, and other -implementation details of the algorithm. In particular, the filter writer -will have to implement either a \code{GenerateData()} (non-threaded) or -\code{ThreadedGenerateData()} method. (See Section~\ref{sec:MultiThreading} -for an overview of multi-threading in ITK.) - -An important note: the GenerateData() method is required to allocate memory -for the output. The ThreadedGenerateData() method is not. In default -implementation (see \doxygen{itk}{ImageSource}, a superclass of -\doxygen{itk}{ImageToImageFilter}) -\code{GenerateData()} allocates memory and then invokes -\code{ThreadedGenerateData()}. - -One of the most important decisions that the developer must make is whether -the filter can stream data; that is, process just a portion of the input to -produce a portion of the output. Often superclass behavior works well: if the -filter processes the input using single pixel access, then the default -behavior is adequate. If not, then the user may have to a) find a more -specialized superclass to derive from, or b) override one or more methods -that control how the filter operates during pipeline execution. The next -section describes these methods. - - - -\section{Streaming Large Data} -\label{sec:StreamingLargeData} -\index{pipeline!streaming large data} - -The data associated with multi-dimensional images is large and becoming larger. -This trend is due to advances in scanning resolution, as well as increases in -computing capability. Any practical segmentation and registration software -system must address this fact in order to be useful in application. ITK -addresses this problem via its data streaming facility. - -In ITK, streaming is the process of dividing data into pieces, or regions, -and then processing this data through the data pipeline. Recall that the -pipeline consists of process objects that generate data objects, connected -into a pipeline topology. The input to a process object is a data object -(unless the process initiates the pipeline and then it is a source process -object). These data objects in turn are consumed by other process objects, -and so on, until a directed graph of data flow is constructed. Eventually the -pipeline is terminated by one or more mappers, that may write data to -storage, or interface with a graphics or other system. This is illustrated in -figures \ref{fig:DataPipeLineOneConnection} and \ref{fig:DataPipeLine}. - -A significant benefit of this architecture is that the relatively complex -process of managing pipeline execution is designed into the system. This -means that keeping the pipeline up to date, executing only those portions of -the pipeline that have changed, multithreading execution, managing memory -allocation, and streaming is all built into the architecture. However, these -features do introduce complexity into the system, the bulk of which is seen -by class developers. The purpose of this chapter is to describe the pipeline -execution process in detail, with a focus on data streaming. - - -\subsection{Overview of Pipeline Execution} -\label{sec:OverviewPipelineExecution} -\index{pipeline!overview of execution} - -The pipeline execution process performs several important functions. - -\begin{figure} - \par\centering - \resizebox{5in}{!}{ \includegraphics{DataPipeline.eps}} - \itkcaption[The Data Pipeline]{The Data Pipeline} - \label{fig:DataPipeLine} - \par -\end{figure} - -\begin{enumerate} - \item It determines which filters, in a pipeline of filters, need to - execute. This prevents redundant execution and minimizes overall - execution time. - - \item It initializes the (filter's) output data objects, preparing - them for new data. In addition, it determines how much memory each - filter must allocate for its output, and allocates it. - - \item The execution process determines how much data a filter must - process in order to produce an output of sufficient size for - downstream filters; it also takes into account any limits on memory - or special filter requirements. Other factors include the size of - data processing kernels, that affect how much data input data - (extra padding) is required. - - \item It subdivides data into subpieces for multithreading. (Note - that the division of data into subpieces is exactly same problem as - dividing data into pieces for streaming; hence multithreading comes - for free as part of the streaming architecture.) - - \item It may free (or release) output data if filters no longer need - it to compute, and the user requests that data is to be - released. (Note: a filter's output data object may be considered a - ``cache''. If the cache is allowed to remain (\code{ReleaseDataFlagOff()}) - between pipeline execution, and the filter, or the input to the - filter, never changes, then process objects downstream of the filter - just reuse the filter's cache to re-execute.) -\end{enumerate} - -To perform these functions, the execution process negotiates with the -filters that define the pipeline. Only each filter can know how much data is -required on input to produce a particular output. For example, a shrink -filter with a shrink factor of two requires an image twice as large (in terms -of its x-y dimensions) on input to produce a particular size output. An -image convolution filter would require extra input (boundary padding) -depending on the size of the convolution kernel. Some filters require the -entire input to produce an output (for example, a histogram), and have the -option of requesting the entire input. (In this case streaming does not work -unless the developer creates a filter that can request multiple pieces, -caching state between each piece to assemble the final output.) - - -\begin{figure} - \par\centering - \resizebox{5in}{!}{ \includegraphics{DataPipelineUpdate.eps}} - \itkcaption[Sequence of the Data Pipeline updating mechanism]{Sequence of the -Data Pipeline updating mechanism} - \label{fig:DataPipeLineUpdate} - \par -\end{figure} - - -Ultimately the negotiation process is controlled by the request for data of a -particular size (i.e., region). It may be that the user asks to process a -region of interest within a large image, or that memory limitations result in -processing the data in several pieces. For example, an application may -compute the memory required by a pipeline, and then use -\doxygen{itk}{StreamingImageFilter} to break the data processing into several pieces. -The data request is propagated through the pipeline in the upstream -direction, and the negotiation process configures each filter to produce -output data of a particular size. - -The secret to creating a streaming filter is to understand how this -negotiation process works, and how to override its default behavior by using -the appropriate virtual functions defined in \doxygen{itk}{ProcessObject}. The next -section describes the specifics of these methods, and when to override -them. Examples are provided along the way to illustrate concepts. - - -\subsection{Details of Pipeline Execution} -\label{sec:DetailsPipelineExecution} -\index{pipeline!execution details} - -Typically pipeline execution is initiated when a process object -receives the \code{ProcessObject::Update()} method invocation. This -method is simply delegated to the output of the filter, invoking the -\code{DataObject::Update()} method. Note that this behavior is typical -of the interaction between ProcessObject and DataObject: a method -invoked on one is eventually delegated to the other. In this way the -data request from the pipeline is propagated upstream, initiating data -flow that returns downstream. - -The \code{DataObject::Update()} method in turn invokes three other methods: - -\begin{itemize} - \item \code{DataObject::UpdateOutputInformation()} - \item \code{DataObject::PropagateRequestedRegion()} - \item \code{DataObject::UpdateOutputData()} -\end{itemize} - -\subsubsection{UpdateOutputInformation()} -\label{sec:UpdateOutputInformation} -\index{pipeline!UpdateOutputInformation} - -The \code{UpdateOutputInformation()} method determines the pipeline modified -time. It may set the RequestedRegion and the LargestPossibleRegion depending -on how the filters are configured. (The RequestedRegion is set to process all -the data, i.e., the LargestPossibleRegion, if it has not been set.) The -UpdateOutputInformation() propagates upstream through the entire pipeline and -terminates at the sources. - -During \code{UpdateOutputInformation()}, filters have a chance to override the -\code{ProcessObject::GenerateOutputInformation()} method -(\code{GenerateOutputInformation()} is invoked by -\code{UpdateOutputInformation()}). The default behavior is for the -\code{GenerateOutputInformation()} to copy the metadata describing the input -to the output (via \code{DataObject::CopyInformation()}). Remember, information -is metadata describing the output, such as the origin, spacing, -and LargestPossibleRegion (i.e., largest possible size) of an image. - -A good example of this behavior is \doxygen{itk}{ShrinkImageFilter}. This filter -takes an input image and shrinks it by some integral value. The result is that -the spacing and LargestPossibleRegion of the output will be different to that -of the input. Thus, \code{GenerateOutputInformation()} is overloaded. - -\subsubsection{PropagateRequestedRegion()} -\label{sec:PropagateRequestedRegion} -\index{pipeline!PropagateRequestedRegion} - -The \code{PropagateRequestedRegion()} call propagates upstream to -satisfy a data request. In typical application this data request is usually the -LargestPossibleRegion, but if streaming is necessary, or the user is -interested in updating just a portion of the data, the RequestedRegion may be -any valid region within the LargestPossibleRegion. - -The function of \code{PropagateRequestedRegion()} is, given a request -for data (the amount is specified by RequestedRegion), propagate -upstream configuring the filter's input and output process object's to -the correct size. Eventually, this means configuring the -BufferedRegion, that is the amount of data actually allocated. - -The reason for the buffered region is this: the output of a filter may be -consumed by more than one downstream filter. If these consumers each request -different amounts of input (say due to kernel requirements or other padding -needs), then the upstream, generating filter produces the data to satisfy -both consumers, that may mean it produces more data than one of the -consumers needs. - -The \code{ProcessObject::PropagateRequestedRegion()} method invokes -three methods that the filter developer may choose to overload. - -\begin{itemize} - \item \code{EnlargeOutputRequestedRegion(DataObject *output)} gives the - (filter) subclass a chance to indicate that it will provide more data - than required for the output. This can happen, for example, when a - source can only produce the whole output (i.e., the - LargestPossibleRegion). - - \item \code{GenerateOutputRequestedRegion(DataObject *output)} gives - the subclass a chance to define how to set the requested regions for - each of its outputs, given this output's requested region. The default - implementation is to make all the output requested regions the same. - A subclass may need to override this method if each output is a - different resolution. This method is only overridden if a filter has - multiple outputs. - - \item \code{GenerateInputRequestedRegion()} gives the subclass a - chance to - request a larger requested region on the inputs. This is necessary - when, for example, a filter requires more data at the ``internal'' - boundaries to produce the boundary values - due to kernel operations - or other region boundary effects. -\end{itemize} - -\doxygen{itk}{RGBGibbsPriorFilter} is an example of a filter that needs to -invoke \code{EnlargeOutputRequestedRegion()}. The designer of this -filter decided that the filter should operate on all the data. Note -that a subtle interplay between this method and -\code{GenerateInputRequestedRegion()} is occurring here. The default -behavior of \code{GenerateInputRequestedRegion()} (at least for -\doxygen{itk}{ImageToImageFilter}) is to set the input RequestedRegion to -the output's ReqestedRegion. Hence, by overriding the method -\code{EnlargeOutputRequestedRegion()} to set the output to the -LargestPossibleRegion, effectively sets the input to this filter to -the LargestPossibleRegion (and probably causing all upstream filters -to process their LargestPossibleRegion as well. This means that the -filter, and therefore the pipeline, does not stream. This could be -fixed by reimplementing the filter with the notion of streaming built -in to the algorithm.) - -\doxygen{itk}{GradientMagnitudeImageFilter} is an example of a filter that needs to -invoke \code{GenerateInputRequestedRegion()}. It needs a larger input requested -region because a kernel is required to compute the gradient at a pixel. Hence -the input needs to be ``padded out'' so the filter has enough data to compute -the gradient at each output pixel. - -\subsubsection{UpdateOutputData()} -\label{sec:UpdateOutputData} -\index{pipeline!UpdateOutputData} - -\code{UpdateOutputData()} is the third and final method as a result of the -\code{Update()} method. The purpose of this method is to determine whether a -particular filter needs to execute in order to bring its output up to date. (A -filter executes when its \code{GenerateData()} method is invoked.) Filter -execution occurs when a) the filter is modified as a result of modifying an -instance variable; b) the input to the filter changes; c) the input data has -been released; or d) an invalid RequestedRegion was set previously and the -filter did not produce data. Filters execute in order in the downstream -direction. Once a filter executes, all filters downstream of it must also -execute. - -\code{DataObject::UpdateOutputData()} is delegated to the DataObject's source -(i.e., the ProcessObject that generated it) only if the DataObject needs to be -updated. A comparison of modified time, pipeline time, release data flag, and -valid requested region is made. If any one of these conditions indicate that -the data needs regeneration, then the source's -\code{ProcessObject::UpdateOutputData()} is invoked. These calls are made -recursively up the pipeline until a source filter object is encountered, or the -pipeline is determined to be up to date and valid. At this point, the recursion -unrolls, and the execution of the filter proceeds. (This means that the output -data is initialized, StartEvent is invoked, the filters \code{GenerateData()} -is called, EndEvent is invoked, and input data to this filter may be released, -if requested. In addition, this filter's InformationTime is updated to the -current time.) - -The developer will never override \code{UpdateOutputData()}. The developer need -only write the \code{GenerateData()} method (non-threaded) or -\code{ThreadedGenerateData()} method. A discussion of threading follows in the -next section. - - -\section{Threaded Filter Execution} -\label{sec:ThreadedFilterExecution} -\index{pipeline!ThreadedFilterExecution} - -Filters that can process data in pieces can typically multi-process -using the data parallel, shared memory implementation built into the -pipeline execution process. To create a multithreaded filter, simply -define and implement a \code{ThreadedGenerateData()} method. For -example, a \doxygen{itk}{ImageToImageFilter} would create the method: - -\small -\begin{verbatim} - void ThreadedGenerateData(const OutputImageRegionType& - outputRegionForThread, itk::ThreadIdType threadId) -\end{verbatim} -\normalsize - -The key to threading is to generate output for the output region given (as -the first parameter in the argument list above). In ITK, this is simple to do -because an output iterator can be created using the region provided. Hence -the output can be iterated over, accessing the corresponding input pixels as -necessary to compute the value of the output pixel. - -Multi-threading requires caution when performing I/O (including using -\code{cout} or \code{cerr}) or invoking events. A safe practice is to allow -only thread id zero to perform I/O or generate events. (The thread id is -passed as argument into \code{ThreadedGenerateData()}). If more than one -thread tries to write to the same place at the same time, the program can -behave badly, and possibly even deadlock or crash. - - -\section{Filter Conventions} -\label{sec:FilterConventions} -\index{pipeline!filter conventions} - -In order to fully participate in the ITK pipeline, filters are expected to -follow certain conventions, and provide certain interfaces. This section -describes the minimum requirements for a filter to integrate into the ITK -framework. - -The class declaration for a filter should include the macro -\code{ITK\_EXPORT}, so that on certain platforms an export declaration can be -included. - -A filter should define public types for the class itself (\code{Self}) and -its \code{Superclass}, and \code{const} and non-\code{const} smart pointers, -thus: - -\begin{verbatim} - typedef ExampleImageFilter Self; - typedef ImageToImageFilter<TImage,TImage> Superclass; - typedef SmartPointer<Self> Pointer; - typedef SmartPointer<const Self> ConstPointer; -\end{verbatim} - -The \code{Pointer} type is particularly useful, as it is a smart pointer -that will be used by all client code to hold a reference-counted -instantiation of the filter. - -Once the above types have been defined, you can use the following -convenience macros, which permit your filter to participate in the object -factory mechanism, and to be created using the canonical \code{::New()}: - -\begin{verbatim} - /** Method for creation through the object factory. */ - itkNewMacro(Self); - - /** Run-time type information (and related methods). */ - itkTypeMacro(ExampleImageFilter, ImageToImageFilter); -\end{verbatim} - -The default constructor should be \code{protected}, and provide sensible -defaults (usually zero) for all parameters. The copy constructor and -assignment operator should be declared \code{private} and not implemented, -to prevent instantiating the filter without the factory methods (above). - -Finally, the template implementation code (in the \code{.hxx} file) should -be included, bracketed by a test for manual instantiation, thus: - -\begin{verbatim} -#ifndef ITK_MANUAL_INSTANTIATION -#include "itkExampleFilter.hxx" -#endif -\end{verbatim} - -\subsection{Optional} -\label{sec:FilterPrinting} -\index{pipeline!printing a filter} - -A filter can be printed to an \code{std::ostream} (such as \code{std::cout}) -by implementing the following method: - -\begin{verbatim} - void PrintSelf( std::ostream& os, Indent indent ) const; -\end{verbatim} - -\noindent and writing the name-value pairs of the filter parameters to the -supplied output stream. This is particularly useful for debugging. - -\subsection{Useful Macros} -\label{sec:UsefulMacros} -\index{pipeline!useful macros} - -Many convenience macros are provided by ITK, to simplify filter coding. -Some of these are described below: - -\begin{description} -\item [itkStaticConstMacro] Declares a static variable of the given type, - with the specified initial value. -\item [itkGetMacro] Defines an accessor method for the specified scalar data - member. The convention is for data members to have a prefix of - \code{m\_}. -\item [itkSetMacro] Defines a mutator method for the specified scalar data - member, of the supplied type. This will automatically set the - \code{Modified} flag, so the filter stage will be executed on the next - \code{Update()}. -\item [itkBooleanMacro] Defines a pair of \code{OnFlag} and \code{OffFlag} - methods for a boolean variable \code{m\_Flag}. -\item [itkGetObjectMacro, itkSetObjectMacro] Defines an accessor and mutator - for an ITK object. The Get form returns a smart pointer to the object. -\end{description} - -Much more useful information can be learned from browsing the source in -\code{Code/Common/itkMacro.h} and for the \doxygen{itk}{Object} and -\doxygen{itk}{LightObject} classes. - - - -% -% Section on how to write composite filters -% -\input{WriteACompositeFilter.tex} - - -% -% TODO: include useful tips from mailing list as flagged -% diff --git a/Documentation/SoftwareGuide/Latex/WriteAnApplication.tex b/Documentation/SoftwareGuide/Latex/WriteAnApplication.tex deleted file mode 100644 index 0ff0c7c2ac1dbb9b7bdda5beef01f71ef909c60a..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/WriteAnApplication.tex +++ /dev/null @@ -1,288 +0,0 @@ -\chapter{How to write an application} -\label{sec:writeAnApplication} - -This chapter presents the different steps to write your own application. -It also contains a description of the framework surrounding the applications. - -\section{Application design} -\label{sec:appDesign} -The first logical step is to define the role of your application: -\begin{itemize} - \item 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. - \item 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. -\end{itemize} -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 \ref{sec:appParam}). - -\section{Architecture of the class} -\label{sec:appArchitecture} -Every application derive from the class \subdoxygen{otb}{Wrapper}{Application}. An -application can't be templated. It must contain the standard class typedefs and -a call to the \code{OTB\_APPLICATION\_EXPORT} macro. - -You need also to define standard macros \doxygen{itk}{NewMacro} and -\doxygen{itk}{TypeMacro}. - -It is also mandatory to implement three methods in a new application: -\begin{itemize} - \item \code{DoInit()} - \item \code{DoUpdateParameters()} - \item \code{DoExecute()} -\end{itemize} - -\subsection{DoInit()} -\label{sec:appDoInit} -This method is called once, when the application is instantiated. It should -contain the following actions: -\begin{itemize} - \item Set the name and the description of the application - \item Fill the documentation and give an example - \item Declare all the parameters - \item Define the documentation link: - \item for contrib application use SetDocLink("\textit{docLink}") function defined in \subdoxygen{otb}{Wrapper}{Application} - \item for official application use SetOfficialDocLink() function defined in \subdoxygen{otb}{Wrapper}{Application} -\end{itemize} - - -\subsection{DoUpdateParameters()} -\label{sec:appDoUpdateParameters} -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 and relationship -between parameters (e.g. in ExtractROI: when changing the input image, maybe the ROI size -has to be updated). - -\subsection{DoExecute()} -\label{sec:appDoExecute} -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: -\begin{itemize} - \item \code{GetParameterInt(key)} : get the integer value of a parameter - \item \code{GetParameterFloat(key)} : get the float value of a parameter - \item \code{GetParameterString(key)} : get the string value of a parameter - \item \code{GetParameterImage(key)} : get a pointer to an image object, read from the - file name given in input - \item \dots -\end{itemize} - -where \code{key} refers to parameter key, defined using \code{AddParameter()} method in \code{DoInit()} method. - -Similar methods exist for binding a data object to an output parameter: -\begin{itemize} - \item \code{SetParameterOutputImage(key,data)} : link the image object to the given output parameter - \item \code{SetParameterComplexOutputImage(key,data)} : link the complex image object to the given output parameter - \item \code{SetParameterOutputVectorData(key,data)} : link the vector data object to the given - output parameter -\end{itemize} - -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. - -\subsection{Parameters selection} -\label{sec:appParam} -In the new application framework, every input, output or parameter derive from -\subdoxygen{otb}{Wrapper}{Parameter}. The application engine supplies the following -types of parameters: -\begin{itemize} - \item \code{ParameterType\_Bool} : parameter storing a boolean. - \item \code{ParameterType\_Int} : parameter storing an integer. - \item \code{ParameterType\_Radius} : parameter storing a radius. - \item \code{ParameterType\_Float} : parameter storing a float. - \item \code{ParameterType\_String} : parameter storing character string. - \item \code{ParameterType\_StringList} : parameter storing a list of character string. - \item \code{ParameterType\_InputFilename} : parameter storing an input file name. - \item \code{ParameterType\_InputFilenameList} : parameter storing a list of input file names. - \item \code{ParameterType\_Directory} : parameter storing a folder name. - \item \code{ParameterType\_Group} : parameter storing children parameters. - \item \code{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. - \item \code{ParameterType\_ListView} : parameter storing a list of choices (support - multi-choice and single-choice). - \item \code{ParameterType\_InputImage} : parameter storing an input image. - \item \code{ParameterType\_InputImageList} : parameter storing a list of input image. - \item \code{ParameterType\_ComplexInputImage} : parameter storing a complex input image. - \item \code{ParameterType\_InputVectorData} : parameter storing input vector data. - \item \code{ParameterType\_InputVectorDataList} : parameter storing a list of input vector data. - \item \code{ParameterType\_InputProcessXML} : parameter storing an input XML file name. - \item \code{ParameterType\_OutputFilename} : parameter storing an output file name. - \item \code{ParameterType\_OutputImage} : parameter storing an output image. - \item \code{ParameterType\_ComplexOutputImage} : parameter storing a complex output image. - \item \code{ParameterType\_OutputVectorData} : parameter storing an output vector data. - \item \code{ParameterType\_OutputProcessXML} : parameter storing an output XML file name. - \item \code{ParameterType\_RAM} : parameter storing the maximum amount of RAM to be used. -\end{itemize} -\textbf{Note :} The former \code{ParameterType\_Empty} is \textbf{deprecated} and shall be replaced by \code{ParameterType\_Bool}. - -\subsection{Parameters description} - -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 \code{DoInit()} method, then the framework will set their value (either by parsing the -command line or reading the graphical user interface). The \code{DoExecute()} method is called when all -mandatory parameters have been given a value, which can be obtained with "Get" methods defined in -\subdoxygen{otb}{Wrapper}{Application}. Parameters are set mandatory (or not) using \code{MandatoryOn(key)} method (\code{MandatoryOff(key)}). - -Some functions are specific to numeric parameters, such as \code{SetMinimumParameterIntValue(key,value)} -or \code{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 -\code{SetParameterRole(key,Role\_Output)}. - -The input types \code{InputImage}, \code{InputImageList}, \code{ComplexInputImage}, \code{InputVectorData} -and \code{InputVectorDataList} store the name of the files to load, but they also encapsulate the -readers needed to produce the input data. - -The output types \code{OutputImage}, \code{ComplexOutputImage} and \code{OutputVectorData} store the -name of the files to write, but they also encapsulate the corresponding writers. - -\section{Composite application} - -The application framework has been extended to allow the implementation of composite applications : -\textbf{applications that use other applications}. The concept is simple : you have two applications A and B -that you want to chain in order to build a third application C. Rather than writing C by copying -the code of A and B, you would like to re-use applications A and B. This plain example will be -re-used in this section for explanations. - -A dedicated class \subdoxygen{otb}{Wrapper}{CompositeApplication} has been added to create such applications. -If you derive this class to implement application C, you will be able to create a composite application. - -\subsection{Creating internal applications} - -Like with standard applications, you have to write a \code{DoInit()} function. In this function, -you should first clean any internal application with the function \code{ClearApplications()} -(the \code{DoInit()} function is called twice in some cases). Then you can -instantiate the internal applications that you want to use (for instance A and B). -The function \code{AddApplication()} will do that, based on : -\begin{itemize} -\item The application type (i.e. its official name, such as ExtractROI, BandMath, \dots) -\item An identifier : like with parameter keys, you have to specify an identifier -to refer to this internal application. Use the same naming conventions as parameters. -\item A description : give a small description of the role of this internal application. -\end{itemize} - -Using the function \code{GetInternalApplication()}, you can get a pointer to the -internal application corresponding to a given identifier. - -In the example given in introduction, we assume that : -\begin{itemize} -\item An internal application of type A has been added with identifier \code{a} -\item An internal application of type B has been added with identifier \code{b} -\end{itemize} - -\subsection{Connecting parameters} - -Once you have internal applications, you may want to setup their parameters. There -are typically 3 cases. - -You may want to expose a parameter of an internal application as a parameter of -your composite application. Let say you want to expose parameter \code{io.in} from application -\code{a} into your composite application C with the key \code{input}. You can call the function : - -\code{ShareParameter("input","a.io.in")} - -As a result, the parameters \code{input} in application C and \code{io.in} in application \code{a} -will point to the same object. Under the two parameter keys, there is a unique value. -These two parameters can be considered as synchronized. - -This leads to the second case : you may want to synchronize two parameters from internal -applications. Let say you want to synchronize parameter \code{field} from application -\code{a} with parameter \code{fname} from application \code{b}. You can call the function : - -\code{Connect("a.field","b.fname")} - -Note that the functions \code{ShareParameter()} and \code{Connect()} : -\begin{itemize} -\item Use the same syntax to access internal parameters ("application identifier" -dot "parameter key"). -\item Shall be used in the DoInit() function, after the internal applications -have been added. -\end{itemize} - -In this synchronization, the two parameters should have the same type, or have a -similar interface, such as input and output filenames that are both accessed using -\code{GetParameterString()} and \code{SetParameterString()}. - -This type of connection is a transition to the third case : you may want to connect -the output of an internal application to the input of an other internal application. -Here the difficulty is that the two parameters to connect probably have different -types. Let say you want to connect parameter \code{a.out} to parameter \code{b.in}. -The "Connect()" function may work in favorable cases (see previous paragraph), -but for images, you have two options : -\begin{itemize} -\item Explicitly copy the image pointer from the output image parameter in the input -image parameter (with functions \code{SetParameterInputImage()} and -\code{GetParameterOutputImage()}). It will connect the pipelines in applications -A and B, to form an "in-memory" connexion. This has to be done between the calls -to \code{DoExecute()} of application A and B. -\item Use a temporary filename to store the output image \code{a.out} and read it -with \code{b.in}. In this case, you have to manually call the writers of parameter -\code{a.out}. -\end{itemize} - -At the moment, the in-memory connexion of vector data parameters is not supported. - -\subsection{Orchestration} - -In the \code{DoUpdateParameters()} of your composite application, you can call -the same function on an internal application with the function \code{UpdateInternalParameters()}. -This is needed only if your internal applications have a specific behaviour during -parameter update. - -In the \code{DoExecute()} of your composite application, you have to call \code{ExecuteInternal()} -in order to launch each internal application. The order should be compatible with -image parameter connexions. If you want to do "in-memory" connexions, you can do it between -two calls to \code{ExecuteInternal()}, for instance : - -\begin{cppcode} -ExecuteInternal("a"); -GetInternalApplication("b")->SetParameterInputImage("in", - GetInternalApplication("a")->GetParameterOutputImage("out")); -ExecuteInternal("b"); -\end{cppcode} - -The application BundleToPerfectSensor is a simple example of composite applications. -For a more complex example, you can check the application TrainImagesClassifier. - -\section{Compile your application} - -In order to compile your application you must call the macro \code{OTB\_CREATE\_APPLICATION} in the \emph{CMakelists.txt} file. -This macro generates the lib \emph{otbapp\_XXX.so}, in (OTB\_BINARY\_DIR/lib/otb/applications), where \emph{XXX} refers to the class name. - -\section{Execute your application} - -There are different ways to launch applicatons : - -\begin{description} -\item[CommandLine :] The command line option is invoked using \emph{otbApplicationLauncherCommandLine} executable followed by the classname, the application dir and the application parameters. -\item[QT :] Application can be encapsuled in Qt framework using \emph{otbApplicationLauncherQt} executable followed by the classname and the application dir. -\item[Python :] A Python wrapper is also available. -\end{description} - - -\section{Testing your application} -\label{sec:appTesting} -It is possible to write application tests. They are quite similar to filters tests. -The macro \code{OTB\_TEST\_APPLICATION} makes it easy to define a new test. - - -\section{Application Example} -\label{sec:ApplicationExample} -\ifitkFullVersion -\input{ApplicationExample.tex} -\fi - diff --git a/Documentation/SoftwareGuide/Latex/WriteModules.tex b/Documentation/SoftwareGuide/Latex/WriteModules.tex deleted file mode 100644 index accf14c369a99f09bfb662b6a5cd2ed7df5053ab..0000000000000000000000000000000000000000 --- a/Documentation/SoftwareGuide/Latex/WriteModules.tex +++ /dev/null @@ -1,294 +0,0 @@ -\chapter{Adding New Modules} -\label{chapter:newModules} - -This chapter is concerned with the creation of new modules. -The following sections give precise instructions about : -\begin{itemize} - \item the organization of your directories - \item the files you need to include - \item what they must contain - \item ... -\end{itemize} - -\section{How to Write a Module} -\label{sec:writemodule} - -There is a template of OTB remote module which help you start developing you're -remote module: \href{https://gitlab.orfeo-toolbox.org/remote_modules/remote-module-template}{External Module Template} - -Each module is made of different components, which are described in the following sections. - -\section{The otb-module.cmake file} - -This file is mandatory. It follows the CMake syntax, and has two purposes: - -\begin{itemize} - \item Declare dependencies to other modules, - \item Provide a short description of the module purpose. -\end{itemize} - -These purposes are fulfilled by a single CMake Macro call: - -\begin{verbatim} -otb_module(TheModuleName DEPENDS OTBModule1 OTBModule2 ... OTBModuleN DESCRIPTION "A description string") -\end{verbatim} - -\textbf{Note}: You can use the keyword TEST\textunderscore DEPENDS to declare module dependencies that only applies to the tests. - -\section{The CMakeLists.txt file} - -The CMakeLists.txt file is mandatory. It contains only a few things. -First, it declares a new CMake project with the name of the module. - -\begin{verbatim} -project(TheModuleName) -\end{verbatim} - -Second, if the module contain a library (see src folder section below), it initializes the TheModuleName\textunderscore LIBRARIES CMake variable (if your module only contains headers or template code, skip this line): - -\begin{verbatim} -set(TheModuleName_LIBRARIES OTBTheModuleName) -\end{verbatim} - -You can build your remote modules inside the OTB source tree by copying your -source inside the directory \textit{Module/Remote} or against an existing OTB -build tree (note that it does not work with an install version of OTB). - -The configuration below will handle both cases and take care of all the CMake -plumbing of the module: - -\begin{verbatim} - if(NOT OTB_SOURCE_DIR) - find_package(OTB REQUIRED) - list(APPEND CMAKE_MODULE_PATH ${OTB_CMAKE_DIR}) - include(OTBModuleExternal) - else() - otb_module_impl() - endif() -\end{verbatim} - -The overall file should look like this: - -\begin{verbatim} -cmake_minimum_required(VERSION 2.8.9) -project(TheModuleName) -set(ExternalTemplate_LIBRARIES OTBTheModuleName) - -if(NOT OTB_SOURCE_DIR) - find_package(OTB REQUIRED) - list(APPEND CMAKE_MODULE_PATH ${OTB_CMAKE_DIR}) - include(OTBModuleExternal) - else() - otb_module_impl() - endif() -\end{verbatim} - -\section{The include folder} - -The include folder will contain all your headers (*.h files) and template method boy files (*.hxx or *.hxx). It does not require any additional file (in particular, no CMakeLists.txt file is required). - -\section{The src folder } - -The src folder contains the internal implementation of your module : - -\begin{itemize} - \item It typically contains cxx source files that will be compiled into a library. - \item It can contain header files for classes used only within the implementation files of your module. Any header file present in the src folder will not be installed, and will not be available to other modules depending on your module. -\end{itemize} - -If your modules is made of template only code, you do not need a src folder at all. - -If present, the src folder requires a CMakeLists.txt file. - -The first part of the CMakeLists.txt file is classical, as it builds the library and links it: - -\begin{verbatim} -set(OTBTheModuleName_SRC - sourceFile1.cxx - sourceFile2.cxx - sourceFile3.cxx - ... - sourceFileN.cxx) - -add_library(OTBTheModuleName ${OTBTheModuleName_SRC}) - -target_link_libraries(OTBTheModuleName ${OTBModule1_LIBRARIES} ${OTBModule2_LIBRARIES} ... ${OTBModuleN_LIBRARIES}) -\end{verbatim} - -\textbf{Notes}: - -\begin{itemize} - \item Library name should match the one declared in the root CMakeLists.txt when setting CMake variable TheModuleName\textunderscore LIBRARIES, - \item Linked libraries should match the dependencies of your module declared in the root otb-module.cmake file. -\end{itemize} - -The last line of CMake code takes care of installation instructions: -\begin{verbatim} -otb_module_target(TBTheModuleName) -\end{verbatim} - -The overall CMakeLists.txt file should look like: - -\begin{verbatim} -set(OTBTheModuleName_SRC - sourceFile1.cxx - sourceFile2.cxx - sourceFile3.cxx - ... - sourceFileN.cxx) - -add_library(OTBTheModuleName ${OTBTheModuleName_SRC}) - -target_link_libraries(OTBTheModuleName ${OTBModule1_LIBRARIES} ${OTBModule2_LIBRARIES} ... ${OTBModuleN_LIBRARIES}) - -otb_module_target(TBTheModuleName) -\end{verbatim} - -\section{The app folder} - -The app folder contains the code of applications shipped with your module. If your module has no application, you do not need the app folder. - -\textbf{Notes}: If your module contains application (and an app folder), do not forget to add the ApplicationEngine in the dependencies listed in the otb-module.cmake file. - -In addition to the applications source code, the app folder should contain a CMakeLists.txt file as follows. - -For each application, a single call otb\textunderscore create\textunderscore application is required: - -\begin{verbatim} -otb_create_application( - NAME TheModuleApplication1 - SOURCES TheModuleApplication1.cxx - LINK_LIBRARIES ${OTBModule1_LIBRARIES} ${OTBModule2_LIBRARIES} ... ${OTBModuleN_LIBRARIES}) - -\end{verbatim} - -\section{The test folder} - -This folder contains tests of the module. If your module has no test in it (which is not recommended, you do not need it). - -The test folder should contain the source files of tests, as well as a CMakeLists.txt file. This file will contain the following. - -First, indicate that this folder contains tests. - -\begin{verbatim} -otb_module_test() -\end{verbatim} - -Then, build the test driver: - -\begin{verbatim} -set(OTBTheModuleNameTests - testFile1.cxx - testFile2.cxx - ... - testFileN.cxx) - -add_executable(otbTheModuleNameTestDriver ${OTBTheModuleNameTests}) - -target_link_libraries(otbTheModuleNameTestDriver ${OTBTheModuleName-Test_LIBRARIES}) - -otb_module_target_label(otbTheModuleNameTestDriver) -\end{verbatim} - -Finally, you can add your tests: - -\begin{verbatim} -otb_add_test(NAME nameOfTheTest COMMAND otbTheModuleNameTestDriver - --compare-image ${EPSILON_8} ... # baseline comparison if needed - nameOfTheTestFunction - testParameters) -\end{verbatim} - -If your module contains one or more application in the app folder, you should -also write tests for them, in the test folder. Running an application test is -easily done with the helper macro otb\textunderscore test\textunderscore -application: - -\begin{verbatim} -otb_test_application(NAME nameofApplication1Test1 - APP TheModuleApplication1 - OPTIONS -in1 ${INPUTDATA}/input1.tif - -in2 ${INPUTDATA}/input2.tif - -out ${TEMP}/nameofApplication1Test1_result.tif - VALID --compare-image ${EPSILON_8} - ${BASELINE}/nameofApplication1Test1_result.tif - ${TEMP}/nameofApplication1Test1_result.tif) -\end{verbatim} - -ToDo: Add instructions for test naming and input/baseline data inclusion. - -You overall CMakeLists.txt file should look like: - -\begin{verbatim} -otb_module_test() - -set(OTBTheModuleNameTests - testFile1.cxx - testFile2.cxx - ... - testFileN.cxx) - -add_executable(otbTheModuleNameTestDriver ${OTBTheModuleNameTests}) - -target_link_libraries(otbTheModuleNameTestDriver ${OTBTheModuleName-Test_LIBRARIES}) - -otb_module_target_label(otbTheModuleNameTestDriver) - -otb_add_test(NAME nameOfTheTest COMMAND otbTheModuleNameTestDriver - --compare-image ${EPSILON_8} ... # baseline comparison if needed - nameOfTheTestFunction - testParameters) -\end{verbatim} - -\section{Including a remote module in OTB} -\begin{itemize} - \item Local build of a remote module -\end{itemize} - -Your remote module can be build inside the OTB source tree or outside as a -external CMake project with an existing OTB. Please note in that case -that you'll have to set OTB\textunderscore DIR CMake option. - -If OTB\textunderscore DIR is an OTB build tree, there are two ways of compiling: -\begin{itemize} - \item Build as a module, in which case build files will be written - to the OTB build tree as other modules. Main benefit is that this - will enrich the current OTB build with your new module, but you - need to have write access to the build directory. - \item Build as a standalone CMake project, in which case build files - will remain in the module build folder. This build is fully - independent from the build (or install) directory, but the module - will not be recognized as an OTB module (still you will be able to - use its binaries and libraries). -\end{itemize} - -This behaviour is controlled by the OTB\textunderscore BUILD\textunderscore MODULE\textunderscore AS\textunderscore STANDALONE, which is OFF by default (hence first behaviour). - -Note that when dealing with an installed OTB, only the second behaviour (build as standalone) is available. - -Optionally, you can build your new remote module inside the OTB source tree by simply copy -the folder containing the module component to Modules/Remote, then run CMake -configuration. you should see a new CMake option named MODULE\textunderscore -TheModuleName. Simply turn this option to ON, and finish CMake -configuration. Your module will be built with the rest of the OTB project. - -\begin{itemize} - \item Sharing your remote module -\end{itemize} - -To make your remote module available to others when building OTB, you should -provide a CMake file named TheModuleName.remote.cmake file for inclusion in the -Modules/Remote folder in OTB source tree. - -This file should contain the following: - -\begin{verbatim} -#Contact: Author name <author email address> - -otb_fetch_module(TheModuleName - "A description of the module, to appear during CMake configuration step" - GIT\textunderscore REPOSITORY http\textunderscore link\textunderscore to\textunderscore a\textunderscore git\textunderscore repository\textunderscore hosting\textunderscore the\textunderscore module - GIT\textunderscore TAG the\textunderscore git\textunderscore revision\textunderscore to\textunderscore checkout - ) -\end{verbatim} -This file should be provided along with your remote module inclusion proposal email to the otb-developers list. Please refer to the contributors guidelines for more information (next section).