Documentation/4.8/Modules/Markups

From SlicerWiki
Jump to: navigation, search
Home < Documentation < 4.8 < Modules < Markups



Introduction and Acknowledgements

This work is part of the National Alliance for Medical Image Computing (NA-MIC), funded by the National Institutes of Health through the NIH Roadmap for Medical Research, Grant U54 EB005149. Information on NA-MIC can be obtained from the NA-MIC website.
Author: Nicole Aucoin, SPL, BWH
Contact: Nicole Aucoin,

Surgical Planning Laboratory (SPL)  

Module Description

This module is used to manage markups in Slicer.

It is based on the functionality in the Slicer 3.6 Fiducials module, with elements from the Slicer 4.2 Annotations module.

Currently, only fiducials are supported.

Create and edit markups, supplementary information associated with a scene. Currently supported markups are lists of fiducial points. Fiducials can be placed using the mouse mode tool bar. Once fiducial place mode has been entered, a new fiducial can be placed under the current mouse position by pressing the p key. Right mouse button click will exit persistent place mode.


Development history can be found in the references.

Use Cases

This module allows you to add new markups, edit markups in a list, delete markups and modify display properties of markups.


How To Use

Note: Markups can be passed to command line modules (CLIs) using the
--point
or
--pointfile
argument.

Note: The Mouse mode tool bar can be used to place new markups by positioning the mouse and left clicking in the viewers. Once you are in Place mode and placing Markups fiducials, you can use the 'p' key to place a new fiducial while the Markups GUI is open. You can also use a right button click to stop placing fiducials when in persistent mode.

Note: You can place fiducials and use the GUI to jump slices or the 3D view to those locations. If you select fiducials in the table, you can right click to get the summed linear distance between their locations.

Note: The Markups module can convert Annotation fiducials into Markups fiducials, and will offer the user the option of doing it automatically when the Markups GUI is entered. There is also a manual button under the Advanced tab.


Panels and their use

Parameters:

  • Markups List: Top level Markups list with some often used options.
    • List: Select a Markups fiducial node from the scene to populate the GUI and allow modifications. One option is to create a new node with the display properties of the current list.
    • Visibility: Toggle the list visibility, which will override the individual markup visibility settings. If the eye icon is open, the list is visible, and pressing it will make it invisible. If the eye icon is closed, the list is invisible and pressing the button will make it visible.
    • Locked: Toggle the list lock state (if it can be moved by mouse interactions in the viewers), which will override the individual markup lock settings. If the lock icon is open, the list is unlocked, and pressing it will lock it. If the lock icon is closed, the list is locked and pressing the button will unlock it. When the list is locked, the table is disabled so no changes can be made to fiducial positions there.
    • Scale: Set both the glyph and text size to the same value for all markups in the list.
    • Click to Jump Slices: If checked, click in name column to jump slices to that point. The radio buttons control if the slice is centered on the markup or not after the jump. Right click in the table allows jumping 2D slices to a highlighted fiducial (uses the center/offset radio button settings). Once checked, arrow keys moving the highlighted row will also jump slice viewers to that markup position.
  • Buttons: These buttons apply changes to markups in the selected list.
    • Toggle visibility flag: Toggle visibility flag on all markups in list. Use the drop down menu to set all to visible or invisible.
    • Toggle selected flag: Toggle selected flag on all markups in list. Use the drop down menu to set all to selected or deselected. Only selected markups will be passed to command line modules.
    • Toggle lock flag: Toggle lock flag on all markups in list, use drop down menu to set all to locked or unlocked.
    • Delete the highlighted markups from the active list: After highlighting rows in the table to select markups, press this button to delete them from the list.
    • Remove all markups from the active list: Pressing this button will delete all of the markups in the active list, leaving it with a list length of 0.
  • Checkboxes: These check boxes change how the markups in the selected list are displayed.
    • Transformed: Check to show the transformed coordinates in the table. This will apply any transform nodes to the points in the list and show that result. Keep unchecked to show the raw RAS values that are stored in MRML. If you harden the transform the transformed coordinates will be the same as the non transformed coordinates.
    • Hide RAS: Check to hide the coordinate columns in the table and uncheck to show them. Right click in rows to see coordinates.
  • Markups Table: Right click on rows in the table to bring up a context menu to show the full precision coordinates, distance between multiple highlighted fiducials, delete the highlighted markup, jump slice viewers to that location, refocus 3D viewers to that location, or if there are other lists, to copy or move the markup to another list.
    • Selected: A check box is shown in this column, it's check state depends on if the markup is selected or not. Click to toggle the selected state. Only selected markups will be passed to command line modules.
    • Locked: An open or closed padlock is shown in this column, depending on if the markup is unlocked or locked. Click it to toggle the locked state.
    • Visibility: An open or closed eye icon is shown in this column, depending on if the markup is visible or not. Click it to toggle the visibility state.
    • Name: A short name for this markup, displayed in the viewers as text next to the glyphs.
    • Description: A longer description for this markup, not displayed in the viewers.
    • X, Y, Z: The RAS coordinates of this markup, 3 places of precision are shown.
  • Advanced: Buttons:
    • Move Up: Move a highlighted markup up one spot in the list.
    • Move Down: Move a highlighted markup down one spot in the list.
    • Add Markup: Add a new markup to the selected list, placing it at the origin
  • Advanced: Naming:
    • Name Format: Format for creating names of new markups, using sprintf format style. %N is replaced by the list name, %d by an integer.
    • Apply: Rename all markups in this list according to the current name format, trying to preserve numbers. A quick way to re-number all the fiducials according to their index is to use a name format with no number in it, rename, then add the number format specifier %d to the format and rename one more time.
    • Reset: Rest the name format field to the default value, %N-%d.
  • Advanced: Conversion:
    • Convert Annotation Fiducials to Markups Fiducial Lists: Uses annotation fiduical hierarchies to make markup lists. Removes the annotations once they've been moved.
  • Advanced: Display Properties:
    • Glyph Type: Select the symbol that will be used to mark each location. Default is the Sphere3D.
    • Selected Color: Select the color that will be used to display the glyph and text when the markup is marked as selected.
    • Unselected Color: Select the color that will be used to display the glyph and text when the markup is not marked as selected.
    • Glyph Scale: Pick the relative size of the glyph used to mark the points.
    • Text Scale: Pick the relative size of the text shown beside each glyph. Select 0 to turn off text.
    • Opacity: Pick the opacity used for the glyph and text, select 0 for invisible, 1 for fully visible.
    • Reset to Defaults: Reset the display properties of this markups node to the system defaults.
    • Save to Defaults: Save the display properties of this markups node to be the new system defaults.
  • Advanced: Display Properties: Fiducuial Projection: A widget that controls the projection of the fiducials in the 2D viewers onto slices around the one on which the fiducial has been placed.
    • 2D Projection: Toggle the eye icon open or closed to enable or disable visualization of projectied fiducial on 2D viewers.
    • Use Fiducial Color: If checked, color the projections the same color as the fiducials.
    • Projection Color: If not using fiducial color for the projection, use this color.
    • Outlined Behind Slice Plane: Fiducial projection is displayed filled (opacity = Projection Opacity) when on top of slice plane, outlined when behind, and with full opacity when in the plane. Outline isn't used for some glyphs (Dash2D, Cross2D, Starburst).
    • Projection Opacity: A value between 0 (invisible) and 1 (fully visible) for displaying the fiducial projection.


List of parameters generated transforming this XML file using this XSL file. To update the URL of the XML file, edit this page.


Similar Modules

References

Information for Developers

The Simple Markups Widget can be integrated into slicelets. It is lightweight and can access the Markups features. An example of this use is in Gel Dosimetry. To use this, access it at GitHub.

Python

Open the Markups Module

You can set the Markups module gui to be the current module gui using this command:

 slicer.util.mainWindow().moduleSelector().selectModule('Markups')

Load From File

Markups fiducials can be loaded from file:

 slicer.util.loadMarkupsFiducialList('/path/to/list/F.fcsv')

Adding Fiducials Programatically

Markups fiducials can be added to the currently active list from the python console by using the following module logic command:

 slicer.modules.markups.logic().AddFiducial()

The command with no arguments will place a new fiducial at the origin. You can also pass it an initial location:

 slicer.modules.markups.logic().AddFiducial(1.0, -2.0, 3.3)

Adding Fiducials via Mouse Clicks

You can also set the mouse mode into Markups fiducial placement by calling:

 placeModePersistence = 1
 slicer.modules.markups.logic().StartPlaceMode(placeModePersistence)

A lower level way to do this is via the selection and interaction nodes:

 selectionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSelectionNodeSingleton")
 selectionNode.SetReferenceActivePlaceNodeClassName("vtkMRMLMarkupsFiducialNode")
 interactionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLInteractionNodeSingleton")
 placeModePersistence = 1
 interactionNode.SetPlaceModePersistence(placeModePersistence)
 # mode 1 is Place, can also be accessed via slicer.vtkMRMLInteractionNode().Place
 interactionNode.SetCurrentInteractionMode(1)

To switch back to view transform once you're done placing fiducials:

 interactionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLInteractionNodeSingleton")
 interactionNode.SwitchToViewTransformMode()
 # also turn off place mode persistence if required
 interactionNode.SetPlaceModePersistence(0)

Access to Fiducial Properties

Each vtkMRMLMarkupsFiducialNode has a vector of points in it which can be accessed from python:

 fidNode = getNode("vtkMRMLMarkupsFiducialNode1")
 n = fidNode.AddFiducial(4.0, 5.5, -6.0)
 fidNode.SetNthFiducialLabel(n, "new label")
 # each markup is given a unique id which can be accessed from the superclass level
 id1 = fidNode.GetNthMarkupID(n)
 # manually set the position
 fidNode.SetNthFiducialPosition(n, 6.0, 7.0, 8.0)
 # set the label
 fidNode.SetNthFiducialLabel(n, "New label")
 # set the selected flag, only selected = 1 fiducials will be passed to CLIs
 fidNode.SetNthFiducialSelected(n, 1)
 # set the visibility flag
 fidNode.SetNthFiducialVisibility(n, 0)  

You can loop over the fiducials in a list and get the coordinates:

 fidList = slicer.util.getNode('F')
 numFids = fidList.GetNumberOfFiducials()
 for i in range(numFids):
   ras = [0,0,0]
   fidList.GetNthFiducialPosition(i,ras)
   # the world position is the RAS position with any transform matrices applied
   world = [0,0,0,0]
   fidList.GetNthFiducialWorldCoordinates(0,world)
   print i,": RAS =",ras,", world =",world

You can also look at the sample code in the Endoscopy module to see how python is used to access fiducials from a scripted module.

VTK Widget access

The Markups 3D fiducial displayable manager can be accessed from python allowing debugging of the vtkSeedWidget:

 fidNode = slicer.mrmlScene.GetNodeByID("vtkMRMLMarkupsFiducialNode1")
 lm = slicer.app.layoutManager()
 td = lm.threeDWidget(0)
 ms = vtk.vtkCollection()
 td.getDisplayableManagers(ms)
 for i in range(ms.GetNumberOfItems()): 
   m = ms.GetItemAsObject(i)
   if m.GetClassName() == "vtkMRMLMarkupsFiducialDisplayableManager3D":
     print i, m.GetClassName()
     h = m.GetHelper()
     seedWidget = h.GetWidget(fidNode)
     seedRepresentation = seedWidget.GetSeedRepresentation()
     handleRep2 = seedRepresentation.GetHandleRepresentation(2)
     print handleRep2.GetDisplayPosition()
     print handleRep2.GetWorldPosition()


The Markups 2D fiducial displayable manager can be accessed from python as well to debug the seed widget in 2D. For the Red slice viewer:

 fidNode = slicer.mrmlScene.GetNodeByID("vtkMRMLMarkupsFiducialNode1")
 lm = slicer.app.layoutManager()
 redWidget = lm.sliceWidget("Red")
 redView = redWidget.sliceView()
 ms = vtk.vtkCollection()
 redView.getDisplayableManagers(ms)
 for i in range(ms.GetNumberOfItems()):
  m = ms.GetItemAsObject(i)
  if m.GetClassName() == "vtkMRMLMarkupsFiducialDisplayableManager2D":
    print i, m.GetClassName()
    h = m.GetHelper()
    seedWidget = h.GetWidget(fidNode)
    seedRepresentation = seedWidget.GetSeedRepresentation()
    handleRep = seedRepresentation.GetHandleRepresentation(0)
    print handleRep.GetDisplayPosition()

C++

Selection and Interaction

For the selection and interaction nodes, make sure that you access the singleton nodes already in the scene (rather than making your own) via (caveat: this call works on displayable managers, you may have to go a different route to get at the application logic):

 vtkMRMLApplicationLogic *mrmlAppLogic = this->GetMRMLApplicationLogic();
 vtkMRMLInteractionNode *inode = mrmlAppLogic->GetInteractionNode();
 vtkMRMLSelectionNode *snode = mrmlAppLogic->GetSelectionNode();

If you can't get at the mrml application logic, you can get the nodes from the scene:

 vtkMRMLInteractionNode *interactionNode = vtkMRMLInteractionNode::SafeDownCast(this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton"));

You can then call methods on the nodes or add your own event observers as in

 vtkSlicerMarkupsModuleLogic::ObserveMRMLScene

You can see vtkSlicerMarkupsModuleLogic::ProcessMRMLNodesEvents to see how to respond to interaction node changes.

Slicer4/Base/QTGUI/qSlicerMouseModeToolBar.cxx has a lot of the code you'll need as well, with a slightly different way of getting at the mrml app logic to access the nodes.

The calls you need to make to switch into placing fiducials with the mouse are:

 selectionNode->SetReferenceActivePlaceNodeClassName("vtkMRMLMarkupsFiducialNode");
 interactionNode->SetCurrentInteractionMode(vtkMRMLInteractionNode::Place);

If you don't set PlaceModePersistence on the interaction node to 1, the mouse mode/current interaction mode will automatically go back to view transform after one fiducial has been placed, and you just need to reset the current interaction mode for future placing (the active place node class name and ID are persistent).

Programmatic Access to Fiducials

This section explains how to access fiducial nodes added into the scene by the user.

In your module's Logic class, overwrite SetMRMLSceneInternal to observe the NodeAddedEvent of the scene:

void vtkSlicerMYMODULEModuleLogic::SetMRMLSceneInternal(vtkMRMLScene * newScene)
  {
  vtkNew<vtkIntArray> events;
  events->InsertNextValue(vtkMRMLScene::NodeAddedEvent);
  // Optionally you can add more events here, 
  // such as vtkMRMLScene::NodeRemovedEvent
  this->SetAndObserveMRMLSceneEventsInternal(newScene, events.GetPointer());
  }

Via the set and observe mrml scene macro, anytime a node is added into the scene, it will trigger the base Logic class method vtkMRMLAbstractLogic::ProcessMRMLNodesEvents which calls the virtual method vtkMRMLAbstractLogic::OnMRMLSceneNodeAdded(vtkMRMLNode* node) Reimplement that method in your logic class:

void vtkSlicerMYMODULEModuleLogic::OnMRMLSceneNodeAdded(vtkMRMLNode* addedNode)
  {
  vtkMRMLMarkupsFiducialNode* fidNode =
    vtkMRMLMarkupsFiducialNode::SafeDownCast(addedNode);
  if (fidNode)
    {
    // here you write what you need to do when a 
    // fiducial node is added into the scene
    }
  }

File Format

The Markups Fiducial storage node uses a comma separated value file to store the fiducials on disk. The format is:

A leading comment line giving the Slicer version number:

 # Markups fiducial file version = 4.5

A comment line giving the coordinate system, RAS = 0, LPS = 1, IJK = 2 (IJK is currently not supported, RAS is printed instead)

 # CoordinateSystem = 0

A comment line explaining the fields in the csv

 # columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID

Then comes the fiducials, one per line, for example:

 vtkMRMLMarkupsFiducialNode_0,1.29,-40.18,60.15,0,0,0,1,1,1,0,F-1,,
  • id = a string giving a unique id for this fiducial, usually based on the class name
  • x,y,z = the floating point coordinate of the fiducial point
  • ow,ox,oy,oz = the orientation quaternion of this fiducial, angle and axis, default 0,0,0,1 (or 0,0,0,0,0,0,1.0)
  • vis = the visibility flag for this fiducial, 0 or 1, default 1
  • sel = the selected flag for this fiducial, 0 or 1, default 1
  • lock = the locked flag for this fiducial, 0 or 1, default 0
  • label = the name for this fiducial, displayed beside the glyph, with quotes around it if there is a comma in the field
  • desc = a string description for this fiducial, optional
  • associatedNodeID = an id of a node in the scene with which the fiducial is associated, for example the volume or model on which the fiducial was placed, optional

The file can be parsed using stringstream and getline:

 std::fstream fstr;
 fstr.open(fileName.c_str(), std::fstream::in);
 char line[1024];
 while (fstr.good())
    {
    fstr.getline(line, 1024);
    std::stringstream ss(line);
    std::string component;
    getline(ss, component, ',');
    [...]
    }