I’m new to Slicer and was wondering if it’s possible to annotate two different volumes (in a three-by-three view, for example) at the same time for registration purposes? In other words, is it possible to display two different sets of annotation marks in the same layout that only appear on their respective volumes?
Create two markups fiducial nodes (in the most recent versions of Slicer, these have been renamed “Point List”)
I called mine “F” and “G”.
In the Markups module, select the first node (“F” for me), then expand the “Display” section, and then the “Advanced” section within the “Display” section. The top entry is “View:” and the default is “All”, which means that points in this point list will appear on all slice and all 3D views.
Click the dropdown, and uncheck the bottom row slice views (these are “Red+”, “Green+”, and “Yellow+”). This will mean that points in “F” are not visible in the bottom row views.
Do the same for the other point list (“G”). First select it on the list of nodes at the top, then click the “View:” dropdown, and this time uncheck “Red”, “Green”, and “Yellow”. This will make “G” points invisible in the top row of slice views.
Following these instructions, both sets would be visible in the 3D view when present; if that is not what you want, then you can hide either or both in the 3D view by unchecking “View1” in the “View:” dropdown list.
If you haven’t already, I would recommend taking a look at the “Fiducial Registration Wizard” module from the “SlicerIGT” extension (installable from the Extension Manager). The “Landmark Registration” module included in core Slicer is supposed to do something similar, but I have always found it very difficult to use and not at all intuitive.
Thank you very for this very complete anwser! Actually, I am develloping my own scripted module and I am trying to find a way to display the nodes in only specific view ex: Red/Green/Yellow and Red+/Green+/Yellow+ like you did in the last step. Is there a way do that in a python script (accessing slicer.modules.markups.logic() for example)?
In Slicer, you control how things appear via display nodes. A MRML node (markups, model, scalar image volume, etc) typically has one associated display node (but can have multiple in order to have different display properties in different views). To control which views display the MRML node according to the properties in the display node, you provide a list of view node IDs to the display node.
markupName = 'F' # change to whatever it's called in the Data module
Fnode = slicer.util.getNode(markupName)
dispNode = Fnode.GetDisplayNode()
listOfSlicesToDisplayIn = ['vtkMRMLSliceNodeRed+', 'vtkMRMLSliceNodeGreen+', 'vtkMRMLSliceNodeYellow+']
dispNode.SetViewNodeIDs( listOfSlicesToDisplayIn )
The slice and view node ID names are easy to guess once you have seen a few, but you can also get a list of all 2D slice node IDs and all 3D view node IDs like this and inspect them:
sliceNodeIDs = [node.GetID() for node in slicer.util.getNodesByClass('vtkMRMLSliceNode')] # all 2d slice nodes
threeDViewIDs = [node.GetID() for node in slicer.util.getNodesByClass('vtkMRMLViewNode')] # all 3d view nodes
Perhaps slightly counter-intuitive, if you pass in an empty list to dispNode.SetViewNodeIDs(), the default behavior is that display is in all slices and views rather than in none. If you don’t want something displayed anywhere, you control that by dispNode.SetVisible(False) rather than by providing an empty list of places to show.
Thanks again for your very helpful reply, it worked fine in the slice views.
However, I am also trying to display two different volumes in two different 3D views. I am able to display the rendering of each volume using the following python command (displayNode = slicer.modules.volumerendering.logic().CreateDefaultVolumeRenderingNodes(getNode('VolumeName))) but each volume appears in both 3D windows.
Is there a way to choose in which 3D window a volume rendering will be displayed (for example using slicer.app.layoutManager().threeDWidget(0))?
The method is similar, but a bit more complicated with volume rendering because the display nodes are more complex and there are fewer convenience functions.
volNode = getNode('volumeNameHere')
vrLogic = slicer.modules.volumerendering.logic()
vrDispNode1 = vrLogic.CreateDefaultVolumeRenderingNodes(volNode)
vrDispNode1.SetViewNodeIDs(('vtkMRMLViewNode1')) # show only in first 3D view
vrDispNode2 = vrLogic.CreateVolumeRenderingNode() # to create a second vr display node
slicer.mrmlScene.AddNode(vrDispNode2) # needs to be explicitly added to the scene
volNode.AddAndObserveDisplayNodeID(vrDispNode2.GetID()) # link it to the volume to display
vrDispNode2.SetViewNodeIDs(['vtkMRMLViewNode2']) # show only in second 3D view
vrLogic.UpdateDisplayNodeFromVolumeNode(vrDispNode2, volNode) # this initializes the VolumeProperty
# You can't modify the display properties for the second display node using the GUI; only
# the first display node is shown when interacting with the GUI. So, if you want to do any
# modification, you need to figure out how to do it programmatically
Alternatively, you can clone the volume you want displayed twice, and display the original in one 3D view and the clone in the second 3D view. That way you can still interactively modify the display settings for each. In this approach you just need to get the volume rendering display node for each and use SetViewNodeIDs to control which view each is shown in.