Chapter 14. Developing ML Modules

Table of Contents

14.1. Creating a New ML Module for Adding Values
14.1.1. Creating the Basic ML Module with the Project Wizard
14.1.2. Preparing the Project
14.1.3. Programming the Functions of the ML Module
14.1.4. GUI Creation/Optimizing
14.1.5. Creating an Example Network and Help File
14.2. Creating an ML Module For Simple Average
14.2.1. Creating the Basic ML Module with the Project Wizard
14.2.2. Editing the Header File of SimpleAverage
14.2.3. Editing the CPP File of SimpleAverage
14.2.4. Testing the Module
14.3. Combining Two Modules in One Project
14.3.1. Copying the Source Files
14.3.2. Editing and Recompiling the CMakeLists.txt File
14.3.3. Editing the Project in the Development Environment
14.3.4. Editing the Module Definition (.def)
14.3.5. Cleaning up Folders and Example Networks

In the following chapter, the development of ML modules will be shown in three examples.

  1. An ML module that allows adding a user-defined constant value to image voxels, see Section 14.1, “Creating a New ML Module for Adding Values”.

  2. A more complex ML module that calculates a simple average over voxel values of an entire image, see Section 14.2, “Creating an ML Module For Simple Average”.

  3. Combining the two ML modules in one project (which results in one DLL), with a discussion of the pros and cons of such combinations, see Section 14.3, “Combining Two Modules in One Project”.

The following examples are developed very explicitly to give you some insight into the ML, the MeVis image processing library. Another useful way to start with module development is to copy the source code of an existing module that might already have some of the wanted functionality and adapt it to your needs. For further information, please refer to the ML Guide.

[Note]Note

Developing C++ modules requires a C++ development environment being available on your computer, for example Visual C++ on Windows or Xcode on Mac OS X.

[Note]Note

It is recommended to open and compile the debug versions for development.

14.1. Creating a New ML Module for Adding Values

In the following chapter, we will create a new ML module with the functionality of adding a value to all voxels, in the following steps:

[Tip]Tip

This example is delivered with MeVisLab (.def file in $(InstallDir)Packages/MeVisLab/Examples/Modules/GettingStarted/MLSimpleAddExample, source files in $(InstallDir)Packages/Examples/Sources/GettingStarted/MLSimpleAddExample). The module can be added via quick search.

14.1.1. Creating the Basic ML Module with the Project Wizard

  1. First of all, make sure that you have a user package defined as described in Section 8.2, “Creating a User Package for Your Project” or create it now.

  2. Then run the Project Wizard and select the link ML Module. This starts the Wizard for C++/ML Modules. Enter the following:

    • Name: SimpleAdd

    • Comment: Adds a constant double value to each voxel.

    • See Also: Arithmetic1

    • Target Package: Example/General

    • Project: SimpleAdd

    Click Next to proceed.

    Figure 14.1. Entering the ML Module Properties

    Entering the ML Module Properties

  3. On the dialog Imaging Module Properties, the inputs and outputs as well as possible sample code can be added to the ML module.

    Figure 14.2. Entering the Imaging Module Properties

    Entering the Imaging Module Properties

    Select the Module Type Classic ML Module. For information on the differences, see the MeVisLab Reference Manual, chapter ML Wizard.

    Enter the following settings:

    • Inputs: 1

    • Outputs: 1

    • Check Add calculateOutputSubImage() template.

    • Check Add voxel loop to calculateOutputSubImage().

  4. On the dialog Additional Module Properties, the inputs and outputs as well as possible sample code can be added to the ML module.

    Figure 14.3. Additional Module Properties

    Additional Module Properties

    Make the following settings:

    • Check Auto-update output images on field changes (adds handleNotification).

    • Check Add activateAttachments().

    • Check Add ML window with fields.

  5. On the dialog Module Field Interface, the fields of the module can be defined (more fields can be added later but this is the easiest way to add fields).

    Figure 14.4. Entering the ML Module Properties — Fields

    Entering the ML Module Properties — Fields

    Click New to create a new field, then enter the following:

    • Field Name: constantValue

    • Field Type: Double

    • Field Comment: This constant value is added to each voxel.

    • Field Value: 0.

  6. Click Create to create the module.

    In the default file browser of your system, two folders are opened:

    • folder with the source code: {packagePath}/Sources/ML/MLSimpleAdd

    • folder with the module's GUI definition: {packagePath}/Modules/ML/MLSimpleAdd

    [Note]Note

    For a full list of all created files and their contents, refer to the MeVisLab Reference Manual, chapter ML Module — Created Files.

The foundation of the module has been created with the Wizard. From here on, the programming starts.

[Tip]Tip

The Wizard will not close automatically. This way, you can change settings or fields and create the module once more.

After module creation, the module database needs to be reloaded.

14.1.2. Preparing the Project

The Project Wizard creates a CMakeLists.txt file that describes the typical projects settings and used source files. This file can be translated manually with the CMake tool into a project file for your preferred C++ development tool. But most Integrated Development Environments (IDEs) nowadays can open CMake files directly.

Just make sure that the MLAB_ROOT environment variable is set on your system and points to the Packages directory of your MeVisLab installation, because this is used to resolve the reference to the 'MeVisLab' project.

For further documentation about our use of CMake see: CMake for MeVisLab - Documentation.

14.1.3. Programming the Functions of the ML Module

Open the file mlSimpleAdd.cpp.

[Note]Note

In the following code examples, the comment lines already available in the created .cpp file are added for better overview.

14.1.3.1. Implementing calculateOutputImageProperties

As we add a constant value to each voxel, we need to adjust the value range of the output image, which results in:

  outMin = inMin + constValue
  outMax = inMax + constValue

In code, this is:

//--------------------------------------------------------------------------------
//! Sets properties of the output image at output outIndex.
//--------------------------------------------------------------------------------
void SimpleAdd::calculateOutputImageProperties (int outIndex, PagedImage* outImage)
{

  // get the constant add value
  const MLdouble constantValue = _constantValueFld->getDoubleValue();

  // get input image's min and max values
  const MLdouble inMinValue = getInputImage(0)->getMinVoxelValue();
  const MLdouble inMaxValue = getInputImage(0)->getMaxVoxelValue();

  // set the output image's min and max values
  outputImage->setMinVoxelValue(inMinValue + constantValue);
  outputImage->setMaxVoxelValue(inMaxValue + constantValue);  
}
[Note]Note

outIndex is the index number of the output connector.

14.1.3.2. Implementing calculateOutputSubImage

  1. Loop over all voxels of the output page and add the constant value. The loop is already generated by the wizard, so only the following line has to be added at the start of the method, to obtain the constant value in the correct data type:

      // Compute subimage of output image outIndex from input subimages.
      const T constantValue = static_cast<T>(_constantValueFld->getDoubleValue());

    That is the datatype of the output image which is the data type of the input image.

  2. Then change the inner line of the following loop from *outVoxel = *inVoxel0; to *outVoxel = *inVoxel0 + constantValue; so that the constant value is added to the value of the input voxel:

        // Process all row voxels.
        for (; p.x <= rowEnd;  ++p.x, ++outVoxel, ++inVoxel0)
        {
          *outVoxel = *inVoxel0 + constantValue;
        }
  3. Compile the project (this includes all module files) in the development environment.

  4. (Re)start MeVisLab.

    [Note]Note

    If the module was edited in the debug version, MeVisLab must be run in the debug mode.

    The restart is necessary

    • so that the ModuleName.def file can be found and parsed by MeVisLab.

    • so that the module DLL is copied to the correct location, from a temporary source folder to the lib folder. (If a .def file exists but no DLL is found, the module is displayed in red in MeVisLab.)

    The module is now available in the (quick) search. Add it to the network.

14.1.4. GUI Creation/Optimizing

  1. For optimizing the GUI of the module — that is the panel — open the .def file. You can do that in two ways:

    • Open the .def file in your development environment. The downside is that the development environment does not support the MDL language of the .def file.

    • Open the .def file in the inbuilt text editor MATE, by right-clicking the module in MeVisLab and selecting Related FilesMLSimpleAdd.def from the context menu. The advantage is that MATE supports MDL (and Python). Therefore, it is recommended to edit MDL files primarily with MATE. (More information on MATE can be found in the MeVisLab Reference Manual, chapter MATE.)

  2. Add the line step = 100 to the definition of the field constantValue in order to adjust the constant value conveniently. (Smaller steps are barely visible in the output.)

    Window {
      Vertical {
        margin = 3
        Field constantValue {
          tooltip = "This constant value is added to each voxel."
          step    = 100   // big change for big effect          
        }
      }
    }
  3. Reload the module definition by right-clicking the module and selecting Reload Definition from the context menu. This will only reload the GUI definition, not the module DLL.

  4. To check if everything worked, double-click the module to open the panel and test

    Congratulations, you have now implemented your first page-based and demand-driven ML image processing module!

    As last step, we will create a little example network.

14.1.5. Creating an Example Network and Help File

  1. Load the example network of the module via FileOpen. Its name is automatically constructed as <ModuleName>Example.mlab. So far, the example network only includes the module itself.

  2. Add two modules to the network, namely LocalImage and View2D. Connect the image input to the bottom connector and the image output to the top connector of SimpleAdd.

  3. Double-click SimpleAdd to open its panel and View2D to open the viewer. When you now change the steps, the image display changes.

    Figure 14.5. Example Network for SimpleAdd

    Example Network for SimpleAdd

  4. To create the help, right-click the new module and select Edit Help from the context menu. This opens the integrated text editor MATE in a mode to edit a module's help file. See Section 26.9, “Module Help Editor” for more information.

    Now the module is ready for usage.

The module including the example network and help file are delivered with the examples of MeVisLab, so feel free to check it out and play around with it.