The following sections describe classes and toolboxes, and contain a lot of useful information for advanced ML programming.
This project contains some basic classes for simple vector and matrix arithmetics as well as for quaternion support.
This project contains some basic classes, files and interfaces used by the ML which are not directly related to image processing. Some of them are explicitly explained in other chapters of this document.
Defines the class DateTime for
              storing and processing date and time values.
This file contains a number of macros for error handling, checking and tracing that should be used in all ML code. These macros are essential for source code quality control and for many other checks as well as for error tracing and reporting, and for exception handling.
mlErrorOutput and
              mlErrorOutputInfos
The class ErrorOutput  is the main
              error handling and redirecting class of the ML. It uses
              mlErrorOutputInfos as an information
              container for error, debug or trace information that is passed
              to registered error handling routines. See Section 5.4, “The Class ErrorOutput and Configuring Message Outputs” for more information.
Defines a set of C functions for system independent file management (file open, close, etc.). All methods support UTF-8 unicode strings to access files that contain unicode characters in their absolute file names.
See also Chapter 9, Unicode Support for more information on internationalization and management of files that contain international characters in their file names.
This file defines macros that are
              used for platform-independent library initializations with
              correct version checks. Most importantly, the macro ML_INIT_LIBRARY(initMethod)
               is defined in this file. This macro is used to
              initialize shared libraries independently of the underlying
              system (WIN32/Mac OS X/Linux). When the library has been loaded,
              the given init method is called as soon as possible. The name of
              the initMethod should be composed like
              < dllName > +
              'Init'. This is necessary since this macro
              sets the name of the initialized DLL as well. Subsequent runtime
              types will use this name to register the originating DLL.
See also Section 2.2.4, “The Runtime Type System” for macros to initialize module classes and runtime types of the ML.
Basic memory management class for the ML.
Class to notify registered instances of ML changes. With this class, registered classes will be notified of changes to ML internals. It is not intended to be used in normal modules, but can be very useful for diagnostics.
                  mlRuntime.h
                , 
                  mlRuntimeDict.h
                ,
              
                  mlRuntimeSubClass.h
                ,
              
                  mlRuntimeType.h
                
See Section 2.2.4, “The Runtime Type System” for more information on these classes and files.
This file includes many important system files, makes
              correct adaptations for some platforms and disables boring and
              unproductive warnings. It is designed to be independent of the
              ML or MLUtilities and does not need to link to
              any ML or MLUtilities binary. When this file is
              used, the most important program parts are provided
              platform-independently and without any warnings. Include this
              file instead of directly including system files.
Header file that contains the most important ML types,
              constants and definitions; this file can be included without
              having to link the ML, MLUtilities or
              MLLinearAlgebra project (see Section 2.6.1, “MLLinearAlgebra(Vector2, ..., Vector10, Vector16, Matrix2, , ..., Matrix6, quaternion, ImageVector)”) and it also does not use
              any C++ functionality. Thus much ML stuff can be used without
              being really dependent on the ML.
File that contains a set of C functions for converting and managing normal unicode strings.
See also Chapter 9, Unicode Support for more information on internationalization and management of files that contain international characters in their file names.
Public header file for ML version support (Section A.7, “Version Control”). It provides some support for checking for the correct binary versions of the ML and the ML C-API.
Like 
              SubImageBox
            , only
          with 
              Vector6
            
          corners. Manages a rectangular 6D box given by two Vector6. Permits
          intersections etc. See mlSubImgBoxf in
          project ML.
The ML includes some frequently used types.
A detailed explanation of the following helper classes will be given in later editions of this document. Please refer to later versions of this document or to the header files:
A class derived from Module and
              intended to build modules similar to Open Inventor™ engines by the use of ML fields. It does
              not provide any image input or output, i.e., only operations on
              fields can be implemented.
Manages a geometric plane in 3D. Used as an encapsulated
              data type for a PlaneField.
Manages a geometric rotation in 3D. Used as an
              encapsulated data type for a
              RotationField.
Manages a geometric 2D disk of a certain radius that is placed in 3D and that can also be voxelized into any image.
Manages a geometric sphere in 3D.
The MLDataType is an enumerator
            describing all voxel data types currently available in the ML.
            This includes built-in data types like
            MLint8Type,
            MLuint8Type,
            MLint16Type,
            MLuint16Type,
            MLint32Type,
            MLuint32Type,
              MLint64Type,
              MLuint64Type,
              MLfloatType and
            MLdoubleType as well as (pre)registered
            types like Vector2, Vector3,
            Vector4, Vector6,
            Vector8, Vector10,
            Vector16, Vector32,
            complexf,
            
            etc.
Values of this type are often used to request or to determine image data or voxels of a certain type.
Since the number of MLDataTypes can
            change during runtime, it is implemented as an integer, and the
            function MLNumDataTypes() returns the current
            number of available voxel data types.
            MLDataTypeNames() returns a pointer to the
            table of data type names corresponding to the
            MLDataType values.
![]()  | Note | 
|---|---|
  | 
A number of other useful functions is available to query
            information about MLDataTypes: 
const char *MLNameFromDataType(MLDataType dt)
Returns the C string name of data type
                dt if dt is a
                valid type. Otherwise "" is returned.
MLDataType MLDataTypeFromName(const char * const name) 
Returns the MLDataType value of
                the data type with the name name. If
                name is not valid, -1 is
                returned.
double MLDataTypeMax(MLDataType dt)
Returns the maximum value of data type
                dt; if dt is
                invalid, 0 is returned.
double MLDataTypeMin(MLDataType dt)
Returns the minimum value of data type
                dt if dt is
                invalid, 0 is returned.
size_t MLSizeOf(MLDataType dt)
Returns the size of the data type
                dt in bytes. 0 is returned for
                invalid types.
int MLIsValidType(MLDataType dt)
Returns true(=1) if data type dt is valid.
                Otherwise false(=0) is returned.
Returns true(=1) if data type
                dt is signed. Otherwise
                false(=0) is returned.
int MLIsIntType(MLDataType dt)
returns true(=1) if data type
                dt is an integer data type. Otherwise
                false(=0) is returned.
int MLIsFloatType(MLDataType dt)
Returns true(=1) if data type
                dt is a floating point data type.
                Otherwise false(=0) is returned.
int MLIsScalarType(MLDataType dt)
Returns true(=1) if data type
                dt is a scalar (i.e., a built-in)
                type. Otherwise false(=0) is
                returned.
There are some more functions for the definition of features
            and properties related to data types. See the documentation in the
            file 
                mlDataTypes.h
               for more
            information.
            A modern version to get compile-time information on MLDataType is to use the
            TypeTraits template class. See the documentation in the
            file 
                mlTypeTraits.h
               for more information.
            
int MLHolds (MLDataType dt1, MLDataType dt2)
MLDataType MLGetPromotedType (MLDataType d1, MLDataType d2)
MLDataType MLGetDataTypeForRange (double *min, double *max, int preferUnsigned)
MLDataType MLGetDataTypeForUncorrectedRange (double min, double max, int preferUnsigned)
MLDataType MLGetRangeAndPrecisionEquivalent (MLDataType dt)
MLDataType MLGetPromotedPrecision (MLDataType dt1, MLDataType dt2)
This project contains a set of classes that are useful when data
        structures like markers, lists, functions, diagram information, etc.
        are needed that are related to image processing, although they may not
        be an integral part of it. (See also project
        MLBase in the modules library.)
A small template class library with some modules for managing a matrix of kernel elements, and for filtering or correlating/convoluting images. See Kernel Progamming for detailed information.
Class that contains a set of helper functions for different
        tasks. See mlTools.h in project
        MLTools for more information.
The ML project MLDiagnosis contains some
        modules that can prove to be helpful for module debugging and for
        changing the ML configuration at runtime. 
This module is designed to commit a large number of errors and to have many bugs. Hence applications, module networks, MeVisLab, etc. can be checked for stability on bad module behavior.
This module shows the current state and load of the Memory Manager cache.
This module calculates a checksum of an ML image at the input. This is a simple way to see whether two images differ. Saving just the checksum is sufficient for a later comparison of images. This is especially useful to see whether a module calculates the same image as some time before without storing the entire image.
A module that shows all ML outputs in a console window.
Provides an interface to configure the ML error handling system (e.g., how to handle a fatal error, whether the ML continues or terminates), to enable/disable debugging symbols, to configure the ML caching and multithreading, and to obtain the version of the ML.
Provides a simple interface to create messages, errors, and exceptions of user defined types. The exact behavior of the applications, error handlers, networks and the ML can be explicitly tested for any type of error.
In module networks, fields of different modules are often connected and it can become quite difficult to see from where field changes are sent. The field tracer allows for the creation of a field change list in a certain period of time and by that, it allows to analyze changes in the network.
A module that redirects ML output to a log file. The log file's content can be used for further diagnostic purposes (e.g. after crashes).
This module shows the currently instantiated modules and offers a view on the module interfaces, their fields, inputs and outputs, even when working with an ML release version that does not contain debug information.
This module allows for an installation of a dump function in
            the ML core that will be called when a runtime type causes a crash
            that is to be handled by the ML. The current state of the C++
            interface of some runtime types like fields, modules derived from
            Module etc. will be dumped in the error
            output for further diagnostic purposes. This is intended
            especially for error diagnostics in release mode when the debugger
            cannot be used. This module can also remain in released
            applications so that log information on crashes that did not occur
            during application development in debug mode are available.
This module shows all currently registered types in the runtime type system as well as the libraries they come from, their parent classes, whether they are abstract or not, etc.
This powerful module applies a number of tests to one or more modules. It checks for correct field names, memory leaks, stable behavior on many different input images with different (page) extents, data types, min/max values, etc. Parameter and base fields are tested with a large number of combinations of values. More test images are continually added to the module. Testing time, intensity, etc. can be controlled by parameters.
This module generates test images of different types that can be addressed by indices. Thus a large number of different images that cover most image properties like image extent, page extent, min/max values, data type, etc. is available for testing.
The ML project MLImageFormat contains
        file format classes for storing, loading and modifying an ML
        PagedImage or subimages in a file.
It stores all information of an up to 6D ML
        PagedImage, including extended voxel types,
        paging information and property extensions. It supports files of more
        than 4 GB, uses the registered
        MLDataCompressors classes for page-based
        compression, checks for pages containing only one voxel value to avoid
        file accesses and unnecessary compressor calls, and many more
        features. See Section 2.6.9, “
          MLDataCompressors
          
        ” for more
        information on the MLDataCompressors.
The following classes are available as a programming interface
        (see 
            mlImageFormatDoc.h
           and class headers of
        those classes for details):
Class to manage a stored file for saving, loading or retrieving image information. It is mainly used by the module classes.
Collection of independent static file IO classes that are
            mainly used by MLImageFormat.
Module class to cache an image in a file comparable to a
            MemCache module.
Module class to save a PagedImage and
            user tags.
Module class to load a file and some of its information.
Module class to get information about a file.
MLImageFormatTag
Tag class used in
            MLImageFormatTagList to store one pair of
            information items such as a name and an integer or a
            string.
Class to describe the list of tag information stored in a file.
The ML project MLDatCompressors contains
        the base class DataCompressor that allows the
        implementation of new data compression algorithms. It also contains a
        factory class DataCompressorFactory that allows
        for the registration of user-derived classes. By that, any number of
        new compression classes can be implemented which are automatically
        detected by classes using compression algorithms, for example
        MLImageFormat modules (Section 2.6.8, “
          MLImageFormat
          
        ”).
Abstract base class for ML data compression algorithms. New
            data compressors can be derived from this class and then be
            registered in the DataCompressorFactory to
            become available for all other modules and classes that use data
            compression.
Factory class for ML data compression algorithms. It provides access to all registered data compressors, for example for file formats or memory managers using data compression.
See 
            MLDataCompressorDoc.h
           and other header
        files in project MLDataCompressor for
        details.
Follow these steps to implement your own compressor (see
          
              MLDataCompressorDoc.h
             and other header files in
          project MLDataCompressor for details and code
          fragments):
Be sure to implement everything in the namespace ML_UTILS_NAMESPACE.
Derive your compressor from the
              DataCompressor class and override the
              following methods: 
virtual const std::string getTypeName() const = 0;
virtual const std::string getVersion() const = 0;
virtual const bool isSupportedVersion(const std::string &ver) const = 0;
virtual MLErrorCode compress(const void *srcMem, size_t srcSize, void *&dstMem, MLint &dstNum) const = 0;
virtual MLErrorCode decompress(const void *srcMem, size_t srcSize, void *&dstMem, MLint64 &resSize) const = 0;
Register your DataCompressor (for
              example during dll/so registration) with
              YourDataCompressor::initClass() in the
              runtime type system of the ML first and then in the
              DataCompressorFactory.
Be sure that classes that use your data compressor will
              find it registered in the
              DataCompressorFactory before they are instantiated.
In MeVisLab, you can do this by specifying the PreloadDll flag in a .def file for your compressor.
Optionally, you may also want to override the
              numUsedHints() method and initialize the
              following members appropriately to specify parameters for your
              compressor which might be detected and passed by some
              applications to control compression behavior: The parameters
              _hintType,
              _hintName,
              _rangeMin, and
              _rangeMax should be set by your derived
              class, the other parameters should be set to their default
              values.
It is strongly recommended to implement the virtual
              methods getVersion(),
              isSupportedVersions(),
              getVendor(),
              getSuffix(), and
              isLossy() in order to provide additional
              information about classes using the compressor.
Especially isLossy() should be
              implemented to make sure that other classes know that
              decompressed data need not be identical with compressed data.
              Otherwise, checksum tests done in those classes will
              fail.
All classes using DataCompressors via
          the DataCompressorFactory (the
          MLImageFormat class, for example) will
          automatically detect your compression algorithm and offer it as an
          option.
The following example shows a complete header file implementation of a data compressor that packs 16 bit words by removing bit 12 to 15. It is a potentially lossy compressor, because highest bits are removed. It, however, could be useful for CT data, for example, which do not use those bits, or for cases where other compressors do not reach high compression ratios, because data is too noisy:
#ifndef __mlCTPackDataCompressor_H
#define __mlCTPackDataCompressor_H
#include "MLCTPackDataCompressorSystem.h"
#include "mlDataCompressor.h"
ML_UTILS_START_NAMESPACE
//! CTPackDataCompressor example for the ML.
class MLCTPackDATA_COMPRESSOR_EXPORT CTPackDataCompressor : public DataCompressor
{
public:
  //! Constructor (no destructor needed).
  CTPackDataCompressor() : DataCompressor() { }
  //! Returns name of compression scheme, used e.g., "RLE", or "LZW".
  virtual std::string     getTypeName()     const { return "CTPack";    }
  //! Returns the version string, e.g., "1.1.4" or "1.1"; compatibility
  //! check needs to be done in isSupportedVersion().
  virtual std::string     getVersion()      const { return "1.0";       }
  //! Returns true if the passed version ver is supported by the
  //! implemented compressor class and false otherwise.
  virtual bool            isSupportedVersion(const std::string &ver) const
  { return ver == getVersion(); }
  //! Return the name of the vendor providing the compressor code
  //! or algorithm, something like "MeVis", the author or the
  //! company selling the algorithm.
  virtual std::string     getVendor()       const { return "ML Guide";  }
  //! Returns the suffix describing the compression scheme, for
  //! example "rle" or "lzw".
  virtual std::string     getSuffix()       const { return "cpk";       }
  //! Returns true if compression is lossy, false if not, base class
  //! default is false.
  //! We have to enable lossy, because we throw away highest nibble
  //! which could cause check sum errors in file formats if not denoted.
  virtual bool            isLossy()         const { return true;        }
  //! Number of hints used by the derived compressor class (defaults
  //! to 0 in base class).
  virtual MLuint8         numUsedHints()    const { return 0;           }  //! Compresses a chunk of memory to be decompressed later with decompress().
  //! \param  srcMem  is the pointer of data to be compressed.
  //! \param  srcSize is the size of the data pointed to by srcMem in bytes.
  //! \param  dstMem  the pointer to the compressed data.
  //!                 The compressor will allocate the required memory and
  //!                 overwrites the dstMem pointer which then must be freed
  //!                 by the caller with MLFree() or Memory::freeMemory().
  //! \param  dstNum  returns size of compressed data chunk in bytes or 0 on error.
  //! \return         ML_RESULT_OK on successful compression or an error code
  //!                 describing the error.
  virtual MLErrorCode compress(const  void  *srcMem,
                               size_t        srcSize,
                               void        *&dstMem,
                               MLint        &dstNum) const
  {
    MLErrorCode errCode = ML_NO_MEMORY;
    dstMem = NULL;
    dstNum = 0;
    if (srcMem && (srcSize>0)){
      // Determine size of destination buffer, it requires 4 byte at begin to
      // store original data size and in worst case 1 bit more per CTPack more
      // if no CTPack can be compressed. Add four bytes for rounding securely.
      const size_t packedSize =
        static_cast<size_t>(sizeof(MLint64) + (srcSize * 3) / 4 + 4);
      dstMem = Memory::allocateMemory(packedSize, ML_RETURN_NULL);
      if (dstMem != NULL) {
        // Get byte pointer to output memory and clear data.
        unsigned char *targetData = static_cast<unsigned char *>(dstMem);
        memset(targetData, 0, packedSize);
        // Store size of source data in little endian format at buffer start.
        (static_cast<MLint64*>(dstMem))[0] = static_cast<MLint64>(srcSize);
        if (!MLIsLittleEndian()) {
          MLSwapBytes(targetData, sizeof(MLint64), sizeof(MLint64));
        }
        // Traverse all nibbles/half bytes.
        srcSize *= 2;
        size_t oNibble = 16; // Set start to first nibble after stored startDstSize.
        for (size_t n = 0; n < srcSize; ++n) {
          // Get nibble from source data.
          const unsigned char nib =
            (static_cast<const unsigned char*>(srcMem)[n>>1] >>
             ((n & 1)*4)) & 0xf;
          // Add nibble to output data.
          if ((n & 3) != 3) {
            targetData[oNibble>>1] |= (oNibble & 1 ? (nib << 4) : nib);
            ++oNibble;
          }
        }
        // Calculate number of really used bytes in destination buffer and add 1
        // byte as buffer zone for check of buffer overrun during decompression.
        dstNum = (oNibble >> 1) + (oNibble & 1 ? 1 : 0);
        // Return success.
        errCode = ML_RESULT_OK;
      }
    }
    return errCode;
  }  //! Decompresses a chunk of memory created with compress().
  //! \param  srcMem  is the pointer to the compressed data to be decompressed.
  //! \param  srcSize is the size of the data pointed to by srcMem in bytes.
  //! \param  dstMem  returns the pointer to the decompressed data; it is
  //!                 overwritten with the pointer to the allocated and
  //!                 uncompressed data which must be freed by the caller
  //!                 with MLFree() or Memory::freeMemory().
  //! \param  resSize returns the size of the decompressed data
  //!                 memory in bytes or -1 on error.
  //! \return         ML_RESULT_OK on successful decompression or
  //!                 an error code describing the error.
  virtual MLErrorCode decompress(const  void  *srcMem,
                                 size_t        srcSize,
                                 void        *&dstMem,
                                 MLint64      &resSize) const
  {
    // Pointer to working and result buffers.
    dstMem              = NULL;
    resSize             = -1;
    MLErrorCode errCode = ML_BAD_POINTER_OR_0;
    // Check uncompressed size for at least the four size bytes at start.
    if (srcSize <= sizeof(MLint64)) {
      errCode = ML_FILE_OR_DATA_STRUCTURE_CORRUPTED;
    } else {
      // Get size of decompression data from start of compressed data.
      MLint64 uncompressedSize = (static_cast<const MLint64*>(srcMem))[0];
      if (!MLIsLittleEndian()) {
        // Swap data to local endian format, the data is always stored
        // in little endian.
        MLSwapBytes(reinterpret_cast<unsigned char*>(&uncompressedSize),
                    sizeof(MLint64),
                    sizeof(MLint64));
      }
      if (uncompressedSize < 0) {
        // Should not happen, data is probably corrupted.
        errCode = ML_FILE_OR_DATA_STRUCTURE_CORRUPTED;
      } else {
       // Size seems to be valid, allocate return buffer.
        dstMem = Memory::allocateMemory(static_cast<size_t>(uncompressedSize),
                                        ML_RETURN_NULL);
        if (!dstMem) {
          errCode = ML_NO_MEMORY;
        } else {
          // Unpack all packed nibbles from source data into cleaned result buffer.
          memset(dstMem, 0, uncompressedSize);
          MLint64 oNibble = 0;
          for (size_t n = 16; n < srcSize*2; ++n) {
            // Get nibble from packed data.
            const unsigned char nib =
              (static_cast<const unsigned char*>(srcMem)[n>>1] >>
               ((n & 1)*4)) & 0xf;
            // After unpacking 3 nibbles add a fourth empty one.
            if ((oNibble & 3) == 3) { ++oNibble; }
            // Add nibble to output, shifted by 4 bits if necessary.
            static_cast<unsigned char*>(dstMem)[oNibble >> 1] |=
             (oNibble & 1) ? (nib << 4) : nib;
            ++oNibble;
          }
          // Return success and number of uncompressed bytes.
          errCode = ML_RESULT_OK;
          resSize = uncompressedSize;
        } // else ML_NO_MEMORY;
      } // else if ((uncompressedSize < 0))
    } // else if (srcSize <= sizeof(MLint64) + 1)
    // Clean up on error.
    if (ML_RESULT_OK != errCode) {
      MLFree(dstMem);
      dstMem  = NULL;
      resSize = -1;
    }
    return errCode;
  }
private:
  //! Implements interface for the runtime type system of the ML.
  ML_CLASS_HEADER(CTPackDataCompressor)
};
ML_UTILS_END_NAMESPACE
#endif // __mlCTPackDataCompressor_HDo not forget to implement the registration code in the ML
          runtime type system with the typical
          ML_CLASS_SOURCE macro in the .cpp file:
ML_CLASS_SOURCE(CTPackDataCompressor, DataCompressor);
Also, the registration of the classes in the runtime type system and in the factory for ML data compressors need to be called before using them for the first time (normally in the initialization code while loading the module code):
CTPackDataCompressor ::initClass(); DataCompressorFactory::registerCompressor(CTPackDataCompressor::getClassTypeId());
          © 2025 MeVis Medical Solutions AG