Difference between revisions of "Documentation/Nightly/Developers/MRML"

From Slicer Wiki
Jump to: navigation, search
Line 33: Line 33:
 
= Relationship between nodes =
 
= Relationship between nodes =
  
Data node can optionally implement interfaces like [{{doxygen-class-url|vtkMRMLDisplayableNode}} Displayable], [{{doxygen-class-url|vtkMRMLStorableNode}} Storable] and [{{doxygen-class-url|vtkMRMLTransformableNode}} Transformable]. Each one of these interfaces have its own requirements. For example, a transformable node will expected to be associated with a transform node. Such association are done by creating MRML Reference.
+
Data node can optionally implement interfaces like [{{doxygen-class-url|vtkMRMLDisplayableNode}} Displayable], [{{doxygen-class-url|vtkMRMLStorableNode}} Storable] and [{{doxygen-class-url|vtkMRMLTransformableNode}} Transformable].  
  
{|
+
Each one of these interfaces have its own requirements. For example, a transformable node will expected to be associated with a transform node. Such association are done by creating MRML Reference.
|[[File:ClassvtkMRMLNode_inherit_graph.png|thumb|400px]]
 
|}
 
  
 
= MRML Hierarchy Node =
 
= MRML Hierarchy Node =

Revision as of 21:48, 3 April 2015

Home < Documentation < Nightly < Developers < MRML


For the latest Slicer documentation, visit the read-the-docs.


Slicer MRML Overview

  • MRML Library provides API for managing medical image data types (Volumes, Models, Transforms, Fiducials, Cameras, etc) and their visualization.
  • Each data type is represented by a special MRML node.
  • MRML Scene is a collection of MRML nodes.
  • Slicer MRML data model is implemented independent of the visualization and algorithmic components of the system.
  • Other Slicer components (Logic and Qt Widget) observe changes in MRML scene and individual nodes and process change MRML events.

For more details on MRML architecture see Architecture Slides.

MRML Scene

  • MRML Scene manages MRML nodes : add, delete, find, find by type, etc.
  • MRML Scene provides persistence of MRML nodes (reading/writing to/from XML file).
  • MRML Scene provides Undo/Redo mechanism that restores a previous state of the scene and individual nodes.

MRML Nodes

  • MRML nodes are designed to store the state of the Slicer application, both raw data and visualization, and storage parameters. A set of core MRML nodes that store the state of core Slicer modules is listed here.
  • All MRML nodes have to implement certain standard API: ReadAttributes, WriteAttributes, Copy, etc.
  • The same data can be visualized in various ways and can be stored in different formats. Therefore, information is stored separately in three node types:
    • Data node: store the raw data (such as vtkMRMLScalarVolumeNode stores the voxel of a volume, spacing, position, orientation).
    • Display nodes: describes how the data should be visualized (there can be multiple display nodes for the same raw data, e.g., one for volume rendering and one for displaying as an image slice)
    • Storage node: describes how the data should be stored persistently on disk (file format, file name)
  • When a data node is created, it is also necessary to create the corresponding display and storage nodes to allow proper visualization and saving to file. This is where MRMLLogic can be helpful in providing function allowing to create a node and is associated display and data node if needed. Note also that in some cases, Slicer detects if the display and storage node is missing and tries to create a default nodes, but the developers should not rely on this error-recovery mechanism.

Relationship between nodes

Data node can optionally implement interfaces like Displayable, Storable and Transformable.

Each one of these interfaces have its own requirements. For example, a transformable node will expected to be associated with a transform node. Such association are done by creating MRML Reference.

MRML Hierarchy Node

This section is an attempt to describe the vtkMRMLHierarchyNode.

HierarchyNodesDiagram.jpg

H = hierarchy node, D = display node, M = model node

MRML node attributes

MRML nodes can store custom attributes as (attribute name; attribute value) pairs.

To avoid name clashes custom modules that adds attributes to nodes should prefix the attribute name with the module's name and the '.' character. Example: the DoseVolumeHistogram module can use attribute names such as DoseVolumeHistogram.StructureSetName, DoseVolumeHistogram.Unit, DoseVolumeHistogram.LineStyle.

References to MRML Nodes

MRML nodes can reference and observes other MRML nodes. The node reference API provides a simple API to manage references. The framework will automatically take care of (1) read/write/copy of node references, (2) updating references on scene import and (3) adding and deleting nodes.

For more details, see here.

MRML Events and Observers

  • Changes in MRML scene and individual nodes propagate to other observing nodes, GUI and Logic objects via vtk events and command-observer mechanism.
  • Use vtk AddObserver() and InvokeEvent() methods. vtkSetMacro generates ModifiedEvent.
  • The command-observer mechanism for MRML is implemented using helper vtkObserverManager, class, MRML Observer macros, and ProcessMRMLEvents method.
  • Observers should store a registered pointer to a MRML node to prevent callbacks on a deleted object.
Slicer3 MRML Observ.jpg
  • MRML observer macros are defined in Libs/MRML/vtkMRMLNode.h
  • vtkSetMRMLObjectMacro - registers MRML node with another vtk object (another MRML node, Logic or GUI). No observers added.
  • vtkSetAndObserveMRMLObjectMacro - registers MRML node and adds an observer for vtkCommand::ModifyEvent.
  • vtkSetAndObserveMRMLObjectEventsMacro - registers MRML node and adds an observer for a specified set of events.
  • SetAndObserveMRMLScene[Events]() method is used in GUI and Logic to observe Modify, NewScene, NodeAdded, etc. events.
  • ProcessMRMLEvents method should be implemented in MRML nodes, Logic, and GUI classes in order to process events from the observed nodes.

Creating Custom MRML Node Classes

  • Custom MRML nodes provide persistent storage for the module parameters.
  • Custom MRML nodes should be registered with the MRML scene using RegisterNodeClass() so they can be saved and restored from a scene file.
  • Classes should implement the following methods:
  • CreateNodeInstance() – similar to VTK New() method only not static.
  • GetNodeTagName() – return a unique XML tag for this node.
  • ReadXMLAttributes() – reads node attributes from XML file as name-value pairs.
  • WriteXML() – writes node attributes to output stream (as in interpolate="1" ).
  • Copy() – copies node attributes.
  • If the node has references to other nodes the following additional methods should be implemented:
–UpdateReferenceID() - updates the stored reference to another node. 
–UpdateScene()- updates other nodes in the scene depending on this node or updates this node if it depends on other nodes when the scene is read in. 
  This method is called automatically by XML parser after all nodes are created. 
  • An example of a custom MRML node implementation: vtkMRMLGradientAnisotropicDiffusionFilterNode in Modules/GradientAnisotropicDiffusionFilter directory.
  • To add node to the MRML scene:
–In the code: use standard vtk New() and add node to the scene using vtkMRMLScene::AddNode(vtkMRMLNode *)
–By user request: use vtkSlicerNodeSelectorWidget that creates a new node from the module’s UI.


Undo/Redo Mechanism

  • Undo/Redo is based on saving and restoring the state of MRML nodes in the Scene.
  • MRML scene can save snapshot of all nodes into a special Undo and Redo stacks.
  • The Undo and Redo stacks store copies of nodes that have changed from the previous snapshot. The node that have not changed are stored by a reference (pointer).
  • When an Undo is called on the scene, the current state of Undo stack is copied into the current scene and also into Redo stack.
  • All Undoable operations must store their data as MRML nodes
Slicer3 MRML Undo.jpg
  • Developer controls at what point the snapshot is saved by calling SaveStateForUndo method on the MRML scene.

–SaveStateForUndo() - saves the state of all nodes in the scene
–SetActiveScene(vtkMRMLScene *) - saves the state of the specified node.
–SetActiveScene(vtkCollection*) - saves the state of the specified collection of nodes.

  • SaveStateForUndo() should be called in GUI/Logic classes before changing the state of MRML nodes. This is usually done in the ProcessGUIEvents method that processes events from the user interactions with GUI widgets.
  • SaveStateForUndo() should not be called while processing transient events such as continuous events sent by KW UI while dragging a slider (for example vtkKWScale::ScaleValueStartChangingEvent).

The following methods on the MRML scene are used to manage Undo/Redo stacks:

  • vtkMRMLScene::Undo() – restore the previously saved state of the MRML scene.
  • vtkMRMLScene::Redo() – restore the previously undone state of the MRML scene.
  • vtkMRMLScene::SetUndoOff() – ignore following SaveStateForUndo calls (usefull when making multiple changes to the scene/nodes that does not need to be undone).
  • vtkMRMLScene::SetUndoOn() – enable following SaveStateForUndo calls.
  • vtkMRMLScene::ClearUndoStack() – clears the undo history.
  • vtkMRMLScene::ClearRedoStack() – clears the redo history.

Other Useful References

MRML API Documentation

The detailed documentation of MRML API can be found in Slicer Nightly Doxygen pages

Slice view pipeline

SliceView.png

VTK/MRML pipeline for the 2D slice views: File:SliceView.pptx.

Another view of the ScalarVolumeDisplayNode pipeline:

Screen Shot 2014-02-11 at 4.00.31 PM.png

Notes: the MapToWindowLevelColors has no lookup table set, so it maps the scalar volume data to 0,255 with no "color" operation. This is controlled by the Window/Level settings of the volume display node. The MapToColors applies the current lookup table to go from 0-255 to full RGBA.

History

See Data Model notes in AHM 2006 Programming week project.

Path-based MRML proposal

Mike's proposal for a path-based MRML3 representation, based on extending the Coordinate Space Manager ideas to the entire MRML3 tree

Slicer Daemon

The goal of the Slicer Daemon project is to allow remote editing of the MRML data model by external programs over a socket.

EventBroker Discussion

The Event Broker is a proposal to improve the way events are managed inside slicer.

Slicer 2.6 MRML

Data Represented in MRML in Slicer 2.6

  • Volumes
    • IJK->RAS (VTK->RAS)
    • Scalar Types
    • Multicomponent (RGB, Displacement Vector)
    • Tensor Volumes
    • Label Maps
    • Reference to Lookup Table
  • Models
    • vtkPolyData
      • Named Field Data (scalars, vectors, labels) at points and cells (FreeSurferReaders)
      • Polylines with tensor point data (DTMRI Module)
    • Color, Clipping State, Visibility, Scalar Visibility, LookupTable
  • Transforms
    • Matrix4x4
  • Lookup Tables
    • vtkLookupTable info
  • Fiducials
    • Position, Quaternion
    • Name, Selection State, Type (endoscopic, normal)
    • Glyph Size, Text Size
  • Fiducial Lists
    • Name, Slze, Color, Selection State
  • Colors
    • Name, Label#, Diffuse/Ambient/Specular
  • Model Groups
  • Application State (not to be carried to Slicer3 MRML)
  • Locator (not to be carried to Slicer3 MRML)
  • Module Specific Parameters (not to be carried to Slicer3 MRML)


Operations On MRML Scene

  • Load from File
  • Save to File
  • Traverse Nodes in Tree
  • Insert Node
  • Delete Node
  • Register Tree Observer
  • Update MRML
  • Get Transformations (e.g. IJK to World through transform tree)
  • Data Type Specific Operations
    • Get/Set Node MetaData
    • Get/Set Data (e.g. as vtkImageData)

General References on XML

A wikibook on XML

The section on ID/IDREF implementations, which are similar to what we use in MRML.



Developer FAQ: MRML

How to add a MRML node into the scene ?

  • Generic pattern
vtkNew<vtkMRML???Node> nodeToAdd;
...
mrmlScene->AddNode(nodeToAdd.GetPointer());
  • Add a polydata to the scene
vtkNew<vtkMRMLModelNode> modelNode;
modelNode->SetPolyData(polyData);
mrmlScene->AddNode(modelNode.GetPointer());
  • Load a polyData from file
vtkSlicerModelsLogic* modelsLogic = ...;
//modelsLogic->SetMRMLScene(mrmlScene);
modelsLogic->AddModel(polyDataFileName);

What to do if you get 'No LookupTable was set but number of components in input doesn't match OutputFormat' when loading a MRML scene ?

If you get the following error messages:

ERROR: In /path/to/VTK/Imaging/vtkImageMapToColors.cxx, line 153
vtkImageMapToColors (0x268f190): RequestInformation: No LookupTable was set but number of components in input doesn't match OutputFormat, therefore input can't be passed through!

ERROR: In /path/to/VTK/Imaging/vtkImageExtractComponents.cxx, line 239
vtkImageExtractComponents (0x26947e0): Execute: Component 1 is not in input.

ERROR: In /path/to/VTK/Imaging/vtkImageExtractComponents.cxx, line 239
vtkImageExtractComponents (0x26947e0): Execute: Component 1 is not in input.

[...]

Make sure the colorNodeRef attribute is set on each VolumeDisplay node.

How to change the volumes in the 2D views ?

appLogic = slicer.app.applicationLogic()
selectionNode = appLogic.GetSelectionNode()
selectionNode.SetReferenceActiveVolumeID(bg)
selectionNode.SetReferenceSecondaryVolumeID(fg)
appLogic.PropagateVolumeSelection()

Source: https://github.com/fedorov/ChangeTrackerPy/blob/master/Wizard/Helper.py#L82

How to know the min/max offset of a slice view ?

vtkMRMLSliceNode* redSliceNode = vtkMRMLSliceNode::SafeDownCast( this->GetMRMLScene()->GetNodeByID( "vtkMRMLSliceNodeRed" ));
vtkMRMLSliceLogic* sliceLogic = this->GetMRMLApplicationLogic()->GetSliceLogic( redSliceNode );

double sliceBounds[6] = {0, -1, 0, -1, 0, -1};
sliceLogic->GetLowestVolumeSliceBounds(sliceBounds);
double min = sliceBounds[4];
double max = sliceBounds[5];

Source: https://github.com/Slicer/Slicer/blob/master/Libs/MRML/Widgets/qMRMLSliceControllerWidget.cxx#L1267-L1276