Chapter 9
How To Create A Module

The Insight Toolkit is organized into logical units of coherent functionality called modules. These modules are self-contained in a directory, whose components are organized into subdirectories with standardized names. A module usually has dependencies on other modules, which it declares. A module is defined with CMake scripts that inform the build system of its contents and dependencies.

The modularization effort significantly improves the extensibility of the toolkit and lowers the barrier to contribution.

Modules are organized into:

This chapter describes how to create a new module. The following sections are organized by the different directory components of the module. The chapter concludes with a section on how to add a third-party library dependency to a module.

Note that the Insight Toolkit community has adopted a Coding Style guideline for the sake of consistentcy and readability of the code. Such guideline is described in Chapter ??.

9.1 Name and dependencies

The top level directory of a module is used to define a module’s name and its dependencies. Two files are required:

  1. CMakeLists.txt
  2. itk-module.cmake

The information described in these files is used to populate <ModuleName>.cmake files in the ITK module registry. The module registry is located at <ITK build directory>/lib/cmake/5.0/Modules/ in a build tree or <CMAKE_INSTALL_PREFIX>/lib/cmake/5.0/Modules/ in an install tree. These module files declare information about the module and what is required to use it. This includes its module dependencies, C++ include directories required to build against it, the libraries to link against, and CMake code required to use it in a CMake configured project.

9.1.1 CMakeLists.txt

When CMake starts processing a module, it begins with the top level CMakeLists.txt file. At a minimum, the CMakeLists.txt should contain

  cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR)
  cmake_policy(VERSION 3.10.2)
  
  project(MyModule)
  
  set(MyModule_LIBRARIES MyModule)
  
  if(NOT ITK_SOURCE_DIR)
    find_package(ITK REQUIRED)
    list(APPEND CMAKE_MODULE_PATH ${ITK_CMAKE_DIR})
    include(ITKModuleExternal)
  else()
    itk_module_impl()
  endif()

where MyModule is the name of the module.

The CMake variable <module-name>_LIBRARIES should be set to the names of the libraries, if any, that clients of the module need to link. This will be the same name as the library generated with the add_library command in a module’s src directory, described in further detail in the Libraries Section 9.3.

The path if(NOT ITK_SOURCE_DIR) is used when developing a module outside of the ITK source tree, i.e. an External module. An External module can be made available to the community by adding it to Modules/Remote/⋆.remote.cmake Remote module index in the ITK repository per Section  ??.

The CMake macro itk_module_impl is defined in the file CMake/ITKModuleMacros.cmake. It will initiate processing of the remainder of a module’s CMake scripts. The script ITKModuleExternal calls itk_module_impl internally.

9.1.2 itk-module.cmake

The itk-module.cmake is also a required CMake script at the top level of a module, but this file is used to declare

  1. The module name.
  2. Dependencies on other modules.
  3. Modules properties.
  4. A description of the module.

In this file, first set a CMake variable with the module’s description followed by a call to the itk_module macro, which is already defined by the time the script is read. For example, itk-module.cmake for the ITKCommon module is

  set(DOCUMENTATION "This module contains the central classes of the ITK
  toolkit.  They include, basic data structures \(such as Points, Vectors,
  Images, Regions\) the core of the process objects \(such as base
  classes for image filters\) the pipeline infrastructure classes, the support
  for multi-threading, and a collection of classes that isolate ITK from
  platform specific features. It is anticipated that most other ITK modules will
  depend on this one.")
  
  itk_module(ITKCommon
    ENABLE_SHARED
    PRIVATE_DEPENDS
      ITKDoubleConversion
    COMPILE_DEPENDS
      ITKKWSys
      ITKVNLInstantiation
    TEST_DEPENDS
      ITKTestKernel
      ITKMesh
      ITKImageIntensity
      ITKIOImageBase
    DESCRIPTION
      "${DOCUMENTATION}"
  )

The description for the module should be escaped as a CMake string, and it should be formatted with Doxygen markup. This description is added to ITK’s generated Doxygen documentation when the module is added to the Remote module index. The description should describe the purpose and content of the module and reference an Insight Journal article for further information.

A module name is the only required positional argument to the itk_module macro. Named options that take one or argument are:

DEPENDS
Modules that will be publicly linked to this module. The header’s used are added to include/⋆.{h,hxx} files.
PRIVATE_DEPENDS
Modules that will be privately linked to this module. The header’s used are only added to src/⋆.cxx files.
COMPILE_DEPENDS
Modules that are needed at compile time by this module. The header’s used are added to include/⋆{h,hxx} files but there is not a library to link against.
TEST_DEPENDS
Modules that are needed by this modules testing executables. The header’s used are added to test/⋆.cxx files.
DESCRIPTION
Free text description of the module.

Public dependencies are added to the module’s INTERFACE_LINK_LIBRARIES, which is a list of transitive link dependencies. When this module is linked to by another target, the libraries listed (and recursively, their link interface libraries) will be provided to the target also. Private dependencies are linked to by this module, but not added to INTERFACE_LINK_LIBRARIES.

Compile Dependencies are added to CMake’s list of dependencies for the current module, ensuring that they are built before the current module, but they will not be linked either publicly or privately. They are only used to support the building of the current module.

The following additional options take no arguments:

EXCLUDE_FROM_DEFAULT
Exclude this module from collection of modules enabled with the ITK_BUILD_DEFAULT_MODULES CMake option.
ENABLE_SHARED
Build this module as a shared library if the BUILD_SHARED_LIBS CMake option is set.

All External and Remote modules should set the EXCLUDE_FROM_DEFAULT option.

9.2 Headers

Headers for the module, both ⋆.h declaration headers and ⋆.hxx template definition headers, should be added to the include directory. No other explicit CMake configuration is required.

This path will automatically be added to the build include directory paths for libraries (9.3) and tests (9.4) in the module and when another module declares this module as a dependency.

When a module is installed, headers are installed into a single directory common to all ITK header files.

When BUILD_TESTING is enabled, a header test is automatically created. This test simply builds a simple executable that #includes all header files in the include directory. This ensures that all included headers can be found, which tests the module’s dependency specification per Section 9.1.

9.3 Libraries

Libraries generated by a module are created from source files with the .cxx extension in a module’s src directory. Some modules are header-only, and they will not generate any libraries; in this case, the src directory is omitted. When present, the src directory should contain a CMakeLists.txt file that describes how to build the library. A minimal CMakeLists.txt file is as follows.

  set(AModuleName_SRCS
    itkFooClass.cxx
    itkBarClass.cxx
    )
  
  itk_module_add_library(AModuleName ${AModuleName_SRCS})

The itk_module_add_library macro will create a library with the given sources. The macro will also link the library to the libraries defined by the module dependency specification per Section 9.1. Additionally, the macro will set CMake target properties associated with the current module to the given target.

If the ENABLE_SHARED option is set on a module, a shared library will be generated when the CMake option BUILD_SHARED_LIBS is enabled. A library symbol export specification header is also generated for the module. For a module with the name AModuleName, the generated header will have the name AModuleNameExport.h. Include the export header in the module source headers, and add the export specification macro to the contained classes. The macro name in this case would be called AModuleName_EXPORT. For example, the file itkFooClass.h would contain

  #include "AModuleNameExport.h"
  
  namespace itk
  {
  
  class AModuleName_EXPORT FooClass
  {
  ...

Modules that do not build a library in their src directory or do not have export specifications on their class declarations should not set ENABLE_SHARED.

9.4 Tests

Regression tests for a module are placed in the test directory. This directory will contain a CMakeLists.txt with the CMake configuration, test sources, and optional Input and Baseline directories, which contain test input and baseline image datasets, respectively. Placement of the input and baseline image datasets within a given module directory is preferred over placement in the general Testing/Data directory; this ensures that a module’s data is only downloaded when the module is enabled. An exception to this rule may be widely used input datasets, such as the cthead1.png image.

An example CMake configuration for a test directory is shown below.

  itk_module_test()
  
  set(ModuleTemplateTests
    itkMinimalStandardRandomVariateGeneratorTest.cxx
    itkLogNormalDistributionImageSourceTest.cxx
    )
  
  CreateTestDriver(ModuleTemplate "${ModuleTemplate-Test_LIBRARIES}" "${ModuleTemplateTests}")
  
  itk_add_test(NAME itkMinimalStandardRandomVariateGeneratorTest
    COMMAND ModuleTemplateTestDriver itkMinimalStandardRandomVariateGeneratorTest
    )
  
  itk_add_test(NAME itkLogNormalDistributionImageSourceTest
    COMMAND ModuleTemplateTestDriver --without-threads
    --compare
      ${ITK_TEST_OUTPUT_DIR}/itkLogNormalDistributionImageSourceTestOutput.mha
      DATA{Baseline/itkLogNormalDistributionImageSourceTestOutput.mha}
    itkLogNormalDistributionImageSourceTest
      ${ITK_TEST_OUTPUT_DIR}/itkLogNormalDistributionImageSourceTestOutput.mha
    )

The CMakeLists.txt file should start with a call to the itk_module_test macro. Next, the test sources are listed. The naming convention for unit test files is itk<ClassName>Test.cxx. Each test file should be written like a command line executable, but the name of the main function should be replaced with the name of the test. The function should accept int argc, char ⋆ argv[] as arguments. To reduce the time required for linking and to provide baseline comparison functionality, all tests are linked to into a single test driver executable. To generate the executable, call the CreateTestDriver macro.

Tests are defined with the itk_add_test macro. This is a wrapper around the CMake add_test command that will resolve content links in the DATA macro. Testing data paths are given inside the DATA macro. Content link files, stored in the source code directory, are replaced by actual content files in the build directory when CMake downloads the ITKData target at build time. A content link file has the same name as its target, but a .sha512 extension is added, and the .sha512 file’s contents are only the SHA512 hash of its target. Content links for data files in a Git distributed version control repository prevent repository bloat. To obtain content links, register an account at https://data.kitware.com. Upload images to your account’s My folders/Public folder. Once the image has been uploaded, click on the item’s link, then click the Show info icon. A Download key file icon will be available to download the content link. Place this file in the repository tree where referenced by the DATA macro.

When a test requires a new (or modified) input or baseline image dataset, the corresponding content link files have to be provided as well. Image datasets provided should be kept as small as possible. As a rule of thumb, their size should be under 50 kB.

Test commands should call the test driver executable, followed by options for the test, followed by the test function name, followed by arguments that are passed to the test. The test driver accepts options like --compare (or --compare-MD5 when using the MD5SUM hash) to compare output images to baselines or options that modify tolerances on comparisons. An exhaustive list of options is displayed in itkTestDriverInclude.h.

A few rules must be acknowledged to actually write a units test file itk<ClassName>Test.cxx for a given ITK class:

  1. All class methods must be exercised.
  2. Test cases with values for member variables different from the default ones should be provided. The usefulness of this rule is especially manifest for boolean members, whose value usually determines whether a large portion of code is exercised or not.
  3. Test cases to reach the exception cases within the class should be provided.
  4. Regression tests must be included for methods returning a value.
  5. When a test detects a failure condition it must return the EXIT_FAILURE value; if a test exits normally, it must return the EXIT_SUCCESS value.

In any case, ITK provides with a number of classes and macros that ease the process of writing tests and checking the expected results. The following is an exhaustive list of such tools:

A test may have some input arguments. When a test does not need any input argument (e.g., it generates a synthetic input image), the main argument names may either be omitted (int itk<ClassName>Test( int, char⋆ [] )), or the itkNotUsed macro can be used (int itk<ClassName>Test( int itkNotUsed( argc ), char ⋆itkNotUsed( argv ) [] )), to avoid compiler warnings about unused variables.

The number of input arguments provided must be checked at the beginning of the test. If a test requires a fixed number of input arguments, then the argument number check should verify the exact number of arguments.

It is essential that a test is made quantitative, i.e., the methods’ returned values and the test’s output must be compared to a known ground-truth. As mentioned, ITK contains a series of methods to compare basic types. ITK also provide a powerful regression tool for a test that checks the validity of a process over an image, which is the most common case in ITK. To this end, the test is expected to write its output to a file. The first time the test is run, the output is expected to be manually placed within the test module’s Baseline folder. Hence, when CTest is executed, the distance between the test’s output and the expected output (i.e., the baseline) is computed. If the distance is below a configurable tolerance, the regression test is marked as a success.

9.5 Wrapping

Wrapping for programming languages like Python can be added to a module through a simple configuration in the module’s wrapping directory. While wrapping is almost entirely automatic, configuration is necessary to add two pieces of information,

  1. The types with which to instantiate templated classes.
  2. Class dependencies which must be wrapped before a given class.

When wrapping a class, dependencies, like the base class and other types used in the wrapped class’s interface, should also be wrapped. The wrapping system will emit a warning when a base class or other required type is not already wrapped to ensure proper wrapping coverage. Since module dependencies are wrapped by the build system before the current module, class wrapping build order is already correct module-wise. However, it may be required to wrap classes within a module in a specific order; this order can be specified in the wrapping/CMakeLists.txt file.

Many ITK classes are templated, which allows an algorithm to be written once yet compiled into optimized binary code for numerous pixel types and spatial dimensions. When wrapping these templated classes, the template instantiations to wrap must be chosen at build time. The template that should be used are configured in a module’s ⋆.wrap files. Wrapping is configured by calling CMake macros defined in the ITK/Wrapping/TypedefMacros.cmake file.

9.5.1 CMakeLists.txt

The wrapping/CMakeLists.txt file calls three macros, and optionally set a variable, WRAPPER_SUBMODULE_ORDER. The following example is from the ITKImageFilterBase module:

  itk_wrap_module(ITKImageFilterBase)
  
  set(WRAPPER_SUBMODULE_ORDER
    itkRecursiveSeparableImageFilter
    itkFlatStructuringElement
    itkKernelImageFilter
    itkMovingHistogramImageFilterBase
  )
  itk_auto_load_submodules()
  itk_end_wrap_module()

The itk_wrap_module macro takes the current module name as an argument. In some cases, classes defined in the ⋆.wrap files within a module may depend each other. The WRAPPER_SUBMODULE_ORDER variable is used to declare which submodules should be wrapped first and the order they should be wrapped.

9.5.2 Class wrap files

Wrapping specification for classes is written in the module’s ⋆.wrap CMake script files. These files call wrapping CMake macros, and they specify which classes to wrap, whether smart pointer’s should be wrapped for the the class, and which template instantiations to wrap for a class.

Overall toolkit class template instantiations are parameterized by the CMake build configuration variables shown in Table 9.1. The wrapping configuration refers to these settings with the shorthand values listed in the second column.




CMake variable Wrapping shorthand value




ITK_WRAP_IMAGE_DIMS List of unsigned integers


ITK_WRAP_VECTOR_COMPONENTS List of unsigned integers


ITK_WRAP_double D


ITK_WRAP_float F


ITK_WRAP_complex_double CD


ITK_WRAP_complex_float CF


ITK_WRAP_vector_double VD


ITK_WRAP_vector_float VF


ITK_WRAP_covariate_vector_double CVD


ITK_WRAP_covariate_vector_float CVF


ITK_WRAP_signed_char SC


ITK_WRAP_signed_short SS


ITK_WRAP_signed_long SL


ITK_WRAP_unsigned_char UC


ITK_WRAP_unsigned_short US


ITK_WRAP_unsigned_long UL


ITK_WRAP_rgb_unsigned_char RGBUC


ITK_WRAP_rgb_unsigned_short RGBUS


ITK_WRAP_rgba_unsigned_char RGBAUC


ITK_WRAP_rgba_unsigned_short RGBAUS



Table 9.1: CMake wrapping type configuration variables and their shorthand value in the wrapping configuration.

Class wrap files call sets of wrapping macros for the class to be wrapped. The macros are often called in loops over the wrapping variables to instatiate the desired types. The following example demonstates wrapping the itk::ImportImageFilter class, taken from the ITK/Modules/Core/Common/wrapping/itkImportImageFilter.wrap file.

  itk_wrap_class("itk::ImportImageFilter" POINTER)
  
    foreach(d ${ITK_WRAP_IMAGE_DIMS})
      foreach(t ${WRAP_ITK_SCALAR})
        itk_wrap_template("${ITKM_${t}}${d}" "${ITKT_${t}},${d}")
      endforeach()
    endforeach()
  
  itk_end_wrap_class()
Wrapping Variables

Instantiations for classes are determined by looping over CMake lists that collect sets of shorthand wrapping values, namely,

Templated classes are wrapped as type aliases for particular instantiations. The type aliases are named with a name mangling scheme for the template parameter types. The mangling of common types are stored in CMake variables listed in Table 9.2, Table 9.3, and Table 9.4. Mangling variables start with the prefix ITKM_ and their corresponding C++ type variables start with the prefix ITKT_.





CMake Variable Value






Mangling ITKM_B B



C++ Type ITKT_B bool






Mangling ITKM_UC UC



C++ Type ITKT_UC unsigned char






Mangling ITKM_US US



C++ Type ITKT_US unsigned short






Mangling ITKM_UI UI



C++ Type ITKT_UI unsigned integer






Mangling ITKM_UL UL



C++ Type ITKT_UL unsigned long






Mangling ITKM_SC SC



C++ Type ITKT_SC signed char






Mangling ITKM_SS SS



C++ Type ITKT_SS signed short






Mangling ITKM_SI SI



C++ Type ITKT_SI signed integer






Mangling ITKM_UL UL



C++ Type ITKT_UL signed long






Mangling ITKM_F F



C++ Type ITKT_F float






Mangling ITKM_D D



C++ Type ITKT_D double




Table 9.2: CMake wrapping mangling variables, their values, and the corresponding CMake C++ type variables and their values for plain old datatypes (PODS).





CMake Variable

Value







Mangling

ITKM_C${type}

C${type}




C++ Type

ITKT_C${type}

std::complex<${type}>







Mangling

ITKM_A${type}

A${type}




C++ Type

ITKT_A${type}

itk::Array<${type}>







Mangling

ITKM_FA${ITKM_${type}}${dim}

FA${ITKM_${type}}${dim}




C++ Type

ITKT_FA${ITKM_${type}}${dim}

itk::FixedArray<${ITKT_${type}}, ${dim}>







Mangling

ITKM_RGB${dim}

RGB${dim}




C++ Type

ITKT_RGB${dim}

itk::RGBPixel<${dim}>







Mangling

ITKM_RGBA${dim}

RGBA${dim}




C++ Type

ITKT_RGBA${dim}

itk::RGBAPixel<${dim}>







Mangling

ITKM_V${ITKM_${type}}${dim}

V${ITKM_${type}}${dim}




C++ Type

ITKT_V${ITKM_${type}}${dim}

itk::Vector<${ITKT_${type}}, ${dim}>







Mangling

ITKM_CV${ITKM_${type}}${dim}

CV${ITKM_${type}}${dim}




C++ Type

ITKT_CV${ITKM_${type}}${dim}

itk::CovariantVector<${ITKT_${type}}, ${dim}>







Mangling

ITKM_VLV${ITKM_${type}}${dim}

VLV${ITKM_${type}}${dim}




C++ Type

ITKT_VLV${ITKM_${type}}${dim}

itk::VariableLengthVector<${ITKT_${type}}, ${dim}>







Mangling

ITKM_SSRT${ITKM_${type}}${dim}

SSRT${ITKM_${type}}${dim}




C++ Type

ITKT_SSRT${ITKM_${type}}${dim}

itk::SymmetricSecondRankTensor<${ITKT_${type}}, ${dim}>





Table 9.3: CMake wrapping mangling variables, their values, and the corresponding CMake C++ type variables and their values for other ITK pixel types.





CMake Variable

Value







Mangling

ITKM_O${dim}

O${dim}




C++ Type

ITKT_O${dim}

itk::Offset<${dim}>







Mangling

ITKM_CI${ITKM_${type}}${dim}

CI${ITKM_${type}}${dim}




C++ Type

ITKT_CI${ITKM_${type}}${dim}

itk::ContinuousIndex<${ITKT_${type}}, ${dim}>







Mangling

ITKM_P${ITKM_${type}}${dim}

P${ITKM_${type}}${dim}




C++ Type

ITKT_P${ITKM_${type}}${dim}

itk::Point<${ITKT_${type}}, ${dim}>







Mangling

ITKM_I${ITKM_${type}}${dim}

I${ITKM_${type}}${dim}




C++ Type

ITKT_I${ITKM_${type}}${dim}

itk::Image<${ITKT_${type}}, ${dim}>







Mangling

ITKM_VI${ITKM_${type}}${dim}

VI${ITKM_${type}}${dim}




C++ Type

ITKT_VI${ITKM_${type}}${dim}

itk::VectorImage<${ITKT_${type}}, ${dim}>







Mangling

ITKM_SO${dim}

SO${dim}




C++ Type

ITKT_SO${dim}

itk::SpatialObject<${dim}>







Mangling

ITKM_SE${dim}

SE${dim}




C++ Type

ITKT_SE${dim}

itk::FlatStructuringElement<${dim}>







Mangling

ITKM_H${ITKM_${type}}

H${ITKM_${type}}




C++ Type

ITKT_H${ITKM_${type}}

itk::Statistics::Histogram<${ITKT${type}}>







Mangling

ITKM_ST

Depends on platform




C++ Type

ITKT_ST

itk::SizeValueType







Mangling

ITKM_IT

Depends on platform




C++ Type

ITKM_IT

itk::IdentifierType







Mangling

ITKM_OT

Depends on platform




C++ Type

ITKT_OT

itk::OffsetValueType





Table 9.4: CMake wrapping mangling variables, their values, and the corresponding CMake C++ type variables and their values for basic ITK types.

Wrapping Macros

There are a number of a wrapping macros called in the wrapping/⋆.wrap files. Macros are specialized for classes that use itk::SmartPointers and templated classes.

For non-templated classes, the itk_wrap_simple_class is used. This macro takes fully qualified name of the class as an argument. Lastly, the macro takes an optional argument that can have the values POINTER, POINTER_WITH_CONST_POINTER, or POINTER_WITH_SUPERCLASS. If this argument is passed, then the type alias classname::Pointer, classname::Pointer and classname::ConstPointer, or classname::Pointer and classname::Superclass::Pointer are wrapped. Thus, the wrapping configuration for itk::Object is

  itk_wrap_simple_class("itk::Object" POINTER)

When wrapping templated classes, three or more macro calls are required. First, itk_wrap_class is called. Again, its arguments are the fully qualified followed by an option argument that can have the value POINTER, POINTER_WITH_CONST_POINTER, POINTER_WITH_SUPERCLASS, POINTER_WITH_2_SUPERCLASSES, EXPLICIT_SPECIALIZATION, POINTER_WITH_EXPLICIT_SPECIALIZATION, ENUM, or AUTOPOINTER. Next, a series of calls are made to macros that declare which templates to instantiate. Finally, the itk_end_wrap_class macro is called, which has no arguments.

The most general template wrapping macro is itk_wrap_template. Two arguments are required. The first argument is a mangled suffix to be added to the class name, which uniquely identifies the instantiation. This argument is usually specified at least partially with ITKM_ mangling variables. The second argument is the is template instantiation in C++ form. This argument is usually specified at least partially with ITKT_ C++ type variables. For example, wrapping for itk::ImageSpatialObject, which templated a dimension and pixel type, is configured as

  itk_wrap_class("itk::ImageSpatialObject" POINTER)
    # unsigned char required for the ImageMaskSpatialObject
    UNIQUE(types "UC;${WRAP_ITK_SCALAR}")
  
    foreach(d ${ITK_WRAP_IMAGE_DIMS})
      foreach(t ${types})
        itk_wrap_template("${d}${ITKM_${t}}" "${d},${ITKT_${t}}")
      endforeach()
    endforeach()
  itk_end_wrap_class()

In addition to itk_wrap_template, there are template wrapping macros specialized for wrapping image filters. The highest level macro is itk_wrap_image_filter, which is used for wrapping image filters that need one or more image parameters of the same type. This macro has two required arguments. The first argument is a semicolon delimited CMake list of pixel types. The second argument is the number of image template arguments for the filter. An optional third argument is a dimensionality condition to restrict the dimensions that the filter can be instantiated. The dimensionality condition can be a number indicating the dimension allowed, a semicolon delimited CMake list of dimensions, or a string of the form n+, where n is a number, to indicate that instantiations are allowed for dimension n and above. The wrapping specification for itk::ThresholdMaximumConnectedComponentsImageFilter is

  itk_wrap_class("itk::ThresholdMaximumConnectedComponentsImageFilter" POINTER)
    itk_wrap_image_filter("${WRAP_ITK_INT}" 1 2+)
  itk_end_wrap_class()

If it is desirable or required to instantiate an image filter with different image types, the itk_wrap_image_filter_combinations macro is applicable. This macro takes a variable number of parameters, where each parameter is a list of the possible image pixel types for the corresponding filter template parameters. A condition to restrict dimensionality may again be optionally passed as the last argument. For example, wrapping for itk::VectorMagnitudeImageFilter is specified with

  itk_wrap_class("itk::VectorMagnitudeImageFilter" POINTER_WITH_SUPERCLASS)
    itk_wrap_image_filter_combinations("${WRAP_ITK_COV_VECTOR_REAL}" "${WRAP_ITK_SCALAR}")
  itk_end_wrap_class()

The final template wrapping macro is itk_wrap_image_filter_types. This macro takes a variable number of arguments that should correspond to the image pixel types in the filter’s template parameter list. Again, an optional dimensionality condition can be specified as the last argument. For example, wrapping for itk::RGBToLuminanceImageFilter is specified with

  itk_wrap_class("itk::RGBToLuminanceImageFilter" POINTER_WITH_SUPERCLASS)
    if(ITK_WRAP_rgb_unsigned_char AND ITK_WRAP_unsigned_char)
      itk_wrap_image_filter_types(RGBUC UC)
    endif(ITK_WRAP_rgb_unsigned_char AND ITK_WRAP_unsigned_char)
  
    if(ITK_WRAP_rgb_unsigned_short AND ITK_WRAP_unsigned_short)
      itk_wrap_image_filter_types(RGBUS US)
    endif(ITK_WRAP_rgb_unsigned_short AND ITK_WRAP_unsigned_short)
  
    if(ITK_WRAP_rgba_unsigned_char AND ITK_WRAP_unsigned_char)
      itk_wrap_image_filter_types(RGBAUC UC)
    endif(ITK_WRAP_rgba_unsigned_char AND ITK_WRAP_unsigned_char)
  
    if(ITK_WRAP_rgba_unsigned_short AND ITK_WRAP_unsigned_short)
      itk_wrap_image_filter_types(RGBAUS US)
    endif(ITK_WRAP_rgba_unsigned_short AND ITK_WRAP_unsigned_short)
  itk_end_wrap_class()

In some cases, it necessary to specify the headers required to build wrapping sources for a class. To specify additional headers to included in the generated wrapping C++ source, use the itk_wrap_include macro. This macro takes the name of the header to include, and it can be called multiple times.

By default, the class wrapping macros include a header whose filename corresponds to the name of the class to be wrapped according to ITK naming conventions. To override the default behavior, set the CMake variable WRAPPER_AUTO_INCLUDE_HEADERS to OFF before calling itk_wrap_class. For example,

  set(WRAPPER_AUTO_INCLUDE_HEADERS OFF)
  itk_wrap_include("itkTransformFileReader.h")
  itk_wrap_class("itk::TransformFileReaderTemplate" POINTER)
    foreach(t ${WRAP_ITK_REAL})
      itk_wrap_template("${ITKM_${t}}" "${ITKT_${t}}")
    endforeach()
  itk_end_wrap_class()

There are a number of convenience CMake macros available to manipulate lists of template parameters. These macros take the variable name to populate with their output as the first argument followed by input arguments. The itk_wrap_filter_dims macro will process the dimensionality condition previously described for the filter template wrapping macros. DECREMENT, INCREMENT are macros that operate on dimensions. The INTERSECTION macro finds the intersection of two list arguments. Finally, the UNIQUE macro removes duplicates from the given list.

9.6 Third-Party Dependencies

When an ITK module depends on another ITK module, it simply lists its dependencies as described in Section 9.1. A module can also depend on non-ITK third-party libraries. This third-party library can be encapsulated in an ITK module – see examples in the ITK/Modules/ThirdParty directory. Or, the dependency can be built or installed on the system and found with CMake. This section describes how to add the CMake configuration to a module for it to find and use a third-party library dependency.

9.6.1 itk-module-init.cmake

The itk-module-init.cmake file, if present, is found in the top level directory of the module next to the itk-module.cmake file. This file informs CMake of the build configuration and location of the third-party dependency. To inform CMake about the OpenCV library, use the find_package command,

  find_package(OpenCV REQUIRED)

9.6.2 CMakeList.txt

A few additions are required to the top level CMakeLists.txt of the module.

First, the itk-module-init.cmake file should be explicitly included when building the module externally against an existing ITK build tree.

  if(NOT ITK_SOURCE_DIR)
    include(itk-module-init.cmake)
  endif()
  project(ITKVideoBridgeOpenCV)

Optionally, the dependency libraries are added to the <module-name>_LIBRARIES variable. Alternatively, if the module creates a library, publically link to the dependency libraries. Our ITKVideoBridgeOpenCV module example creates its own library, named ITKVideoBridgeOpenCV, and publically links to the OpenCV libraries.

CMakeLists.txt:

  set(ITKVideoBridgeOpenCV_LIBRARIES ITKVideoBridgeOpenCV)

src/CMakeLists.txt:

  target_link_libraries(ITKVideoBridgeOpenCV LINK_PUBLIC ${OpenCV_LIBS})

Next, CMake export code is created. This code is loaded by CMake when another project uses this module. The export code stores where the dependency was located when the module was built, and how CMake should find it. Two versions are required for the build tree and for the install tree.

  # When this module is loaded by an app, load OpenCV too.
  set(ITKVideoBridgeOpenCV_EXPORT_CODE_INSTALL "
  set(OpenCV_DIR \"${OpenCV_DIR}\")
  find_package(OpenCV REQUIRED)
  ")
  set(ITKVideoBridgeOpenCV_EXPORT_CODE_BUILD "
  if(NOT ITK_BINARY_DIR)
    set(OpenCV_DIR \"${OpenCV_DIR}\")
    find_package(OpenCV REQUIRED)
  endif()
  ")

Finally, set the <module-name>_SYSTEM_INCLUDE_DIRS and <module-name>_SYSTEM_LIBRARY_DIRS, if required, to append compilation header directories and library linking directories for this module.

  set(ITKVideoBridgeOpenCV_SYSTEM_INCLUDE_DIRS ${OpenCV_INCLUDE_DIRS})
  set(ITKVideoBridgeOpenCV_SYSTEM_LIBRARY_DIRS ${OpenCV_LIB_DIR})

9.7 Contributing with a Remote Module

For most ITK community members, the modularization of the toolkit is relatively transparent. The default configuration includes all the (default) modules into the ITK library, which is used to build their own ITK applications.

For ITK developers and code contributors, the modular structure imposes rules for organizing the source code, building the library and contributing to the ITK source code repository.

A Module may be developed outside the main ITK repository, but it may be made available in the ITK repository as a Remote Module. The Remote Module infrastructure enables fast dissemination of research code through ITK without increasing the size of the main repository. The Insight Journal (http://www.insight-_journal.org/) adds support for ITK module submissions with automatic dashboard testing (see Section ?? on page ?? for further details).

The source code of a Remote Module can be downloaded by CMake (with a CMake variable switch) at ITK CMake configuration time, making it a convenient way to distribute modular source code.

9.7.1 Policy for Adding and Removing Remote Modules

A module can be added to the list of remotes if it satisfies the following criteria:

At the beginning of the release candidate phase of a release, maintainers of failing module dashboard builds will be contacted. If a module’s dashboard submission is still failing at the last release candidate tagging, it will be removed before the final release.

Module names must be unique.

At no time in the future should a module in the main repository depend on a Remote Module.

9.7.2 Procedure for Adding a Remote Module

The repository

https://github.com/InsightSoftwareConsortium/ITKModuleTemplate

provides a useful template to be used as a starting point for a new ITK module.

The procedure to publish a new module in ITK is summarized as follows:

  1. Publish an open access article describing the module in an online, open access journal like The Insight Journal.
  2. Push a topic to the ITK GitHub repository (see Section ?? on page ?? that adds a file named Modules/Remote/<module name>.remote.cmake. This file must have the following:
    1. Dashboard maintainer name and email in the comments.
    2. A call to the itk_fetch_module CMake function (documented in CMake/ITKModuleRemote.cmake) whose arguments are:
      1. The name of the remote module. Note that in each <remote module name>.remote.cmake, the first argument of the function itk_fetch_module() is the name of the remote module, and it has to be consistent with the module name defined in the corresponding <remote module name>.remote.cmake. To better distinguish the remote modules from the internal ITK modules, the names of the remote modules should NOT contain the “ITK” string prefix.
      2. A short description of the module with the handle to the open access article.
      3. URLs describing the location and version of the code to download. The version should be a specific hash.

After the Remote Module has experienced sufficient testing, and community members express broad interest in the contribution, the submitter can then move the contribution into the ITK repository via GitHub code review.

It is possible but not recommended to directly push a module to GitHub for review without submitting to Insight Journal first.