-
Notifications
You must be signed in to change notification settings - Fork 6
Added C++ Tutorial #139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Added C++ Tutorial #139
Changes from 2 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
181 changes: 181 additions & 0 deletions
181
mevislab.github.io/content/tutorials/image_processing/cpp_1.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,181 @@ | ||
| --- | ||
| title: "Example 1: Creating a New ML Module for Adding Values" | ||
| date: 2026-03-15T08:56:33+02:00 | ||
| status: "OK" | ||
| draft: false | ||
| weight: 602 | ||
| tags: ["Advanced", "Tutorial", "Image Processing", "C++"] | ||
| menu: | ||
| main: | ||
| identifier: "cpp1" | ||
| title: "Example 1: Creating a New ML Module for Adding Values" | ||
| weight: 602 | ||
| parent: "cpp" | ||
| --- | ||
|
|
||
| # Example 1: Creating a New ML Module for Adding Values | ||
|
|
||
| ## Precondition | ||
| Make sure to have [cmake](https://cmake.org/download) installed. This example has been created using CMake Legacy Release (3.31.11). | ||
|
|
||
| ## Introduction | ||
| In this example, we develop our own C++ ML module which adds a constant value to each voxel of the given input image. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Steps to Do | ||
| ### Create a new ML Module | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| Before creating the module, make sure to have your own user package available. See [Package creation](tutorials/basicmechanisms/macromodules/package/) for details about Packages. | ||
|
|
||
| Use the *Project Wizard* via menu entry {{< menuitem "File" "Run Project Wizard ..." >}} to create a new ML module. Select *ML Module* and click *Run Wizard*. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
|  | ||
|
|
||
| Enter properties of your new module and give your module the name `SimpleAdd`. Make sure to select your user package and name your project *SimpleAdd*. | ||
|
|
||
|  | ||
|
|
||
| Click *Next*. The next screen of the wizard allows you to define the inputs and outputs of your module. Select *Module Type* as *New style ML Module*, make sure to have one in- and one output and leave the rest of the settings unchanged. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
|  | ||
|
|
||
| Click *Next*. On the next screen, we can define some additional properties of our module. Select *Add activateAttachments()*, unselect *Acc configuration hints* and select *Add MDL window with fields*. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
|  | ||
|
|
||
| Click *Next*. The Module Field Interface allows you to define additional fields for the module. More fields can be added later but this is the easiest way to add 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. | ||
|
|
||
|  | ||
|
|
||
| Click *Create*. You see a screen showing the results of the module creation process. In case the Wizard finished succesfully, you can close the window. Additionally an explorer window opens showing the created folder containing your sources and the *CMakeLists.txt*. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| The foundation of the module has been created with the Wizard. From here on, the programming starts. | ||
|
|
||
| After module creation, the module database needs to be reloaded. | ||
|
|
||
| ### 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. | ||
|
|
||
| Open a commandline and change to your current module directory (the directory containing your *CMakeLists.txt* file). Enter **cmake . -G "Visual Studio 17"**. After execution, a lot of files are generated by CMake. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| For further documentation about our use of CMake see: [CMake for MeVisLab - Documentation](https://mevislabdownloads.mevis.de/docs/current/MeVisLab/Resources/Documentation/Publish/SDK/CMakeManual/#mainBook). | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### Programming the Functions of the ML Module | ||
| Open the file *ALL_BUILD.vcxproj* in your preferred C++ development environment. Select the file *mlSimpleAdd.cpp*. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| {{<alert class="info" caption="Note">}} | ||
| In the following code examples, the comment lines already available in the created .cpp file are added for better overview. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| {{</alert>}} | ||
|
|
||
| #### 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: | ||
|
|
||
| {{< highlight filename="" >}} | ||
| ```c++ | ||
| outMin = inMin + constValue | ||
| outMax = inMax + constValue | ||
| ``` | ||
| {{</highlight>}} | ||
|
|
||
| Change the file *mlSimpleAdd.cpp* as shown below. | ||
|
|
||
| {{< highlight filename="mlSimpleAdd.cpp" >}} | ||
| ```c++ | ||
| void SimpleAdd::calculateOutputImageProperties(int /*outputIndex*/, PagedImage* outputImage) | ||
| { | ||
| // Set up data types and read-only flags of output image and input subimages. | ||
| SimpleAddOutputImageHandler::setupKnownProperties(outputImage); | ||
|
|
||
| // Change properties of output image outputImage here whose | ||
| // defaults are inherited from the input image 0 (if there is one). | ||
| // get the constant add value | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| const MLdouble constantValue = _constantValueFld->getDoubleValue(); | ||
|
|
||
| // get input image's min and max values | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| 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); | ||
|
sahehb marked this conversation as resolved.
|
||
| outputImage->setMaxVoxelValue(inMaxValue + constantValue); | ||
|
|
||
| // Verify whether the input/output data types are supported by our handler. | ||
| // This will invalidate the output image if the type combination is not supported by the handler. | ||
| SimpleAddOutputImageHandler::verifyProperties(outputImage); | ||
| } | ||
| ``` | ||
| {{</highlight>}} | ||
|
|
||
| {{<alert class="info" caption="Note">}} | ||
| *outputIndex* is the index number of the output connector. It is commented out in this example, because we only defined one output. In case of more than one outputs, uncomment this parameter. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| {{</alert>}} | ||
|
|
||
| #### Implementing *typedCalculateOutputSubImage* | ||
| Next, we are going to finally change the voxel values of the image. Open the file *mlSimpleAddOutputImageHandler.cpp*. A loop over all voxels of the output page is generated automatically and we want to add the constant value to each voxel. Add the following line at the start of the method to obtain the current constant value in the correct data type: | ||
|
|
||
| {{< highlight filename="mlSimpleAddOutputImageHandler.cpp" >}} | ||
| ```c++ | ||
| // Compute subimage of output image outIndex from input subimages. | ||
| const OUTTYPE constantValue = static_cast<OUTTYPE>(_parameters.constantValue); | ||
| ``` | ||
| {{</highlight>}} | ||
|
|
||
| Then change the inner line of the loop, so that the constant value is added to the value of the input voxel: | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| {{< highlight filename="mlSimpleAddOutputImageHandler.cpp" >}} | ||
| ```c++ | ||
| // Process all row voxels. | ||
| for (; p.x <= rowEnd; ++p.x, ++outVoxel, ++inVoxel0) | ||
| { | ||
| *outVoxel = *inVoxel0 + constantValue; | ||
| } | ||
| ``` | ||
| {{</highlight>}} | ||
|
|
||
| Compile the project (this includes all module files) in the development environment. Make sure to select a *Release* build. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### Use your module in MeVisLab | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| Your compiled *.dll is available in your project directory under *Sources/lib*. In order to use it in MeVisLab, it needs to be copied to the *lib* folder of your user package. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| You can either do this manually or via PostBuild step. | ||
|
|
||
| In case MeVisLab was running during development, restart MeVisLab and use your new module. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| For testing purposes, you can use a `LocalImage` module and two `View2D` modules. Connect the `SimpleAdd` module to the second `View2D` and change the <field>Constant Value</field> field. | ||
|
|
||
|  | ||
|
|
||
| The output image of the module `SimpleAdd` is automatically re-calculated on changing the field <field>Constant Value</field>. This is already implemented in the generated code of the file below: | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| {{< highlight filename="mlSimpleAdd.cpp" >}} | ||
| ```c++ | ||
| void SimpleAdd::handleNotification(Field* field) | ||
| { | ||
| // Handle changes of module parameters and input image fields here. | ||
| bool touchOutputs = false; | ||
| if (isInputImageField(field)) | ||
| { | ||
| touchOutputs = true; | ||
| } | ||
| else if (field == _constantValueFld) | ||
| { | ||
| touchOutputs = true; | ||
| } | ||
|
|
||
| if (touchOutputs) | ||
| { | ||
| // Touch all output image fields to notify connected modules. | ||
| touchOutputImageFields(); | ||
| } | ||
| } | ||
| ``` | ||
| {{</highlight>}} | ||
|
|
||
| ## Summary | ||
| * MeVisLab allows to develop your own C++ modules. | ||
| * The Project Wizard already generates all necessary *.cpp and *.h files and a loop through all voxels of the input image. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| * Changes of user defined fields automatically lead to a recalculation of the input image. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
68 changes: 68 additions & 0 deletions
68
mevislab.github.io/content/tutorials/image_processing/cpp_development.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| --- | ||
| title: "Developing your own C++ Modules" | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| date: 2026-03-15T08:56:33+02:00 | ||
| status: "OK" | ||
| draft: false | ||
| weight: 601 | ||
| tags: ["Advanced", "Tutorial", "Image Processing", "C++"] | ||
| menu: | ||
| main: | ||
| identifier: "cpp" | ||
| title: "Developing your own C++ Modules" | ||
| weight: 601 | ||
| parent: "imageprocessing" | ||
| --- | ||
|
|
||
| # C++ Module development | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| ## Introduction | ||
| The development of your own C++ modules can be done by ML modules and by Inventor modules. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| {{<alert class="info" caption="Important Information">}} | ||
| Make sure to use a compiler that is compatible to your currently installed MeVisLab version. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| {{</alert>}} | ||
|
|
||
| ### ML modules on the C++ level | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| * Image processing modules are objects derived from class Module defined in the ML library and therefore are also called ML modules. | ||
| * Image inputs and outputs are connectors to objects of class PagedImage, which are defined in the ML library. | ||
| * Inputs and outputs for abstract data structures are connectors to pointers of objects derived from class Base and are called Base objects. | ||
|
|
||
| ### Inventor modules on the C++-level: | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| * Most Inventor modules are objects derived from class SoNode defined in the Open Inventor library. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| * Inventor inputs and outputs are connectors to objects derived from class SoNode defined in the Open Inventor library. Many Inventor modules will return themselves as outputs (“self”). On inputs, they may have connectors to child Inventor modules. | ||
| * Some Inventor modules are objects derived from class SoEngine. They are used for calculations and return their output not via output connectors but via fields. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| * Inventor modules may also have input and output connectors to Base objects and Image objects. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| * All standard Inventor nodes defined in the Open Inventor library are available in MeVisLab as Inventor modules. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| This chapter describes some examples for developing your own ML and Inventor modules. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Some Tips for Module Design | ||
| ### Macro Modules or C++ Modules? | ||
| In [Example 2: Macro Modules](tutorials/basicmechanisms/macromodules/), we already described Macro Modules and how to create them yourself. | ||
|
|
||
| **Advantages of macros:** | ||
| * Macros are useful for creating a layer of abstraction by hierarchical grouping of existing modules. | ||
| * Scripts can be edited on the fly: | ||
| * no compilation and reload of the module database necessary | ||
| * scripting possible on the module or network level | ||
| * scripting supported by the Scripting Assistant View (basically a recorder for actions performed on the network) | ||
|
|
||
| **Disadvantages:** | ||
| * With macros, only existing functionalities and algorithms can be used. | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| **Conclusion:** | ||
| * For rapid prototyping based on existing image processing algorithms, use macros. | ||
| * For implementing new image processing, write new ML or Open Inventor modules. | ||
|
|
||
| ### Combining Functionalities | ||
| It is possible to have ML and Open Inventor connectors in the same module. Two cases are possible: | ||
| * Type 1: **ML -> visualization:** Image data or properties are displayed by a visualization module. Usually a <field>SoSFXVImage</field> field gets random access to an ML image by *getTile()*. Examples: `SoView2D`, `GlobalStatistics`. | ||
| * Type 2: **visualization -> ML:** Modules generate an ML image from an Inventor scene. Examples: `VoxelizeInventorScene`, `SoExaminerViewer` (hidden functionality). | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
|
|
||
| Generally, however, it is not always a good solution to combine that, as the processes of image processing and image visualization are usually separated. | ||
|
|
||
| Therefore, rather separate the ML and Open Inventor functionalities into two modules. This way, | ||
| * functionality is encapsulated and can be reused as module | ||
| * modules for the single steps may already be available in MeVisLab and spare you a new development | ||
|
|
||
| ## Code examples | ||
|
sahehb marked this conversation as resolved.
Outdated
|
||
| In addition to the tutorials in this chapter, you can find additional code examples in your MeVisLab installation directory. | ||
Binary file added
BIN
+27.7 KB
mevislab.github.io/static/images/tutorials/image_processing/cpp/cpp1_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+40.6 KB
mevislab.github.io/static/images/tutorials/image_processing/cpp/cpp1_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+40.9 KB
mevislab.github.io/static/images/tutorials/image_processing/cpp/cpp1_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.6 KB
mevislab.github.io/static/images/tutorials/image_processing/cpp/cpp1_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+29.8 KB
mevislab.github.io/static/images/tutorials/image_processing/cpp/cpp1_5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+352 KB
mevislab.github.io/static/images/tutorials/image_processing/cpp/cpp1_6.png
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe use a lower value, e.g., -1400, so that the difference can easily be seen. Or use a high positive value? Because the name of the module contains "Add" :) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions
2
mevislab.github.io/themes/MeVisLab/layouts/shortcodes/highlight.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.