Thank you, this sample image was helpful.
A simple workflow can be:
- Select volume
- The module switches to four-up view and enables interactive slice intersections
- Rotate slice intersections using drag-and-drop to show axial slice in red and coronal slice in green
- Click “Align” button
- The module rotates volume to make the slice planes aligned with anatomical axes. The result is that the volume is oriented correctly in physical space, except there may be flips.
- Click Flip LR, Flip AP, or Flip IS button if needed to fix any inverted axis
- The module “flips” the volume along the chosen direction (actually it rotates by 180 degrees)
- Define clipping ROI (optional, if not specified then the entire volume is kept)
- Click “Finish” button
- The module uses Crop volume module to crop and resample the volume
Even without the automations, the workflow takes about 1.5 minutes:
With the module it should take less than 1 minutes. It could be automated further by asking the user to specify a threshold and generate a segmentation from that, get principal axes, and use that to initialize the slice orientations. The segmentation can be also used for automatic cropping.
These code snippets were used in the video (that would be in the custom scripted module):
def rotateVolumeToSlicePlanes(volumeNode):
sliceViewNames = ["Yellow", "Green", "Red"] # sagittal, coronal, axial
# Rotate slice planes to standard anatomical planes
roiToWorld = vtk.vtkMatrix4x4()
for axisIndex, sliceViewName in enumerate(sliceViewNames):
# Set roiToWorld column to slice normal
sliceToRas = slicer.app.layoutManager().sliceWidget(sliceViewName).mrmlSliceNode().GetSliceToRAS()
for component in range(3):
roiToWorld.SetElement(component, axisIndex, sliceToRas.GetElement(component, 2))
# Invert matrix
worldToRoi = vtk.vtkMatrix4x4()
vtk.vtkMatrix4x4.Invert(roiToWorld, worldToRoi)
# Apply transform to volume
volumeNode.ApplyTransformMatrix(worldToRoi)
slicer.modules.volumes.logic().CenterVolume(volumeNode)
# Reset view axes to default
for sliceViewName in sliceViewNames:
slicer.app.layoutManager().sliceWidget(sliceViewName).mrmlSliceNode().SetOrientationToDefault()
# Reset field of view in slice views
slicer.util.setSliceViewerLayers(fit=True)
def flipVolumeOrientation(volumeNode, axis):
transform = vtk.vtkTransform()
if axis == 0:
transform.RotateX(180)
if axis == 1:
transform.RotateY(180)
if axis == 2:
transform.RotateZ(180)
volumeNode.ApplyTransform(transform)
volumeNode = getNode('809_1-resample_sample')
rotateVolumeToSlicePlanes(volumeNode)
flipVolumeOrientation(volumeNode, 0)
#flipVolumeOrientation(volumeNode, 1)
#flipVolumeOrientation(volumeNode, 2)